Coder Social home page Coder Social logo

massfords / jaxb-visitor Goto Github PK

View Code? Open in Web Editor NEW
16.0 10.0 16.0 1 MB

Adds the visitor pattern that includes all JAXB objects produced by the xjc compiler.

License: Apache License 2.0

Java 98.06% Groovy 1.94%
jaxb jaxb-xjc jaxb-xjc-plugin visitor-pattern

jaxb-visitor's Introduction

jaxb-visitor

A visitor pass featuring duke, the Java mascot

What it does

This plugin adds the visitor pattern that includes all JAXB objects produced by the xjc compiler. The plugin produces the following changes in the beans:

  • add accept(Visitor) to each bean that invokes appropriate method on Visitor interface
  • create Visitor interface with visit method for each bean
  • create Traverser interface for traversing the graph with a Visitor
  • create DepthFirstTraverser class as a sample implementation of performing a depth first traversal of the graph
  • create BaseVisitor class with no-op methods for each visit as a suitable base class for providing your own operations
  • create TraversingVisitor that has a Visitor and Traverser and performs a traversing visit on all nodes in the graph
  • create TraversingVisitorProgressMonitor to get callbacks when a bean is visited and traversed

Changes in 3.0

  • Upgrade to jakarta namespace for XJC
  • Added flag for legacy javax.xml.bind support
  • Support for Java 11 at build and runtime
  • Change tests to be based on the Apache Maven Invoker

Changes in 2.0

Version 2.0 of the plugin changed the code generator to produce a Visitor and supporting classes that have a return type and an Exception on each visit method.

Integration Tests

The Apache Maven Invoker verifies the plugin behavior via a number of different test projects. The table below identifies each project and what is special about its configuration.

All folders in the table below are found under src/it Run a single test from the command line with the folder name: mvn verify -Dinvoker.test=basic

folder jaxb plugin version JAXB Version
bindings file
or namespace
extra args assertions
basic jaxb30-maven-plugin 0.15.0 visitor interfaces and classes
basic-arg jaxb30-maven-plugin 0.15.0 -Xvisitor-includeArg visitor interfaces and classes
basic-codehaus jaxb2-maven-plugin 3.1.0 visitor interfaces and classes
calcviz maven-jaxb2-plugin 0.15.3 2.1 -Xvisitor-legacy
-Xfluent-api
-Xvalue-constructor
unit tests show traverser and visitor working
direct-classes jaxb30-maven-plugin 0.15.0 3.0 visitor interfaces and classes
direct-classes-legacy maven-jaxb2-plugin 0.15.3 2.1 visitor interfaces and classes
dupe jaxb30-maven-plugin 0.15.0 visitor interfaces and classes
exclude-id-ref jaxb30-maven-plugin 0.15.0 3.0 -Xvisitor-noIdrefTraversal visitor interfaces and classes
legacy maven-jaxb2-plugin 0.15.3 -Xvisitor-legacy visitor interfaces and classes and one bean with JAXBElement
missing-type-attribute jaxb2-maven-plugin 3.1.0 visitor interfaces
noClasses jaxb30-maven-plugin 0.15.0 -Xvisitor-noClasses visitor interfaces
noOverload jaxb30-maven-plugin 0.15.0 -Xvisitor-includeType visitor interfaces and classes
ogc jaxb30-maven-plugin 0.15.0 only DepthFirstTraverserImpl and one type with a substitution group
serializable jaxb30-maven-plugin 0.15.0 3.0 only DepthFirstTraverserImpl

Configuration

jaxb-visitor is now in Maven Central. You only need to configure the dependency below in your pom:

<dependency>
    <groupId>com.massfords</groupId>
    <artifactId>jaxb-visitor</artifactId>
    <version>3.0.0</version>
</dependency>
Command Line Argument Description
-Xvisitor Main option name that triggers the plugin's behavior
-Xvisitor-package:com.your.package.name Tells the plugin which package to use for the generated code. If not specified, defaults to first package encountered during codegen
-Xvisitor-includeType Changes the default code generator for the visitor and traverse to avoid overloading and instead include the type name. This is in response to Issue #8 where very large schemas resulted in a large number of overloaded methods which can be a performance issue.
-Xvisitor-noClasses Skips the generation of classes. The plugin will only generate interfaces and modify the beans to support the visitor pattern.
-Xvisitor-noIdrefTraversal The DepthFirstTraverserImpl will only traverse the XML tree, and will not follow IDREFs
-Xvisitor-legacy Uses the legacy namespaces java.xml.bind and javax.annotation instead of jakarta
-Xvisitor-includeArg Includes a generic argument on each visit and traverse function.

Example Usage in POM

<plugin>
    <groupId>com.evolvedbinary.maven.jvnet</groupId>
    <artifactId>jaxb30-maven-plugin</artifactId>
    <version>0.15.0</version>
    <configuration>
        <schemaDirectory>
            ${basedir}/src/main/resources
        </schemaDirectory>
        <args>
            <arg>-Xvisitor</arg>
            <arg>-Xvisitor-package:org.example.visitor</arg>
        </args>
        <plugins>
            <plugin>
                <groupId>com.massfords</groupId>
                <artifactId>jaxb-visitor</artifactId>
                <version>3.0.0</version>
            </plugin>
        </plugins>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>generate</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Visitor Pattern

The standard Visitor Pattern provides a way to perform an operation on the elements of an object structure without changing the code for the object on which it operates (see Gang of Four).

Traversal

In many cases, the user wishes to traverse the entire object graph during a visit. The implementation of the graph traversal is typically done either in the accept method of the element being traversed or the implementation of the visitor. When implemented in the accept method, the order of the traversal is fixed for all visitor applications and traversal always occurs when visiting. When implemented within the visitor class, the visitor is in control of the traversal order and whether to traverse, but the actual traversal logic is typically repeated across all visitor implementations.

There are two goals for this visitor implementation that make the previous two options for traversal undesirable:

  • The traversal of the full graph is not always required
  • The order and depth of the traversal must be easily configurable

In order to address these requirements, the implementation of the graph traversal is externalized into its own interface. An implementation of the Traverser interface provides a single traverse method for each bean that allows the implementation to visit some or all of the child nodes in whatever order desired by the Traverser. This modular approach leads to a great deal of flexibility in the configuration of visitors and traversal.

The result of the externalization is that a Visitor implementation can address single nodes without traversing or work with a Traverser to visit the entire graph. The plugin generates a few classes to help provide the user a starting point in their implementations.

Class Description
DepthFirstTraverser Implementation of the Traverser interface that traverses all of the children in a depth first order
TraversingVisitor Implementation of the Visitor interface that contains a delegate Visitor for its operation and a Traverser to traverse the graph.
TraversingVisitorProgressMonitor Interface that receives callbacks when a node is visisted or traversed. Useful if you're maintaing a stack and pushing/popping nodes

Visitor Diagram

The UML diagrams below show the basic layout (minus the TraversingVisitorProgressMonitor)

visitor diagram

Sequence Diagram

The Sequence diagram showing the creation of a TraversingVisitor?. This only shows the interaction with a single bean. If the simple bean shown has child beans, then each of those beans would be visited during the traversal.

sequence diagram

JAXBElement Behavior

The JAXB tutorial suggests modifying your schema to avoid having JAXBElement<?> types. The problem with the JAXBElement wrapper is that you don't have a distinct class for the top level type which makes visiting and traversing difficult.

Use Simple Binding

The simple binding may help reduce some JAXBElement generation. Example Schema with JAXBElements

<xsd:schema>
    <!--- snip -->
    <xsd:element name="comparisonOps"
                 type="fes:ComparisonOpsType"
                 abstract="true"/>
    <xsd:complexType name="ComparisonOpsType" abstract="true"/>

    <xsd:element name="PropertyIsEqualTo"
                 type="fes:BinaryComparisonOpType"
                 substitutionGroup="fes:comparisonOps"/>
    <xsd:element name="PropertyIsNotEqualTo"
                 type="fes:BinaryComparisonOpType"
                 substitutionGroup="fes:comparisonOps"/>

    <xsd:element name="PropertyIsLike"
                 type="fes:PropertyIsLikeType"
                 substitutionGroup="fes:comparisonOps"/>
    <xsd:element name="PropertyIsNull"
                 type="fes:PropertyIsNullType"
                 substitutionGroup="fes:comparisonOps"/>
    <xsd:element name="PropertyIsNil"
                 type="fes:PropertyIsNilType"
                 substitutionGroup="fes:comparisonOps"/>
    <xsd:element name="PropertyIsBetween"
                 type="fes:PropertyIsBetweenType"
                 substitutionGroup="fes:comparisonOps"/>
</xsd:schema>

The schema snippet above is from the OGC schema. You can provide a filter where you specify a property/value with one of the following operators:

    (=, !=, >, >=, <, <=, LIKE, NULL, NIL, BETWEEN).

Note that the elements for some of these operators (LIKE, NULL, NIL, BETWEEN) all have custom types, while the other operators all derive from BinaryComparisonOpType.

The result is that the JAXB for the comparison type looks like this:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "ComparisonOpsType")
@XmlSeeAlso({
        BinaryComparisonOpType.class,
        PropertyIsNilType.class,
        PropertyIsBetweenType.class,
        PropertyIsNullType.class,
        PropertyIsLikeType.class
})
public abstract class ComparisonOpsType implements Named, Visitable { /*snipped*/
}

Note that we don't get top level classes for PropertyIsEqual, and others since they are all folded into BinaryComparisonOpType.

If you owned the schema, you would create custom types as the tutorial link at the top suggests but that's not always possible.

The result in this case is that the Visitor plugin will unwrap the JAXBElement value during its traversal and visiting. The drawback here is that the semantics of the element which are encoded in its name are not readily available in the visit method. Consider the case of the BinaryComparisonOpType? above. The visit method could be working with any of the following operators:

    =, !=, >, >=, <, <=.

Current Approach

The DepthFirstTraverserImpl? generated by the plugin is the class most affected by JAXBElements. When examining a generated bean, this portion of the code generator must consider all of the child beans in the object and whether and how to traverse them. Child properties that manifest as simple type elements or attributes are not traversed. Only values that are themselves generated beans get traversed.

The decision for whether to traverse a any element is made by examining its type.

Type Traversal Code
SomeGeneratedBean null check required but no cast since the generated bean will implement Visitable
SomeSimpleType no traversal since simple types are not Visitable
Collection of SomeGeneratedBean for each bean, null check required but no cast since the generated bean will implement Visitable
Collection of SomeSimpleType no traversal since simple types are not Visitable
Collection of ? extends Object for each bean check for instanceof Visitable and traverse if it is
JAXBElement of SomeGeneratedBean check element for not null and traverse its value if available
JAXBElement of ? extends Object check element for not null and its value for instanceof Visitable and traverse if it is

1.13+ handling

An additional step in the VisitorPlugin? adds a QName to beans that are wrapped within a JAXBElement. This field is automatically set via an Unmarshaller callback event. This QName can be used during a visit to check on the instance's name and therefore determine what the semantics are for the bean.

The snippet below illustrates how a visitor can check the QName while visiting a wrapped bean. Note that this assumes that the bean has been unmarshalled. There currently isn't a mechanism in place to set the QName apart from the Unmarshaller Listener.

public class VisitorExample implements Visitor {
    // ... snip ...
    @Override
    public void visit(BinaryComparisonOpType bean) {
        // shows how to check JAXBElement names when visiting
        if ("PropertyIsEqualTo".equals(
                bean.getJAXBElementName().getLocalPart())) {
            // behavior for equals
        }
    }
}

1.12 handling

The generated visitor and traversal classes do not address this issue. One workaround here is that the implementor could store the name during the traversal.

jaxb-visitor's People

Contributors

beckerjohannes avatar borismarin avatar hedath avatar marcparmet avatar massfords avatar sclassen avatar turbokiwi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jaxb-visitor's Issues

jaxb-visitor is not compatible with maven-jaxb2-plugin 0.14.0

java.lang.NoSuchMethodError: com.sun.tools.xjc.outline.Outline.getContainer(Lcom/sun/tools/xjc/model/CClassInfoParent;Lcom/sun/tools/xjc/model/Aspect;)Lcom/sun/codemodel/JClassContainer;
at com.massfords.jaxb.VisitorPlugin.getOrCreatePackageForVisitors(VisitorPlugin.java:215)

seems like the xjc api changed between version 2.2 and 2.3. In particular com.sun.tools.xjc.model.Aspect was moved to com.sun.tools.xjc.outline.Aspect

To reproduce change the xjc version in the pom to 2.3.0:

<dependency>
   <groupId>org.glassfish.jaxb</groupId>
   <artifactId>jaxb-xjc</artifactId>
   <version>2.3.0</version>
</dependency>

NullPointerException when running visitor plugin

I just tried running the 2.2 version of this plugin against the OGC Schemas project and I'm getting a null pointer exception.

java.lang.NullPointerException
at com.massfords.jaxb.CreateDepthFirstTraverserClass.run(CreateDepthFirstTraverserClass.java:85)
at com.massfords.jaxb.VisitorPlugin.run(VisitorPlugin.java:122)
at com.sun.tools.xjc.model.Model.generateCode(Model.java:292)
at org.jvnet.mjiip.v_2_2.XJC22Mojo.generateCode(XJC22Mojo.java:66)
at org.jvnet.mjiip.v_2_2.XJC22Mojo.doExecute(XJC22Mojo.java:41)
at org.jvnet.mjiip.v_2_2.XJC22Mojo.doExecute(XJC22Mojo.java:28)
at org.jvnet.jaxb2.maven2.RawXJC2Mojo.doExecute(RawXJC2Mojo.java:488)
at org.jvnet.jaxb2.maven2.RawXJC2Mojo.execute(RawXJC2Mojo.java:311)

The line it's failing on is:

boolean isJAXBElement = ClassDiscoverer.isJAXBElement(getter.type());

After the NPE is thrown, the scratch.java file is left behind (not cleaned up, due to the unchecked exception thrown) and the scratch file then causes compilation to fail.

You should be able to reproduce it by running "mvn install" against this branch of my repository:
https://github.com/tastle/ogc-schemas/tree/visitor

visitor / depth first trasverser with custom class bindings

I am using <jxb:class implClass=MyClass> or <jxb:class ref=MyClass> binding customizations to get jaxb to use custom classes which extend those generated automatically (e.g. MyClass extends org.x.y.DefaultClass). Jaxb-visitor always generates visitors with signatures which point to the automatically generated classes, though (e.g. public void traverse (DefaultClass aBean, Visitor<?,E> aVisitor){} instead of public void traverse (MyClass aBean, Visitor<?,E> aVisitor){}). We can always cast MyClass to DefaultClass when creating visitors, though, so that is not very problematic.

In addition, the depth first traverser is not generated correctly for lists of custom objects customized via <jxb:class ref=...>. The for(myClass mc: getMyClass){} loop is not created when the customizations are present - probably because of the logic here.

Limit Visitor to a Particaular type

is there a way to limit the visitor to a particular type?
I saw an IncludeType command line arg, but that doesn't take any arguments itself.

For example if you had something that contained a list of substitutionGroup it would be nice to have the visitor work on just that substitution group. not for every type in the schema.

Problems with TraversingVisitor implementation for custom classes

First, thanks for the great plugin! With that out of the way, I wanted to explain an issue I've come across.

I am working on a project with various microservices that communicate via XML. I am using JAXB and this plugin to generate classes from the XML schemas that define the interactions. The issue I have is that I want to use a common implementation of a type that is imported in multiple schemas. I am using <jaxb:class ref="..."/> to reference the common implementation. This correctly changes all references to the type in the generated classes to be the common implementation. However, the referenced type doesn't implement the generated Visitable interface, and as such the generated TraversingVisitor implementation fails to compile.

The DepthFirstTraverserImpl class contains a comment about details not being known at compile time. Can this be extended to the generated TraversingVisitor class so that the generated code at least compiles? In this project I am writing my own Visitor implementation anyway. Alternatively, as I'm not using the generated classes, could an option be provided to only generate the various interfaces and not the classes?

I have pushed a sample project that demonstrates the problem: https://github.com/neilgreatorex/jaxb-visitor-test

Typed IDREF(S) properties lead to Compile Errors

Thanks for your great plugin!

We currently have a problem with using it in one of our project. We have an object model with a lot of cross referencing between the objects, that is seralized to XML. The cross referencing is implemented by IDREF(S) elements.

see http://ecad-wiki.prostep.org/doku.php?id=specifications:vec:start for XSD and model documentation.

Per default JAXB is generating IDREF(S) elements as properties with type Object or List<Object>. In our case this is not convenient, since there are model constraints that define specific types for specific IDREFS. To avoid programming errors during serialization and to avoid unnecessary type checks and cast during deserialization, we have to customize the IDREF properties to specific types.

The only way to this (at least the one we found) is to create custom binding like this one:

   <jxb:bindings node="//xs:complexType[@name='CompatibilityStatement']">
      <jxb:bindings node=".//xs:element[@name='Slot']">
         <jxb:property>
            <jxb:baseType name="......VecAbstractSlot"/>
         </jxb:property>
      </jxb:bindings>
   </jxb:bindings>

And here starts the problem. The VecAbstractSlot itself is included in the schema and is generated by XJC, but at the time of parsing the Schema (and the Binding) XJC does not know that it generates the class. So FieldOutline.getRawType() is initialized with a com.sun.codemodel.JDirectClass .

In the plugin, this leads to duplicate methods in the Visitor interface, because one method is created for the generated class, and one method is created for the com.sun.codemodel.JDirectClass which actually point to the same class. Same applies to the Traverser.

Additionally, the DepthFirstTraverserImpl generates traversal for the IDREF(S) properties as well, which will result in endless looping.

From my point of view, there are two possible solutions:

  1. Exclude the IDREF(S) properties from com.massfords.jaxb.ClassDiscoverer.discoverDirectClasses(Outline, Set<ClassOutline>). (I tried it and it works).
  2. Double check, that there is no JDefinedClass with the same name as the JDirectClass.

I will try the second approach, as it seems more elegant and does not require interpretation of the CPropertyInfo.getSchemaComponent() and submit a pull request for either the first or the second approach.

THX in advance

Possible issue with generated DepthFirstSearchTraverserImpl?

The DFS traversal that was generated by your tool gave me a method like this:

public void traverse(HTMLTextType aBean, Visitor<?, E> aVisitor)
    throws E
{
    for (Serializable bean: aBean.getContent()) {
        if (bean instanceof Visitable) {
            ((Visitable) bean).accept(aVisitor);
        }
    }
}

and I had to patch it (using a subclass) to get the traverser to visit everything:

static class PatchedDepthFirstTraverserImpl<E extends Throwable> extends DepthFirstTraverserImpl<E> {
    public void traverse(HTMLTextType aBean, Visitor<?, E> aVisitor) throws E {
        for (Serializable bean: aBean.getContent()) {
            if (bean instanceof JAXBElement<?>) {
                Object v = ((JAXBElement<?>) bean).getValue();
                if (v instanceof Visitable)
                    ((Visitable) v).accept(aVisitor);
            }
            else if (bean instanceof Visitable)
                ((Visitable) bean).accept(aVisitor);
        }
    }
}

The instanceof JAXBElement test is the new code. What does your experience suggest why this is necessary? Thanks. Great tool.

support both Jakarta and JDK 8 style dependencies

The newer versions of Java require the Jakarta dependencies so it seems reasonable to have this as the default.

Some users may need to remain on JDK 8 and not want to add the Jakarta dependencies or change supporting code. There should be another switch defined to allow the legacy code gen.

NPE in `ClassDiscoverer::handleXmlElement`

ClassDiscoverer#handleXmlElement fails with an NPE on type when processing the following XSD file. This is (I think) because the generated Java classes (at least, using the codehaus plugin) do not have a type associated with the XmlElement annotation for the base type:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="DerivedA" type="DerivedA"/>
    <xs:element name="BaseType" type="BaseType"/>

    <xs:element name="TypeList" type="TypeList"/>

    <xs:element name="DerivedD" type="DerivedD" />

    <xs:complexType name="TypeList">
        <xs:sequence>
            <xs:choice minOccurs="0" maxOccurs="unbounded">
                <xs:element ref="BaseType"/>
                <xs:element ref="DerivedA"/>
                <xs:element ref="DerivedD"/>
            </xs:choice>
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="BaseType">
        <xs:sequence>
            <xs:element name="localisations" minOccurs="0">
                <xs:complexType>
                    <xs:sequence>
                        <xs:element name="localisations" type="xs:string" nillable="true" minOccurs="0" maxOccurs="unbounded"/>
                    </xs:sequence>
                </xs:complexType>
            </xs:element>
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="AbstractBase">
        <xs:complexContent>
            <xs:extension base="PersistingOject">
                <xs:sequence>
                    <xs:element name="label" type="xs:string" minOccurs="0" />
                    <xs:element name="internalId" type="xs:long" minOccurs="0" />
                </xs:sequence>
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>

    <xs:complexType name="PersistingOject">
        <xs:sequence>
            <xs:element name="id" type="xs:string" minOccurs="0"/>
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="DerivedA">
        <xs:complexContent>
            <xs:extension base="BaseType">
                <xs:sequence>
                    <xs:element name="category" type="xs:int" minOccurs="0"/>
                </xs:sequence>
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>

    <xs:complexType name="DerivedD">
        <xs:complexContent>
            <xs:extension base="BaseType">
                <xs:sequence>
                    <xs:element name="nodeId" type="xs:string" minOccurs="0"/>
                </xs:sequence>
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>
</xs:schema>
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "TypeList", propOrder = {
    "baseTypeOrDerivedAOrDerivedD"
})
public class TypeList {

    @XmlElements({
        @XmlElement(name = "BaseType"), // <-- !
        @XmlElement(name = "DerivedA", type = DerivedA.class),
        @XmlElement(name = "DerivedD", type = DerivedD.class)
    })
    protected List<BaseType> baseTypeOrDerivedAOrDerivedD;

    // ...
}

I just ended up checking for nullity and that fixed it (obviously), but I'm not sure that that's the correct fix.

java.lang.NullPointerException: Cannot invoke "com.sun.codemodel.JAnnotationValue.generate(com.sun.codemodel.JFormatter)" because "type" is null
	at com.massfords.jaxb.codegen.ClassDiscoverer.handleXmlElement(ClassDiscoverer.java:114)
	at com.massfords.jaxb.codegen.ClassDiscoverer.lambda$parseXmlAnnotations$6(ClassDiscoverer.java:95)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
	at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625)
	at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:762)
	at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
	at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179)
	at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
	at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596)
	at com.massfords.jaxb.codegen.ClassDiscoverer.parseXmlAnnotations(ClassDiscoverer.java:95)
	at com.massfords.jaxb.codegen.ClassDiscoverer.lambda$discoverDirectClasses$0(ClassDiscoverer.java:62)
	at java.base/java.lang.Iterable.forEach(Iterable.java:75)
	at com.massfords.jaxb.codegen.ClassDiscoverer.lambda$discoverDirectClasses$1(ClassDiscoverer.java:51)
	at java.base/java.util.LinkedHashMap$LinkedValues.forEach(LinkedHashMap.java:647)
	at com.massfords.jaxb.codegen.ClassDiscoverer.discoverDirectClasses(ClassDiscoverer.java:48)
	at com.massfords.jaxb.VisitorPlugin.run(VisitorPlugin.java:159)
	at com.sun.tools.xjc.model.Model.generateCode(Model.java:262)
	at com.sun.tools.xjc.Driver.run(Driver.java:359)
	at org.codehaus.mojo.jaxb2.javageneration.AbstractJavaGeneratorMojo.performExecution(AbstractJavaGeneratorMojo.java:476)
	at org.codehaus.mojo.jaxb2.AbstractJaxbMojo.execute(AbstractJaxbMojo.java:337)
	at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:137)
	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:210)
	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:156)
	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:148)
	at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:117)
	at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:81)
	at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:56)
	at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:128)
	at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:305)
	at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:192)
	at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:105)
	at org.apache.maven.cli.MavenCli.execute(MavenCli.java:957)
	at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:289)
	at org.apache.maven.cli.MavenCli.main(MavenCli.java:193)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:282)
	at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:225)
	at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:406)
	at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:347)

I can't modify the .xsd files as they are exposed and generated by a service I consume.

add support for a param for visit and traverse generation

The visitor pattern often has an extra parameter passed into the visit function.

Add a new param like: -Xvisitor:includeArg

Example of a generated visit function w/ this switch enabled.

public interface Visitor<R, E extends Throwable, A> {
    R visit(BeanA bean, A arg) throws E;
}

If set, then include the type and argument

Duplicate methods in visitor

Thanks for the great plugin. I tried to upgrade from 1.x version to 2.3 version, but the visitor methods started to get duplicates. My schema produces static inner classes (due to nested complex types I guess) and these classes are the ones that get both a version that has package prefixed and non-package prefixed version. The same thing happens also to the implementations as well.

visit(com.example.One.Two.Three.Four.FooBar aBean);
visit(FooBar aBean); 

I think that the cause is XJC 2.2.11, but would it be possible to circumvent this in the plugin for the time being, because now I have to fix the code manually after generating it.

DepthFirstTraverserImpl follows IDREFS

Currently the DepthFirstTraverserImpl follows all outgoing references of a JAXB Object. This means it traverses the hierachy of the XML Structure and all cross-references in the tree via IDREF(S).

In a XML structure with IDREFS a traversal from the root Object results in multiple visits of the same objects and in the worst case in endless loops.

Traversal of the hierarchy only would be highly appreciated. ;-)

I will post a pull request for this.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.