Jackson with JodaTime and Jax-rs - java

I have a REST web-service created in Java. I am using Joda-time for the date and Jackson for the JSON formatting. Everything is uploaded on a Glassfish 4.1 server
Versions
avax.ws.rs-api-2.0.1.jar
joda-time-2.7.jar
jackson-annotation-2.8.8.jar
jackson-core-2.8.8.jar
jackson-databind-2.8.8.jar
jackson.datatype-joda-2.8.8.jar
Mapper
#Provider
public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper>{
final ObjectMapper mapper = new ObjectMapper();
public ObjectMapperContextResolver() {
mapper.registerModule(new JodaModule());
}
#Override
public ObjectMapper getContext(Class<?> type) {
return mapper;
}
}
Error when calling the service
java.lang.NoSuchFieldError: WRITE_DURATIONS_AS_TIMESTAMPS
What I found
I already found that it may have a mismatch between different versions. All the jars come from maven repository and I took each times the dependencies needed.
Question
What am I missing ? Is there a missing library ? Is there a wrong library's version ?
Note: I am not using Maven
Update
I tried to update the jackson-?.jars inside glassfish4.1/glassfish/modules but now I cant even start the server because of a requirement mismatch with jackson versions
Updates 2
Is there a way to use the jackson libraries that are inside my project instead of the one in Glassfish ? This seems to be the solution

Is there a way to use the Jackson libraries that are inside my project instead of the one in Glassfish? This seems to be the solution.
See the following quote from the chapter 2 of the GlassFish 4 Application Development Guide:
The Java Servlet specification recommends that a web module's class loader look in the local class loader before delegating to its parent. You can make this class loader follow the delegation inversion model in the Servlet specification by setting delegate="false" in the class-loader element of the glassfish-web.xml file. It is safe to do this only for a web module that does not interact with any other modules. [...]
The default value is delegate="true", which causes a web module's class loader to delegate in the same manner as the other class loaders. You must use delegate="true" for a web application that accesses EJB components or that acts as a web service client
or endpoint. [...]
For a number of packages, including java.* and javax.*, symbol resolution is always delegated to the parent class loader regardless of the delegate setting. This prevents applications from overriding core Java runtime classes or changing the API versions of specifications that are part of the Java EE platform.
In the section B of the GlassFish 4 Application Deployment Guide you'll find an example of the glassfish-web.xml deployment descriptor. Tailoring it to your issue, your glassfish-web.xml file would be like:
<!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD
GlassFish Application Server 3.1 Servlet 3.0//EN"
"http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
<glassfish-web-app>
<class-loader delegate="false" />
</glassfish-web-app>
Then place it under WEB-INF of your web module.

Related

Is it possible to have EJBs in domain1/lib using GlassFish?

I use GlassFish 4 web profile and I have the following interface and class.
#Local
public interface SomeService {
...
}
#Singleton
public class SomeServiceBean implements SomeService {
...
}
When I put interface and class in .war archive (that is in domain1/autodeplay) everything works fine. However, when I put interface and class in separate .jar archive (that is in domain1/lib) then deploying war application I get:
java.lang.RuntimeException: Cannot resolve reference Local ejb-ref name=com.temp.MyServlet/someService,Local 3.x interface =com.temp.SomeService,ejb-link=null,lookup=,mappedName=,jndi-name=,refType=Session
at com.sun.enterprise.deployment.util.ComponentValidator.accept(ComponentValidator.java:374) ~[dol.jar:na]
at com.sun.enterprise.deployment.util.DefaultDOLVisitor.accept(DefaultDOLVisitor.java:78) ~[dol.jar:na]
at com.sun.enterprise.deployment.util.ComponentValidator.accept(ComponentValidator.java:123) ~[dol.jar:na]
at com.sun.enterprise.deployment.util.ApplicationValidator.accept(ApplicationValidator.java:152) ~[dol.jar:n
...
I don't use any xml descriptors. So, is it possible to have EJBs in domain1/lib and if yes, how to make EJB container find them? P.S. I tried in GF 4 full - result is the same.
EJBs cannot be added as a library to GlassFish, libraries are just added to the classpath and any annotations on them are ignored and they do not go through the EJB container. If you do want your EJBs as a seperate JAR, they can be deployed just like a WAR or EAR file.
In the Glassfish reference manual for the add-library command it says that it "adds the library to the class loader directory", while for the deploy command it says that "Applications can be...EJB modules".
Also by looking at the source code for Glassfish it can be worked out that all libraries are simply added to the Classloader either at launch (See here and here) or if in applibs then when the application is deployed (See here).

RESTEasy annotation scan unable to find resources (under Tomcat)

I'm trying to update WAR with old RESTEasy 3.0.5 to something newer. 3.0.6 works fine, but after updating to 3.0.7 (or higher, like 3.0.24) all resources (#Path) are lost — 404 for any resource. WAR is run under Apache Tomcat server.
I believe the reason is linked to change of annotation scanner:
https://issues.jboss.org/browse/RESTEASY-1010
I've tried to create class which extends javax.ws.rs.core.Application instead of web.xml configuration. According to answer https://stackoverflow.com/a/29957040/2528366, empty set should trigger scan for #Path but no any resource is found. If I override getClasses() which returns non-empty set, that resources work as expected.
web.xml: https://pastebin.com/uRD2w6Z6
New Application inherited class:
#ApplicationPath("/rest")
public class WebApi extends Application
{
#Override
public Set<Class<?>> getClasses()
{
Set<Class<?>> s = new HashSet<>();
// if line below is uncommented SomeResource works fine
// s.add(SomeResourceImpl.class);
return s;
}
}
Resources are interfaces and implementation is in derived classes. Moving annotations to classes itself changes nothing.
What's wrong with annotations or configuration? Or is there something else needed to trigger scanning for annotations?
If you are using a Tomcat version that is compatible with the Servlet 3.0 specification, you need to add the resteasy-servlet-initializer dependency :
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-servlet-initializer</artifactId>
<version>${resteasy.version}</version>
</dependency>
As stated in the documentation :
Resteasy uses the ServletContainerInitializer integration interface in Servlet 3.0 containers to initialize an application, automatically scanning for resources and providers. To enable automatic scanning, you must also include the resteasy-servlet-initializer artifact in your WAR file as well

JAX-RS - Loading #Provider classes from a jar file

I have a simple Rest application that is deployed to an IBM MobileFirst 7.1 Liberty Server. (I don't know the implementation of the JAX-RS but it is included with the liberty server runtime I believe)
I have to share some of my common code with other teams, so I moved some of the code into a separate maven project to be jared and added as a server library. This all works great until I had to add some #Provider annotated classes into the separate maven project. Specifically, some ExceptionMapper implementations marked with the #Provider annotation.
I have tried setting the class directly within the Application classes getClasses() method. This seemed to work, but I get a warning message saying that my exception mapper implementations need to be marked with the #Provider or #Path annotations (which they are).
Is there some sort of trick to get JAX-RS to recognize these resource classes from a Jar file?
In order to have the #Provider recognized, please try to put the JAR inside the adapter /lib folder instead of the server/lib folder.

Dynamic Web Application - platform with components

I am doing a research on how to make a proper structure for my web application.
It will be a web application serving as a platform for additional, independent components.
The components must be able to map requests by using the #Controller annotaion.
So far I have learned, that:
The platform will be deployed as a .war file on Tomcat.
The platform classpath location will contain components in a form of .jar files.
My question is:
How to setup the components and the platform, so that platform will make use of the components' #Controllers?
So far I have the platform.war running on Tomcat. It is annotation based Spring configuration.
I also have the first component, it is a single Java class with #Controller annotation and first mapping. For some reason when I include this component in the classpath of the platform and try to access the url mapped in the component, the application returns 404 error. In the log files it says "No mapping found for HTTP request" so it does not initialize the component's #Controller.
For further explanation click here.
In your JAR file, create a package defining your namespace, i.e: "com.platformproject.web". Then all you need to do is put the JAR file in WEB-INF/lib (or better use Maven Modules) and scan the annotations at startup:
MvcConfig.java
#EnableWebMvc
#Configuration
#ComponentScan(basePackages = { "com.platformproject.web" })
public class MvcConfig extends WebMvcConfigurerAdapter { ... }

WSDL parsing exception creating Webservice client with CXF JaxWSClientFactoryBean

I've written some code to create and run webservice client using CXF. I used JaxWsClientFactoryBean (not sure it's the best solution) to create client from .wsdl file.
The goal here was to do this programmatically avoiding Spring etc. Just pure code with Java and CXF.
JaxWsClientFactoryBean cfb = new JaxWsClientFactoryBean();
cfb.setAddress(getServiceProperty(intClass, PROPERTY_KEY_URL_SUFFIX));
cfb.setServiceClass(intClass);
cfb.setOutInterceptors(getOutInterceptors(intClass));
cfb.setServiceName(SERVICE_NAME);
cfb.setWsdlURL("classpath:wsdl/" + intClass.getSimpleName() + ".wsdl");
cfb.setEndpointName(ENDPOINT_NAME);
Client client = cfb.create();
ClientProxy cp = new ClientProxy(client);
I intService = (I)
Proxy.newProxyInstance(intClass.getClassLoader(), new Class[] { intClass }, cp);
I'm really not sure if this is done correctly, but it works when I run this code locally and when I deploy it on Tomcat.
Unfortunatelly I need to run this code on Weblogic and this results in strange exception:
Caused by: javax.wsdl.WSDLException: WSDLException: faultCode=PARSER_ERROR: org.w3c.dom.DOMException: HIERARCHY_REQUEST_ERR: An attempt was
made to insert a node where it is not permitted.
at org.apache.cxf.wsdl11.WSDLManagerImpl.loadDefinition(WSDLManagerImpl.java:235)
at org.apache.cxf.wsdl11.WSDLManagerImpl.getDefinition(WSDLManagerImpl.java:186)
at org.apache.cxf.wsdl11.WSDLServiceFactory.<init>(WSDLServiceFactory.java:92)
... 26 more
Caused by: org.w3c.dom.DOMException: HIERARCHY_REQUEST_ERR: An attempt was made to insert a node where it is not permitted.
at com.sun.org.apache.xerces.internal.dom.ParentNode.internalInsertBefore(ParentNode.java:356)
at com.sun.org.apache.xerces.internal.dom.ParentNode.insertBefore(ParentNode.java:284)
at com.sun.org.apache.xerces.internal.dom.CoreDocumentImpl.insertBefore(CoreDocumentImpl.java:399)
at com.sun.org.apache.xerces.internal.dom.NodeImpl.appendChild(NodeImpl.java:235)
at org.apache.cxf.staxutils.StaxUtils.readDocElements(StaxUtils.java:1019)
at org.apache.cxf.staxutils.StaxUtils.readDocElements(StaxUtils.java:939)
at org.apache.cxf.staxutils.StaxUtils.read(StaxUtils.java:866)
at org.apache.cxf.wsdl11.WSDLManagerImpl.loadDefinition(WSDLManagerImpl.java:226)
... 28 more
This happens during application deployment. It looks like there is something wrong with .wsdl file, but wait... It was working on Tomcat!
I think that there could be some difference in com.sun.org.apache.xerces.* classes implementation within Weblogic with its JRockit VM and standard JVM, but I have no idea how to solve it.
I spent many hours trying differend ways of client creation. Most of them worked locally and in Tomcat, but none on WebLogic.
Any hints what to try next? I'm kinda tired of this topic :D
I agree with your suspicion that the problem is related to the used version of Xerces. The stacktrace shows that the Sun implementation of Xerces which is derivative of the Apache Xerces is used in your case.
Please check the Apache CFX Application Server Configuration Guide instructions related to WebLogic.
WebLogic ClassLoading
In WebLogic Server, any .jar file present in the system classpath is loaded by the WebLogic Server system classloader. All applications running within a server instance are loaded in application classloaders which are children of the system classloader. In this implementation of the system classloader, applications cannot use different versions of third-party jars which are already present in the system classloader. Every child classloader asks the parent (the system classloader) for a particular class and cannot load classes which are seen by the parent.
For example, if a class called com.foo.Baz exists in both $CLASSPATH as well as the application EAR, then the class from the $CLASSPATH is loaded and not the one from the EAR. Since weblogic.jar is in the $CLASSPATH, applications can not override any WebLogic Server classes.
In order to use an alternate version of Xerces you have to create a FilteringClassLoader.
Usage of FilteringClassLoader
The FilteringClassLoader provides a mechanism for you to configure deployment descriptors to explicitly specify that certain packages should always be loaded from the application, rather than being loaded by the system classloader. This allows you to use alternate versions of applications such as Xerces and Ant.
The FilteringClassLoader sits between the application classloader and the system. It is a child of the system classloader and the parent of the application classloader. The FilteringClassLoader intercepts the loadClass(String className) method and compares the className with a list of packages specified in weblogic-application.xml file.
In conclusion, check the steps included in the Apache CFX Application Server Configuration Guide and take care to explicitly specify that the org.apache.xerces.* package is loaded from the application, rather than being loaded from the system classloader.
For example the weblogic-application.xml file in the META-INF should look like:
<?xml version="1.0" encoding="UTF-8"?>
<weblogic-application xmlns="http://www.bea.com/ns/weblogic/90">
<application-param>
<param-name>webapp.encoding.default</param-name>
<param-value>UTF-8</param-value>
</application-param>
<prefer-application-packages>
<package-name>javax.jws.*</package-name>
<package-name>org.apache.xerces.*</package-name>
</prefer-application-packages>
</weblogic-application>
I hope this helps.

Categories