javabean-validationjaxb2jaxb2-basicsannox

ClassNotFoundException with jaxb/annox and custom annotation


I'm a little stuck with an annotations usage scenario and I was hoping for your input.

Given the following annotation (defined in the same project along with ExistingCustomerValidator class ) package com.tktserver.constraints;

@Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = { ExistingCustomerValidator.class })
@Documented
public @interface ExistingCustomerMatch {
    String message() default "{customer.notfound}";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    /**
     * @return The field
     */
    String field();
}

and the following jxb customisation

<jaxb:bindings node="xsd:complexType[@name='customer']">
    <annox:annotate>
        <annox:annotate
            annox:class="com.tktserver.constraints.ExistingCustomerMatch"
            field="electronicUserId" />
    </annox:annotate>
</jaxb:bindings>

I get this when I generate my sources via Maven (the entire project is handled by it)

Caused by: org.jvnet.annox.annotation.AnnotationClassNotFoundException: Annotation class [com.tktserver.constraints.ExistingCustomerMatch] could not be found.
    ... 32 more
Caused by: java.lang.ClassNotFoundException: com.bgc.ticketserver.constraints.ExistingCustomerMatch
    at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:169)
    at org.jvnet.annox.parser.XAnnotationParser.parse(XAnnotationParser.java:76)
    ... 31 more

Other JSR-303 annotations seem to work fine. What I'm wondering is whether I'm getting trapped by a cyclic dependency here i.e. generate-sources runs first, then compile, therefore there's no ExistingCustomerMatch annotation class available when generate-sources runs, or whether this is an entirely different beast.

Thanks, Ioannis


Solution

  • I got my annox JAXB plugin working with xjc by using the antrun plugin in maven with the org.jvnet XJC2Task against the maven.compile.classpath. (see http://confluence.highsource.org/display/J2B/JAXB2+Basics+XJC+Ant+Task) Could never get it to work with straight maven plugins.

    But that's not why I came here to write. I am guessing you landed here because you are very clever with your Google searches and you are doggedly determined to get out of whatever JAXB hell you are in via this annox thing. It is with humility that I write to you, I have been there with you time and time again. And I'm writing to you today to say: stop struggling, you're doing it wrong

    My advice is for those who are to the point in their personal "compile-xsd-to-jaxb-beans" adventure where the desire is to add annotations to your generated JAXB beans by-way of annox or anything else. If you are there, then you may be feeling constrained and hamstrung by the limitations of XSD's or your XSD's may be getting out of control.

    My experience with building my XML Schema into JAXB beans was pretty good to start with, it was gratifying to see all those pojos appear and my schema's were all factored nicely with different namespaces and imported into one master XSD. My build was really clear. I found myself trying to add Javadoc documentation tags everywhere and my XSD's were getting more and more complicated. But my generated beans were very good looking and I got free Javadocs out of the deal. I had to put in some JAXB annotations (@XMLTransient, mainly) and the only way I could get annox to work in maven for me was to use an antrun plugin with the hacky Ant task, I was unhappy with that kludge. I thought, why can't these things just work??

    Then more and more requirements forced me into tighter and tighter corners with my schema design and I was spending more and more time hacking XSD - until the breaking point: I had to be able to marshal to JSON using EclipseLink MOXy, and suddenly my schema could not be twisted into that pretzel and get both good looking JSON and XML. I was stuck, and for a long time.

    I consulted an expert and he told me to drop my schema-to-JAXB-beans effort entirely. The right way to go was to hand-write my JAXB beans with JAXB and MOXy annotations and then use schemagen to generate my .xsd's. Go the other direction!? It worked. My schemagen-generated .xsd's weren't pretty, but who cares, it worked! The schema was correct per my beans and it just all worked when I parsed XML and with MOXy, I could marshal my beans to JSON.

    To convert my code over, I even used my original generated JAXB beans I had from my hand-written schema as a starting point, so I didn't even need to start from scratch. In fact, I threw away more than half of my generated JAXB beans; they were superfluous (xjc generates a ton of throw-away classes.) The best part is now I am familiar with the MOXy annotations. Use MOXy as your provider for everything, stop using the built-in Oracle JAXB impl entirely. MOXy is the future of JAXB.

    So, I hope this reaches you poor souls trying to make XJC work. I hope you will stop suffering with your pretzel twisting. It won't take you very long to make the change, just do it.