error using camel jaxb with java route - jaxb

According to Camel documentation, I create JaxbDataFormat (example code in documentation uses non-existing constructor, though?)
#Override
public void configure() throws Exception {
JaxbDataFormat jaxbDataFormat = new JaxbDataFormat();
jaxbDataFormat.setContextPath("somepackage");
I have pom-dependency
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jaxb</artifactId>
<version>2.18.3</version>
</dependency>
Doesn't work : "ConvertBody... because of Data format 'jaxb' could not be created."
Could somebody please give an example code how jaxb conversions are supposed to work with Camel. I have Camel in Action 2ed, but the example there uses XML-definde route. Procedure seems simple enough with XML - but I'm not very enthusiastic about using xml as programming language ;)
Using java 8.
............
Exception in thread "CamelMainRunController" java.lang.RuntimeException: org.apache.camel.FailedToCreateRouteException: Failed to create route route2 at: >>> Marshal[org.apache.camel.model.dataformat.JaxbDataFormat#57d7f108] <<< in route: Route(route2)[[From[activemq:gateway.queue]] -> [OnException... because of Data format 'jaxb' could not be created. Ensure that the data format is valid and the associated Camel component is present on the classpath
at org.apache.camel.spring.boot.CamelSpringBootApplicationController.run(CamelSpringBootApplicationController.java:74)
at org.apache.camel.spring.boot.CamelMainRunController$DaemonTask.run(CamelMainRunController.java:42)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.apache.camel.FailedToCreateRouteException: Failed to create route route2 at: >>> Marshal[org.apache.camel.model.dataformat.JaxbDataFormat#57d7f108] <<< in route: Route(route2)[[From[activemq:gateway.queue]] -> [OnException... because of Data format 'jaxb' could not be created. Ensure that the data format is valid and the associated Camel component is present on the classpath
at org.apache.camel.model.RouteDefinition.addRoutes(RouteDefinition.java:1071)
at org.apache.camel.model.RouteDefinition.addRoutes(RouteDefinition.java:196)
at org.apache.camel.impl.DefaultCamelContext.startRoute(DefaultCamelContext.java:984)
at org.apache.camel.impl.DefaultCamelContext.startRouteDefinitions(DefaultCamelContext.java:3401)
at org.apache.camel.impl.DefaultCamelContext.doStartCamel(DefaultCamelContext.java:3132)
at org.apache.camel.impl.DefaultCamelContext.access$000(DefaultCamelContext.java:183)
at org.apache.camel.impl.DefaultCamelContext$2.call(DefaultCamelContext.java:2961)
at org.apache.camel.impl.DefaultCamelContext$2.call(DefaultCamelContext.java:2957)
at org.apache.camel.impl.DefaultCamelContext.doWithDefinedClassLoader(DefaultCamelContext.java:2980)
at org.apache.camel.impl.DefaultCamelContext.doStart(DefaultCamelContext.java:2957)
at org.apache.camel.support.ServiceSupport.start(ServiceSupport.java:61)
at org.apache.camel.impl.DefaultCamelContext.start(DefaultCamelContext.java:2924)
at org.apache.camel.main.Main.doStart(Main.java:129)
at org.apache.camel.support.ServiceSupport.start(ServiceSupport.java:61)
at org.apache.camel.main.MainSupport.run(MainSupport.java:138)
at org.apache.camel.spring.boot.CamelSpringBootApplicationController.run(CamelSpringBootApplicationController.java:69)
... 2 more
Caused by: java.lang.IllegalArgumentException: Data format 'jaxb' could not be created. Ensure that the data format is valid and the associated Camel component is present on the classpath
at org.apache.camel.model.DataFormatDefinition.getDataFormat(DataFormatDefinition.java:107)
at org.apache.camel.model.DataFormatDefinition.getDataFormat(DataFormatDefinition.java:88)
at org.apache.camel.model.MarshalDefinition.createProcessor(MarshalDefinition.java:177)
at org.apache.camel.model.ProcessorDefinition.makeProcessorImpl(ProcessorDefinition.java:545)
at org.apache.camel.model.ProcessorDefinition.makeProcessor(ProcessorDefinition.java:506)
at org.apache.camel.model.ProcessorDefinition.addRoutes(ProcessorDefinition.java:222)
at org.apache.camel.model.RouteDefinition.addRoutes(RouteDefinition.java:1068)
... 17 more

add to pom
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jaxb-starter</artifactId>
<version>2.23.1</version>
</dependency>
and update project

Related

Why do I get "The constructor Attribute(String, boolean) is undefined"?

I'm creating a Instances instance using weka. When I define attributes, I get the following exception: "The constructor Attribute(String, boolean) is undefined". The following is the code I have tried:
...
Attribute dtzg = new Attribute("att1Name", 0);
Attribute pDea = new weka.core.Attribute("att2Name", true);
...
My pom weka dependency is the following:
<!-- https://mvnrepository.com/artifact/nz.ac.waikato.cms.weka/weka-stable -->
<dependency>
<groupId>nz.ac.waikato.cms.weka</groupId>
<artifactId>weka-stable</artifactId>
<version>3.8.0</version>
</dependency>
I would expect that I would be able to use the constructor "Attribute(java.lang.String attributeName, boolean createStringAttribute)" because it is listed as constructor in the javadoc here
I discovered that the documentation I was referring to is about the "develop" version of weka, while I imported in my pom the "stable" version of weka. So, if I exchange the dependency above with the following, the compiler does not complain:
<!-- https://mvnrepository.com/artifact/nz.ac.waikato.cms.weka/weka-dev -->
<dependency>
<groupId>nz.ac.waikato.cms.weka</groupId>
<artifactId>weka-dev</artifactId>
<version>3.9.3</version>
</dependency>
However, I'm curious about the difference between the two versions. I'll ask a question about it, if I'll have time.

How to use asciidoctorj-diagram with Java or Groovy?

PlantUML is a great extension for Asciidoc, but I can't figure out how to use from my groovy code.
As far as I can see, the asciidoctorj-diaram module should be part of the current asciidoctorj-Release, so I guess I need no additional dependency. But my code which renders asciidoc fine, does not render the PlantUML diagrams. It says:
invalid style for open block: plantuml
Any idea what could be wrong? The asciidoctorj-diagram examples I find on the net all use the gradle-plugin :-|
Even if the library is part of the AsciidoctorJ project, there is a separate java library called: asciidoctorj-diagram (the java version of asciidoctor-diagram)
Are you sure that you have asciidoctorj-diagram on your classpath? Here the maven coordinates:
<dependency>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctorj-diagram</artifactId>
<version>1.3.1</version>
</dependency>
You also need to tell Asciidoctor that asciidoctor-diagram is required. See line <1> in the following plain java example:
public static void main(String[] args) {
org.asciidoctor.Asciidoctor asciidoctor =
org.asciidoctor.Asciidoctor.Factory.create();
asciidoctor.requireLibrary("asciidoctor-diagram"); // <1>
StringBuilder sb = new StringBuilder();
sb.append("== Diagrams\n");
sb.append("\n");
sb.append("[plantuml,auth-protocol]\n");
sb.append("....\n");
sb.append("Alice -> Bob: Authentication Request\n");
sb.append("Bob --> Alice: Authentication Response\n");
sb.append("\n");
sb.append("Alice -> Bob: Another authentication Request\n");
sb.append("Alice <-- Bob: another authentication Response\n");
sb.append("....\n");
String html = asciidoctor.convert(sb.toString(),
new java.util.HashMap<String, Object>());
System.out.println(html);
}
By the way, there is also a maven example: asciidoctor-diagram-example. But this example requires the asciidoctor-maven-plugin which is similar to the gradle plugin.

Jersey 2 - JAXB

Using Jersey 2 m13-3 in Tomcat 7, I'm trying to post XML and have JAXB automatically unmarshal it.
My method signature is something like:
#POST
#Consumes(MediaType.APPLICATION_XML)
#Produces( {"text/xml"})
public Response setFoo(
myXJC.generatedclass.Foo foo
)
I get a 400 bad request, but no exception (that I can find).
Testing with:
#POST
#Consumes(MediaType.APPLICATION_XML)
#Produces( {"text/xml"})
public Response setFoo() { ... }
I'm confident this method is being invoked in response to a request.
But as soon as I add arg myXJC.generatedclass.Foo, it isn't.
Do I need something special in my class which extends javax.ws.rs.core.Application to use JAXB? Something ResourceConfig related perhaps? Any extra jersey specific jars?
I see there is a jersey-media-moxy. I'd be happy to get it working with MOXy, but ideally it would also work with Sun/Oracle JAXB.
I've had a look at the source code of:
<dependency>
<groupId>org.glassfish.jersey.examples</groupId>
<artifactId>jaxb</artifactId>
<version>2.0-m13-3</version>
</dependency>
but I'm still having trouble.
Turns out that when I generated the classes from my XSD using XJC, I'd left an incorrect target namespace in there.
The XML I was posting was not namespace qualified, but the generated classes were expecting a namespace.
Once I fixed this, things worked fine.

integrating Swagger with JAX-RS and JAXB help needed

I'm working on REST Api using JAX-RS and JAXB. I also would like to use Swagger to generate docs for the api. I followed the example here https://github.com/wordnik/swagger-core/wiki/java-jax-rs . So I have added com.wordnik.swagger.jaxrs.listing to init parameters in web.xml as below:
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.api.resources;com.api;com.wordnik.swagger.jaxrs.listing;</param-value>
</init-param>
When I tray to access the localhost:9090/rapi/api-docs.json url I get the following error:
SEVERE: Mapped exception to response: 500 (Internal Server Error)
javax.ws.rs.WebApplicationException: javax.xml.bind.JAXBException: class com.wordnik.swagger.core.Documentation nor any of its super class is known to this context.
at com.sun.jersey.core.provider.jaxb.AbstractRootElementProvider.writeTo(AbstractRootElementProvider.java:159)
at com.sun.jersey.spi.container.ContainerResponse.write(ContainerResponse.java:306)
at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1451)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1363)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1353)
at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:414)
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:537)
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:708)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:362)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:726)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:206)
at org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:114)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at org.mortbay.jetty.Server.handle(Server.java:324)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:505)
at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:829)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:514)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:211)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:380)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:395)
at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:488)
Caused by: javax.xml.bind.JAXBException: class com.wordnik.swagger.core.Documentation nor any of its super class is known to this context.
at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getBeanInfo(JAXBContextImpl.java:611)
at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:486)
at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:320)
at com.sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:177)
at com.sun.jersey.json.impl.BaseJSONMarshaller.marshallToJSON(BaseJSONMarshaller.java:103)
at com.sun.jersey.json.impl.provider.entity.JSONRootElementProvider.writeTo(JSONRootElementProvider.java:143)
at com.sun.jersey.core.provider.jaxb.AbstractRootElementProvider.writeTo(AbstractRootElementProvider.java:157)
I fixed it by adding com.wordnik.swagger.core to my custom JAXBContextProvider as below:
public JAXBContextProvider() throws JAXBException {
this.context = new JSONJAXBContext(JSONConfiguration.natural().build(),
"com.api.model.impl.v1:com.api.resource.framework:com.wordnik.swagger.core");
}
This caused another error:
SEVERE: The provider class, class comapi.JAXBContextProvider, could not be instantiated. Processing will continue but the class will not be utilized
javax.xml.bind.JAXBException: "com.wordnik.swagger.core.Documentation" doesnt contain ObjectFactory.class or jaxb.index
I have been using jaxb.index files to keep the context aware of the classes with JAXB annotations, however there is no jaxb.index file in swagger package which inludes the Documentation class. Has anyone come across similar issue when integrating Swagger with JAXB and JAX-RS?
Turned out I needed to create JAXBContext in addition to already created JSONJAXBContext.
I added
this.swaggerJAXBcontext = JAXBContext.newInstance(com.wordnik.swagger.core.Documentation.class);
to constructor and this to getContext(Class type) method:
if (type.equals(com.wordnik.swagger.core.Documentation.class)){
return swaggerJAXBcontext;
}

No suitable classloader found for grab

I have this at the beginning of a class:
#Grab(group = 'org.ccil.cowan.tagsoup', module = 'tagsoup', version = '1.2')
class MyClass{...
I'm trying to unit test this class, but whenever I try to run JUnit 4 tests, I get this error:
Caused by: java.lang.RuntimeException: No suitable ClassLoader found for grab
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at org.codehaus.groovy.reflection.CachedConstructor.invoke(CachedConstructor.java:77)
at org.codehaus.groovy.runtime.callsite.ConstructorSite$ConstructorSiteNoUnwrapNoCoerce.callConstructor(ConstructorSite.java:102)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallConstructor(CallSiteArray.java:52)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:190)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:198)
at groovy.grape.GrapeIvy.chooseClassLoader(GrapeIvy.groovy:163)
at groovy.grape.GrapeIvy$chooseClassLoader.callCurrent(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:44)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:149)
at groovy.grape.GrapeIvy.grab(GrapeIvy.groovy:227)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSite.invoke(PogoMetaMethodSite.java:225)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:51)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:44)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:153)
at groovy.grape.GrapeIvy.grab(GrapeIvy.groovy:216)
at groovy.grape.Grape.grab(Grape.java:131)
at groovy.grape.Grape$grab.callStatic(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallStatic(CallSiteArray.java:48)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:165)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:173)
at ammoscanner.AmmoScanner.<clinit>(AmmoScanner.groovy)
... 30 more
Any ideas? I'm using groovy 1.7.5
The Problem
Looking at the source code, this exception is thrown whenever the supplied ClassLoader's name (or it's superclasses) is not groovy.lang.GroovyClassLoader or org.codehaus.groovy.tools.RootLoader. i.e. The target classloader must be an instance of the aforementioned classes (a bit restrictive IMHO).
A Solution
Currently I don't know how to configure a specific classloader using #Grape/#Grab/#GrabConfig annotations. The closest would be to use #GrabConfig(systemClassLoader=true), and ensure the System classloader is an instance of one of the above ClassLoader classes.
If anyone does know, please let me know (and I'll update this answer).
A Workaround
The following code will programmatically download your Grapes, and load them into the supplied GroovyClassLoader (admittedly, not quite what you want).
def loadGrapes(){
ClassLoader classLoader = new groovy.lang.GroovyClassLoader()
Map[] grapez = [[group : 'org.ccil.cowan.tagsoup', module : 'tagsoup', version : '1.2']]
Grape.grab(classLoader: classLoader, grapez)
println "Class: " + classLoader.loadClass('org.ccil.cowan.tagsoup.jaxp.SAXParserImpl')
}
Using #Grab makes code untestable, at least as of 01/26/2011.
Solution that worked for me (both for running tests for scripts using #Grab in IntelliJ and via Maven):
Reference the dependencies used via #Grab in your Maven pom.xml file (this is useful anyway for better coding experience):
E.g. I have the following #Grab in my Groovy script:
#Grab(group='info.picocli', module='picocli', version='4.6.1')
So I add the following Maven dependency:
<dependency>
<groupId>info.picocli</groupId>
<artifactId>picocli</artifactId>
<version>4.6.1</version>
</dependency>
Add an optional dependency on ivy in your Maven pom.xml file (needed to handle #Grab properly in your IDE):
<dependency>
<groupId>org.apache.ivy</groupId>
<artifactId>ivy</artifactId>
<version>${ivy.version}</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
In your test code, set groovy.grape.enable system property to false. This is the main and crucial part of the solution - it disables #Grab annotation processing for the script, but remember we already have those dependencies referenced in our Maven pom.xml file:
static {
System.setProperty("groovy.grape.enable", "false")
}
#Test
void test() {
MainScript.call()
}
The downside of the solution is that you have to duplicate your dependencies in #Grab and Maven pom.xml file but again, if you develop a Groovy script you oftentimes already do so to improve your coding experience (get better code highlights etc).
I assume you've tried adding
#GrabConfig(systemClassLoader=true)
like so:
#Grapes([
#Grab(group = 'org.ccil.cowan.tagsoup', module = 'tagsoup', version = '1.2'),
#GrabConfig( systemClassLoader=true )
])
class MyClass{...
If you are not using systemClassLoader=true then it seems your IDE is not rrunning the code with a groovy compiler, you can check that with a simple groovy class that outputs the class name of its classloader. I would guess it tries to compile the groovy classes and run them with a non-groovy classloader.
See also this answer to General error during conversion: No suitable ClassLoader found for grab. Also this blog post explains more about running pre-compiled groovy classes with the stock classloader.
Add the plugin snapshot update site for Kepler.
This seems to solve the "..no suitable classloader problem". Unfortunately, I still had to add the grape repo to the classpath for the project after this.
There's one more solution for testing a class with #Grab annotation:
Extract an interface from this class.
Create another class which implements its interface. Move the #Grab annotation to this class. Then make this class a simple wrapper, which just passes all the messages to the original class.
Run the tests against your original class.
Whenever you need to have a version #Grab, use the wrapper.
There is a solution to this!
You can use Groovy's metaprogramming to override the methods responsible for determining if the class loader is an instance of groovy.lang.GroovyClassLoader or org.codehaus.groovy.tools.RootLoader.
Because of this Groovy bug, you cannot override the private methods using metaprogramming, otherwise you could go ahead and change the isValidTargetClassLoaderClass method by doing this:
GrapeIvy.metaClass.isValidTargetClassLoaderClass = { Class loaderClass ->
return (loaderClass != null)
}
However, isValidTargetClassLoaderClass is called by isValidTargetClassLoader (another private method), which is called by chooseClassLoader, which is a public method, which can be overridden using metaprogramming:
GrapeIvy.metaClass.chooseClassLoader = { Map args ->
def loader = args.classLoader
if (loader?.class == null) {
loader = (args.refObject?.class
?: ReflectionUtils.getCallingClass(args.calleeDepth?:1)
)?.classLoader
while (loader && loader?.class == null) {
loader = loader.parent
}
if (loader?.class == null) {
throw new RuntimeException("No suitable ClassLoader found for grab")
}
}
return loader
}
All I did was replace any calls to !isValidTargetClassLoader with loader?.class == null.
Now, I am using Spock, so I put this code in my setupSpec method in my test class. However if you are using JUnit, I would imagine it would want to go in the method annotated with #BeforeClass.
Here is an example of it working with Spock (notice IntelliJ showing it about to return a class loader that would normally throw an exception:

Resources