Add toString, hashCode, equals while generating JAXB classes in Java
Asked Answered
Q

3

17

I'm trying to generate JAXB classes from an XSD file programmatically, using Java. I've used the following code snippet to achieve that:

....
import java.io.File;
import java.io.IOException;
import org.xml.sax.InputSource;
import com.sun.codemodel.JCodeModel;
import com.sun.tools.xjc.api.S2JJAXBModel;
import com.sun.tools.xjc.api.SchemaCompiler;
import com.sun.tools.xjc.api.XJC;
....
....
public static void generateJaxb(String schemaPath,
                                    String outputDirectory,
                                        String packageName) throws DataLoadingException
{
    try {
        // Setup schema compiler
        SchemaCompiler sc = XJC.createSchemaCompiler();
        sc.forcePackageName(packageName);

        // Setup SAX InputSource
        File schemaFile = new File(schemaPath);
        InputSource is = new InputSource(schemaFile.toURI().toString());

        // Parse & build
        sc.parseSchema(is);
        S2JJAXBModel model = sc.bind();

        JCodeModel jCodeModel = model.generateCode(null, null);
        jCodeModel.build(new File(outputDirectory));
    } catch (IOException exec) {
        LOGGER.error("Error while generating JAXB classes: " + exec);
    }
}

The generated classes contain only the getter methods for the fields. But, I want to include the hashCode, equals and setter methods as well. How to do that while generating the code?

Quibbling answered 1/9, 2015 at 14:33 Comment(0)
E
17

On the GitHub website, you will find the JAXB2 Basics project, which provides a common set of JAXB utility plugins, including 4 that should address what you are trying to achieve:

  1. Equals Plugin
  2. HashCode Plugin
  3. Setters Plugin
  4. ToString Plugin

There are other plugins available that cover similar common aspects of Java domain objects.

Configuration

From an XML Schema configuration perspective, you will add references as shown here:

<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
    xmlns:basic="http://jaxb2-commons.dev.java.net/basic"
    xmlns:equals="http://jaxb2-commons.dev.java.net/basic/equals"
    xmlns:hashCode="http://jaxb2-commons.dev.java.net/basic/hashCode"
    xmlns:toString="http://jaxb2-commons.dev.java.net/basic/toString"
    jaxb:extensionBindingPrefixes="basic equals hashCode toString">
    <!-- ... -->
</xs:schema>

There are additional options available, such as defining object properties that should be ignored when generating an equals( that ) implementation, a toString() implementation, etc.

Java Code Generation

From a Java perspective, the plugins generally have the generated classes implement an interface; as an example, generated classes that include an equals( that ) implementation will implement the [Equals][6] interface.

The design approach used by the plugins usually generates 2 flavors of implementation:

  1. A simple/standard implementation, such as an equals( that ) method (when using the Equals Plugin).
  2. A more complex implementation that includes locator and strategy parameters, which allows you to implement custom handling (if you wish). For these, you will see a method signature such as: equals( thisLocator, thatLocator, that, strategy).

Build/Runtime

From a runtime perspective, you must include the JAXB2 Basics Runtime jar and provide option parameters such as: -Xequals, -XhashCode, or -XtoString. There are examples provided for using the JAXB2 Basics from Ant and Maven, if you are using either of those to perform builds and more build-related details are provided in the JAXB2 Basics User Guide.

Endorse answered 1/9, 2015 at 16:43 Comment(7)
Wow, good answer. Small addition: I've moved the code to GitHub: github.com/highsource/jaxb2-basicsSelfsuggestion
thnaks @Sean. I knew about the plugins present in JAXB2 Basics Runtime jar but couldn't find a way to include them into my code as they are not children of com.sun.tools.xjc.Plugin class.Quibbling
@ArkaGhosh They are subclasses of Plugin.Selfsuggestion
@Selfsuggestion I don't suppose there's a SimpleToString Plugin in the works?Sashasashay
@Sashasashay No, no SimpleToString plugin.Selfsuggestion
@Selfsuggestion what's this then? github.com/highsource/jaxb2-basics/tree/master/basic/src/main/…Sashasashay
@Sashasashay Unfinished experiments.Selfsuggestion
S
4

Update The answer below is incorrect. I was mislead by the interface, generateCode really does not do anything with plugins at the moment. As @Sidola pointed out, you should use SchemaCompiler instead.

In addition to @SeanMickey's answer I'll address code generation.

  • Add JAXB2-Basics JARs to your class path.
  • Instantiate
    • org.jvnet.jaxb2_commons.plugin.tostring.ToStringPlugin
    • org.jvnet.jaxb2_commons.plugin.equals.EqualsPlugin
    • org.jvnet.jaxb2_commons.plugin.hashcode.HashCodePlugin
    • org.jvnet.jaxb2_commons.plugin.setters.SettersPlugin
  • ...or whatever you need.
  • Pass plugins to model.generateCode(plugins errorListener) as the first parameter.

By the way, why do you want to generate code programmatically?

Selfsuggestion answered 1/9, 2015 at 21:31 Comment(6)
Thanks a lot @lexicore. That's exactly what I needed (children of com.sun.tools.xjc.Plugin class).Quibbling
And to answer your question - I'm trying to build a framework which will take an XSD as input and generate the required Entity classes and column family definitions to interact with Datastax Cassandra. In one of the steps, the JAXB classes needed to be generated.Quibbling
@ArkaGhosh The reason why I'm asking is that you'll get Java code generated which you'd have to compile first. This is normally what happens in builds so normally it only makes sense if you develop build tools.Selfsuggestion
@Selfsuggestion Does passing plugins to the generateCode method actually do anything? I wrestled with this problem today and noticed that the JAXBModelImpl found in 2.2.11 didn't do anything with the plugins in that method, as can be seen here. I had to add them as options to the SchemaCompiler instead.Carcinogen
@Sidola Hm, you're right. I was mislead by the interface. generateCode really does not do anything with plugins.Selfsuggestion
@Selfsuggestion Glad to hear I wasn't just seeing things then. I made a post here about how I solved it instead. Apparently you have to go through the SchemaCompiler.Carcinogen
P
1

For me the simplest way to do is using JAXB2 Basics Plugins:

  1. Add in pom.xml <dependencies>
<dependency> 
    <groupId>org.jvnet.jaxb2_commons</groupId>
    <artifactId>jaxb2-basics</artifactId>
    <version>0.11.1</version>
</dependency>
  1. Add the plugin
<plugin>
    <groupId>org.jvnet.jaxb2.maven2</groupId>
    <artifactId>maven-jaxb2-plugin</artifactId>
    <version>0.14.0</version>
    <executions>
        <execution>
            <goals>
                <goal>generate</goal>
            </goals>
            <configuration>
                <schemaDirectory>src/main/resources</schemaDirectory>
                <generateDirectory>target/generated-sources</generateDirectory>
                <generatePackage>my.package</generatePackage>
            </configuration>
        </execution>
    </executions>
    <configuration>
        <extension>true</extension>
        <args>
            <arg>-XtoString</arg>
            <arg>-Xequals</arg>
            <arg>-XhashCode</arg>
        </args>
        <plugins>
            <plugin>
                <groupId>org.jvnet.jaxb2_commons</groupId>
                <artifactId>jaxb2-basics</artifactId>
                <version>0.11.1</version>
            </plugin>
        </plugins>
    </configuration>
</plugin>

After mvn clean install the generated class will be like:

package my.package
public class MyClass implements Equals2, HashCode2, ToString2 {

}

Soure: https://github.com/highsource/jaxb2-basics/wiki/Using-JAXB2-Basics-Plugins

Pruinose answered 31/7, 2019 at 12:13 Comment(4)
Can you give complete instructions how to use it? I've added dependency and plugin in pom, called mvn clean install and have no any changes..Forthcoming
@Forthcoming Did you copied the configuration exactly as I shared? And the same jaxb2_commons version? If you didn't solved yet, please share the pom file. Updated the answer how the generated class will looks like.Pruinose
Solved my problem. Should use <plugins> section, not <pluginManagement>. Or define plugin description and configuration in pluginManagement, but also add to plugins sectionForthcoming
@NightEagle, yes indeed. Nice to hear you solved. In case this helped you out, you can always upvote the answer ;)Pruinose

© 2022 - 2024 — McMap. All rights reserved.