Java Ninja Chronicles By Norris Shelton

Things I learned in the pursuit of code

I was migrating some old Jackson code to Jackson 2 (FasterXML). I ran into where they were telling the Jackson to ignore unknown properties via code.

ObjectMapper mapper = new ObjectMapper();
mapper.getDeserializationConfig().set(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);

The new way to do this in Jackson 2 (FasterXML) is

ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

January 13th, 2016

Posted In: Java, java ninja, Javaninja, json, xml

Leave a Comment

In a previous post, I showed how to use @XmlSeeAlso to inform the JAXB context of inheriting classes. This is great during marshalling. The real pain was on unmarshalling. A requirement we had was that there were two objects that would need to be able to be unmarshalled from the same root element, . This combined with the @XmlSeeAlso caused a problem. When I was unmarshalling an object of A, it consistently returned an object of type B. The only way I found to force it to return a certain object was to specify it via:

        try {
            JAXBContext jaxbContext = JAXBContext.newInstance(...This.class or Super.class...);
            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
            Source source = new StreamSource(new StringReader(myString));

            JAXBElement<PersonWatchModel> jaxbElement = unmarshaller.unmarshal(source, This.class);
            someClass.setSomeProperty(jaxbElement.getValue());
        } catch (JAXBException e) {
            log.error("JAXBException {}", e);
            throw e;
        }

This forced it to a specific type and I could use the .getValue() property to get the java object that I needed.

September 3rd, 2012

Posted In: Java, JAXB, xml

Leave a Comment

JAXB by default would output the value of a getter for property “oldName” as data. Specify @XmlElement if you want to use a different name.

@XmlElement(name ="newName")
public String getOldName() {
     return oldName;
}

Thanks to @XmlElement, it will be outputted as data.

This is especially useful when you have a list of objects. Normally you would have something like:

public List<String> getValues() {
     return values;
}

You would need a way to get the collection of data. This can be accomplished by adding @XmlElementWrapper.

@XmlElementWrapper(name = "valueList")
public List<String> getValues() {
     return values;
}

This would create the following output

<valueList>
     <values>value</values>
     <values>value</values>
     <values>value</values>
     <values>value</values>
</valueList>

This is correct, but I don’t like to have a plural name for a single value container. I could change the name of my property to be value, but that looks weird when I iterate over value in my code. A better solution is to specify a wrapper and an element.

@XmlElementWrapper(name = "valueList")
@XmlElement(name = "value")
public List<String> getValues() {
     return values;
}

This would create the following output

<valueList>
     <value>value</value>
     <value>value</value>
     <value>value</value>
     <value>value</value>
</valueList>

Everybody is happy. My code looks like it should and the xml looks like it should.

August 21st, 2012

Posted In: Java, JAXB, xml

Leave a Comment

It’s pretty hard to troubleshoot generated XML. JAXB offers the ability to output it’s generated XML with a formatted option. After you create the marshaller but before you marshall, tell the marshaller to output formatted xml by:

JAXBContext jaxbContext = JAXBContext.newInstance(Animal.class);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
StringWriter stringWriter = new StringWriter();
marshaller.marshal(watchForm, stringWriter);

August 21st, 2012

Posted In: Java, JAXB, xml

Leave a Comment

It’s not uncommon to use superclasses to contain code that is used in multiple sub-classes. This prevents code duplication and allows the code to be maintained in one place instead of several. The normal way that you marshall JAXB classes will have your duplicating the marshaller. It is possible to use the superclass and only specify it once. If you have class Animal and it is extended by Cat and Dog. How would you marshall them without having to duplicate code?

JAXBContext jaxbContext = JAXBContext.newInstance(Animal.class);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
StringWriter stringWriter = new StringWriter();
marshaller.marshal(watchForm, stringWriter);

You specify the parent class when you get the JAXB context instance. This will get you an error message saying that the particular instance (Dog or Cat) that you are trying to marshall isn’t known to this context. This is worked around by adding @XmlSeeAlso({Cat.class, Dog.class}) to Animal. This tells the JAXB context to also load their definitions.

August 21st, 2012

Posted In: Java, JAXB, xml

Leave a Comment

Normally, I have been able to generate a Soap client and be on my way. This particular time I had to perform some business logic on the client. One of the first things that I encountered was the nuisance of debugging classes without a toString() implementation. It’s no biggie, but it does waste time when you have to open a class to inspect it’s contents. When it has a toString() implementation, your editor will generally use this to display the class. Making one less step that I have to perform.

The business logic I had to implement involved splitting a list of items into two groups, according to the value of one of the properties. In addition, if the object was already in the list, but had a different address, I had to add the current address to the existing object instead of adding it again. Great. Now I need to be able to identify an object in a list. I found that JAXB-2 Basics added implementations of equals() and hashcode() methods.

Just when I thought I was done, I had to add the serializable interface because the web application is marked as distributable. This wasn’t provided by JAXB2-Basics and I had to use an XML binding to add that.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.appriss.jxportal</groupId>
        <artifactId>jxportal</artifactId>
        <version>47.0-SNAPSHOT</version>
    </parent>

    <artifactId>tlo-client</artifactId>
    <name>tlo-client</name>

    <properties>
        <cxf.version>2.5.2</cxf.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxws</artifactId>
            <version>${cxf.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http</artifactId>
            <version>${cxf.version}</version>
        </dependency>
        <!-- Jetty is needed if you're are not using the CXFServlet -->
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http-jetty</artifactId>
            <version>${cxf.version}</version>
        </dependency>

        <!--
            Spring dependencies - needed to force a newer version than CXF used
        -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.jvnet.jaxb2_commons</groupId>
            <artifactId>jaxb2-basics-runtime</artifactId>
            <version>0.6.3</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.cxf</groupId>
                <artifactId>cxf-codegen-plugin</artifactId>
                <version>${cxf.version}</version>
                <executions>
                    <execution>
                        <id>generate-sources</id>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>wsdl2java</goal>
                        </goals>
                        <configuration>
                            <sourceRoot>${basedir}/target/generated-sources/cxf</sourceRoot>
                            <wsdlOptions>
                                <wsdlOption>
                                    <!--note: Started getting errors by having this hit their URL directly-->
                                    <wsdl>https://webservice.tlo.com/TLOWebService.asmx?wsdl</wsdl>
                                    <!--<wsdl>${basedir}/src/main/resources/TLOWebService-20120306.wsdl</wsdl>-->
                                    <bindingFiles>
                                        <bindingFile>${basedir}/src/main/resources/binding.xjb</bindingFile>
                                    </bindingFiles>
                                    <extraargs>
                                        <extraarg>-xjc-XtoString</extraarg>
                                        <extraarg>-xjc-Xequals</extraarg>
                                        <extraarg>-xjc-XhashCode</extraarg>
                                    </extraargs>
                                </wsdlOption>
                            </wsdlOptions>
                        </configuration>
                    </execution>
                </executions>
                <dependencies>
                    <dependency>
                        <groupId>org.jvnet.jaxb2_commons</groupId>
                        <artifactId>jaxb2-basics</artifactId>
                        <version>0.6.3</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>
</project>

To use JAXB2-Basics, I added the module dependency starting at line 52. I also added a dependency for the cxf-codegen-plugin at line 93. After that, I had to add the at line 83.

  • -xjc-XtoString – triggers the generation of the toString() method
  • -xjc-Xequals – triggers the generation of the equals() method
  • -xjc-XhashCode – triggers the generation of the hashcode() method

The jaxb binding took a bit more work, but was fairly easy also. I specified the binding file on line 80. ${basedir} is a maven variable that is set to the directory of the module. The binding file is fairly straight forward. I specified a global binding that said serializable. I also specified the optional uid. If the uid is specified, then the value will be specified in the classes. NOTE: that the same uid value will be specified for all classes.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<jaxb:bindings version="2.0" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb">
    <jaxb:bindings>
        <jaxb:globalBindings>
            <jaxb:serializable uid="1"/>
        </jaxb:globalBindings>
    </jaxb:bindings>
</jaxb:bindings>

April 3rd, 2012

Posted In: Java, Maven, xml

Tags: , ,

Leave a Comment

ou would normally marshall a JAXB object to it’s XML String form by something similar to:

marshaller.marshal(tloPersonSearchOutput, stringWriter);

This assumes that the object is annotated with the JAXB @XmlRootElement annotation. If it is not, then you have to create a root element for it, by something like:

marshaller.marshal(new JAXBElement<TLOGenericSearchInput>(new QName("", "rootTag"),
                                                          TLOGenericSearchInput.class,
                                                          searchInput),
                   stringWriter);

You have to create the root element for the object. In this case, the root element is going to be called “rootTag”.

March 13th, 2012

Posted In: Java, xml

Tags: , , ,

Leave a Comment

Maven works great and solves lots of conflicting API problems for you.  The one case when it can’t help and usually hurts is when APIs change groupId or artifactId.  I recently had a case where I needed a CXF generated client to log the outbound and inbound soap messages. I added the following to my client spring config file.

<cxf:bus>
    <cxf:features>
        <cxf:logging/>
    </cxf:features>
 </cxf:bus>

This worked great in the small test app that I wrote.  It was an epic fail when I added it to my much larger webapp.

The problem was that the Xerces api that it was finding wasn’t the same version that it thought it was calling.

After much searching, I found Xerces and xml-api Dependency Hell.  This blog went into the history of the various names.  The gist is that now, you use xml-apis:xml-apis for your Maven XML dependency.  You may also have to exclude xerces:xmlParserAPIs and xml-apis:xmlParserAPIs.

While researching this, I ran across Using the EnvironmentCheck utility that can help diagnose XML API classpath problems.

March 1st, 2012

Posted In: Java, xml

One Comment

LinkedIn Auto Publish Powered By : XYZScripts.com