quarkusio / quarkus

Quarkus: Supersonic Subatomic Java.
https://quarkus.io
Apache License 2.0
13.79k stars 2.68k forks source link

JAXB annotations on a Panache entity causes REST call to fail #6021

Closed jtsnr closed 4 years ago

jtsnr commented 4 years ago

I want to include JAXB annotations on my Panache entity so that I can return the entity in XML format in a REST response. Adding @XmlAttribute on the public property of the entity causes the REST call to fail with an exception. It is possible to change the access modifier of the property to private to prevent the exception however this approach then loses one of the benefits of Panache.

2019-12-08 14:33:28,640 ERROR [org.jbo.res.res.i18n] (vert.x-worker-thread-1) RESTEASY002005: Failed executing GET /person: org.jboss.resteasy.plugins.providers.jaxb.JAXBMarshalException: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
org.acme.quarkus.sample.Person#name has mutually exclusive annotations @javax.xml.bind.annotation.XmlTransient and @javax.xml.bind.annotation.XmlAttribute
    this problem is related to the following location:
        at @javax.xml.bind.annotation.XmlTransient()
        at org.acme.quarkus.sample.Person
    this problem is related to the following location:
        at @javax.xml.bind.annotation.XmlAttribute(name="Name", namespace="##default", required=false)
        at org.acme.quarkus.sample.Person

    at org.jboss.resteasy.plugins.providers.jaxb.AbstractJAXBProvider.getMarshaller(AbstractJAXBProvider.java:187)
    at org.jboss.resteasy.plugins.providers.jaxb.AbstractJAXBProvider.writeTo(AbstractJAXBProvider.java:149)
    at org.jboss.resteasy.core.interception.jaxrs.AbstractWriterInterceptorContext.writeTo(AbstractWriterInterceptorContext.java:193)
    at org.jboss.resteasy.core.interception.jaxrs.ServerWriterInterceptorContext.writeTo(ServerWriterInterceptorContext.java:64)
    at org.jboss.resteasy.core.interception.jaxrs.AbstractWriterInterceptorContext.proceed(AbstractWriterInterceptorContext.java:155)
    at org.jboss.resteasy.core.ServerResponseWriter.lambda$writeNomapResponse$2(ServerResponseWriter.java:156)
    at org.jboss.resteasy.core.interception.jaxrs.ContainerResponseContextImpl.filter(ContainerResponseContextImpl.java:404)
    at org.jboss.resteasy.core.ServerResponseWriter.executeFilters(ServerResponseWriter.java:232)
    at org.jboss.resteasy.core.ServerResponseWriter.writeNomapResponse(ServerResponseWriter.java:97)
    at org.jboss.resteasy.core.ServerResponseWriter.writeNomapResponse(ServerResponseWriter.java:70)
    at org.jboss.resteasy.core.SynchronousDispatcher.writeResponse(SynchronousDispatcher.java:578)
    at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:508)
    at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:252)
    at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:153)
    at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:363)
    at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:156)
    at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:238)
    at io.quarkus.resteasy.runtime.standalone.RequestDispatcher.service(RequestDispatcher.java:73)
    at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:118)
    at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.lambda$handle$0(VertxRequestHandler.java:74)
    at io.vertx.core.impl.ContextImpl.lambda$executeBlocking$2(ContextImpl.java:316)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
org.acme.quarkus.sample.Person#name has mutually exclusive annotations @javax.xml.bind.annotation.XmlTransient and @javax.xml.bind.annotation.XmlAttribute
    this problem is related to the following location:
        at @javax.xml.bind.annotation.XmlTransient()
        at org.acme.quarkus.sample.Person
    this problem is related to the following location:
        at @javax.xml.bind.annotation.XmlAttribute(name="Name", namespace="##default", required=false)
        at org.acme.quarkus.sample.Person

    at com.sun.xml.bind.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:76)
    at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:441)
    at com.sun.xml.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:273)
    at com.sun.xml.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:109)
    at com.sun.xml.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1126)
    at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:135)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:275)
    at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:264)
    at javax.xml.bind.ContextFinder.find(ContextFinder.java:403)
    at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:691)
    at org.jboss.resteasy.plugins.providers.jaxb.JAXBContextWrapper.<init>(JAXBContextWrapper.java:112)
    at org.jboss.resteasy.plugins.providers.jaxb.JAXBContextWrapper.<init>(JAXBContextWrapper.java:175)
    at org.jboss.resteasy.plugins.providers.jaxb.XmlJAXBContextFinder.createContextObject(XmlJAXBContextFinder.java:52)
    at org.jboss.resteasy.plugins.providers.jaxb.AbstractJAXBContextFinder.createContext(AbstractJAXBContextFinder.java:173)
    at org.jboss.resteasy.plugins.providers.jaxb.XmlJAXBContextFinder.findCachedContext(XmlJAXBContextFinder.java:41)
    at org.jboss.resteasy.plugins.providers.jaxb.AbstractJAXBProvider.findJAXBContext(AbstractJAXBProvider.java:83)
    at org.jboss.resteasy.plugins.providers.jaxb.AbstractJAXBProvider.getMarshaller(AbstractJAXBProvider.java:173)
    ... 24 more

To Reproduce Steps to reproduce the behavior:

  1. Create starter project.
  2. Add extensions: hibernate-orm-panache, agroal, resteasy-jaxb, and a JDBC driver extension
  3. Add datasource configuration to appliction.properties
  4. Create a Panache entity that includes a property with a JAXB annotation:
@Entity
@XmlRootElement(name = "Person")
@XmlAccessorType(XmlAccessType.NONE)
public class Person extends PanacheEntity {

    @XmlAttribute(name = "Name")
    public String name;
}
  1. Create a REST resource to return the entity in XML:
@Path("/person")
@Produces(MediaType.APPLICATION_XML)
public class PersonResource {

    @GET
    public Person find() {
        return Person.findAll().firstResult();
    }   
}
  1. Ensure that the database will be populated with a Person record (e.g. use import-dev.sql)
  2. Start the application and go to http://localhost:8080/person

Environment:

gsmet commented 4 years ago

@FroMage could you have a look at that one?

aguibert commented 4 years ago

@gsmet since Stephane appears to be busy I can take a look at this one

FroMage commented 4 years ago

Gladly. @aguibert you need to look at PanacheEntityEnhancer line 90 in visitEnd for the field visitor. It adds a @XmlTransient annotation to the field to force jaxb to use the getter. I guess if we have jaxb annotations we need to move them to the getter perhaps?

Or find a way to make jaxb simply ignore public fields if getters are available, as jsonb does.

aguibert commented 4 years ago

Was able to reproduce the issue and pushed a sample here for future reference: https://github.com/aguibert/basic-quarkus/tree/quarkus-6021