ClassNotFound exception using Jackson ObjectMapper - java

I have a Spring 3 MVC app that I am setting up some ajax actions for.
My controller action looks like this:
#RequestMapping(value="add", method=RequestMethod.POST)
#Secured("ROLE_USER")
#ResponseStatus(HttpStatus.CREATED)
public #ResponseBody Plan addPlan(#RequestBody Plan plan, Principal principal) {
//Save the plan
}
When I post the Plan data from my browser the app throws a ClassNotFound exception:
java.lang.ClassNotFoundException: org.joda.time.ReadableInstant not found by jackson-mapper-asl [176]
at org.apache.felix.framework.ModuleImpl.findClassOrResourceByDelegation(ModuleImpl.java:787)
at org.apache.felix.framework.ModuleImpl.access$400(ModuleImpl.java:71)
at org.apache.felix.framework.ModuleImpl$ModuleClassLoader.loadClass(ModuleImpl.java:1768)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
The Plan object itself does not contain any joda-date types. Though it contains a collection of objects that do. Originally I was pulling in the joda-date jar via my DOA jar but the error persists even if I add a direct dependency to my web project's pom.xml. I'm using the joda classes elsewhere in this project without any issue.
Additional information
Here are the relevant dependencies from my web pom.xml:
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<version>1.9.3</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.3</version>
</dependency>

I somehow came across this question: Apache FTP server is not seeing a logging jar package that exists in the class path
Their solution of setting <class-loader delegate="false"> in glassfish-web.xml seems to have fixed my issues.

I've reported this on Glassfish JIRA https://java.net/jira/browse/GLASSFISH-20808

Related

ClassNotFoundException in embedded Jetty when using Module system

I use an embedded Jetty (11.0.13) server with Jersey (3.1.0) that provides a simple REST interface which returns JSON objects. The JSON objects are serialized using Jackson.
The setup works fine as long as I don´t use Java´s module system.
But when I add the module-info.java file (see below), I get the following error as soon as I call the service.
WARNING: The following warnings have been detected: WARNING: Unknown HK2 failure detected:
MultiException stack 1 of 2
java.lang.NoClassDefFoundError: jakarta/xml/bind/annotation/XmlElement
at com.fasterxml.jackson.module.jakarta.xmlbind.JakartaXmlBindAnnotationIntrospector.<init>(JakartaXmlBindAnnotationIntrospector.java:137)
...
Caused by: java.lang.ClassNotFoundException: jakarta.xml.bind.annotation.XmlElement
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
... 83 more
MultiException stack 2 of 2
java.lang.IllegalStateException: Unable to perform operation: post construct on org.glassfish.jersey.jackson.internal.DefaultJacksonJaxbJsonProvider
at org.jvnet.hk2.internal.ClazzCreator.create(ClazzCreator.java:429)
at org.jvnet.hk2.internal.SystemDescriptor.create(SystemDescriptor.java:466)
...
To make it work, I have to add the JAX-B-API to the pom.xml and to the module-info.java.
The error only occurs when using Java modules. When I simply delete the module-info.java file, everythink works fine even without the JAX-B dependency.
This is the point where I am really confused. Why do I need the JAX-B dependency when I use the module system, but not when I don´t use it? And why does the ClassNotFoundException even occur? Shouldn´t warn the module system about missing dependencies on startup?
I hope someone can explain that. It took me days to make it work.
This is the setup that produces the issue:
pom.xml
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.source>17</maven.compiler.source>
</properties>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>11.0.13</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>11.0.13</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>3.1.0</version>
</dependency>
</dependencies>
</project>
Main.java
public class Main {
public static void main(String[] args) throws Exception {
Server server = new Server(8080);
server.setStopAtShutdown(true);
ServletContextHandler context = new ServletContextHandler(server, "/");
ServletHolder servletHolder = context.addServlet(ServletContainer.class, "/*");
servletHolder.setInitParameter("jersey.config.server.provider.packages", "com.example.demo");
servletHolder.setInitParameter("jersey.config.server.wadl.disableWadl", "true");
server.start();
}
}
DemoResource.java
#Path("/hello")
public class DemoResource {
#GET
#Produces("application/json")
public HelloDto hello() {
return new HelloDto("Hello, World!");
}
public record HelloDto(String value) {
#JsonGetter("value")
public String value() {
return this.value;
}
}
}
module-info.java
module demo {
requires org.eclipse.jetty.server;
requires org.eclipse.jetty.servlet;
requires jersey.container.servlet.core;
requires jakarta.ws.rs;
requires com.fasterxml.jackson.annotation;
}
This is the standard JVM behavior of classpath (old school Java) and modulepath (new school Java Platform Module System, aka JPMS).
Once you have a module-info.class you have a modulepath active, and all of the access rules it has.
Your runtime can have both at the same time, and this is quite normal.
Don't rely on old school classpath to get around bad code and bad behavior, use JPMS and module-info.class and you'll know what the developers of those projects jars intend for you to use (you won't be allowed to use internal classes for example, as those are highly volatile and can change at a moments notice).
jakarta.xml.bind is required by HK2 to operate, so you have to declare it in your build dependencies to just compile, and then your module-info.java to be able to access it.
Check the other answers here on Stackoverflow for advice on how to use module-info.java properly (there's far more to it than just requires <module>).

resilience4j-spring-boot-2 annotations (#Retry, #CircuitBreaker...) are completely ignored

I spent a whole day trying to find why this does not work so I think it might be useful if I share the question and the answer.
The Resilience4j library provides an elegant annotation-based solution from Spring Boot 2. All you need to do is just annotate a method (or a class) with one of the provided annotations, such as #CircuitBreaker, #Retry, #RateLimiter, #Bulkhead, #Thread and the appropriate resilience pattern is automagically added.
I added the expected dependency to the Maven pom.xml:
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot2</artifactId>
<version>${resilience4j.version}</version>
</dependency>
Now the compiler is happy, so I can add the annotations:
...
import org.springframework.stereotype.Service;
import io.github.resilience4j.retry.annotation.Retry;
...
#Service
public class MyService {
...
#Retry(name = "get-response")
public MyResponse getResponse(MyRequest request) {
...
}
}
The program compiles, runs, however the annotations are completely ignored.
According to the resilience4j-spring-boot2 documentation:
The module expects that spring-boot-starter-actuator and spring-boot-starter-aop are already provided at runtime.
So the whole trick is to add also the missing dependencies to the Maven pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

How to expose swagger UI interface with jetty server and camel

I am doing a camel project with Jetty server using Springboot, I must expose the apis swagger-ui. I have already generated the swager in json format and it can be consulted at localhost:8080/swagger. Using swagger-ui webjars I am trying to see the graphic interface of swagger but this is not generated.
Im using this maven dependencies:
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-swagger-java-starter</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>swagger-ui</artifactId>
<version>3.1.4</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>webjars-locator</artifactId>
<version>0.36</version>
</dependency>
it is suppose that when using webjars the swagger-ui can be consulted in the path /webjars/swagger-ui/index.html, but i get:
Problem accessing /webjars/swagger-ui/index.html. Reason:Not Found
I tried to define a camel route like this: but doesnt work.
rest("/swagger")
.produces("text/html")
.get("/index.html")
.responseMessage().code(200).message("Swagger UI").endResponseMessage()
.to("direct://get/swagger/ui/path");
from("direct://get/swagger/ui/path")
.routeId("SwaggerUI")
.setBody().simple("resource:classpath:META-INF/resources/webjars/swagger-ui/3.1.4/index.html");
I was using this example:
https://medium.com/#bszeti/swagger-with-spring-boot-and-camel-ac59cca9556e
but I use Jetty as rest component
restConfiguration().component("jettty").port(8080).bindingMode(RestBindingMode.json)
.skipBindingOnErrorCode(false)
How can I expose the swagger Ui Interface?
I hope someone can help me, thank you very much

can not find addListener method from javax.servlet.ServletContext

I am trying to change spring xml settings to pure code based setting.
So I read official documents and some posts from blogs.
e.g. http://docs.spring.io/spring-framework/docs/4.1.x/javadoc-api/org/springframework/web/WebApplicationInitializer.html
An I made a code like ...
public class TestInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext container)
throws ServletException {
// TODO Auto-generated method stub
System.out.println("on Startup method has called.");
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(RootConfig.class);
container.
//container.addListener(new ContextLoaderListener(ctx));
}
};
A problem here. In those pages, they use addListener(new ContextLoaderListener(ctx)) method to set context. However my eclipse can not find that method from container variable.
I do not know any clue why my container variable(javax.servlet.ServletContext instance) can not read this method.
Thanks for your answer:D
P.S.
My spring version is 4.1.6.RELEASE and I include servlet3.0, spring-context, spring-webmvc on pom.xml.
========================
Maybe I got some communication problem, So I summarize this :D
javax.servlet.ServletContext doc clearly state that it has method
addListener >>
http://docs.oracle.com/javaee/6/api/javax/servlet/ServletContext.html
have to use Spring WebApplicationInitializer.onStartup(ServletContext) to set basic setting via Java source code, not XML
Can not load addListener from ServletContext class.
=================================
Edit. This is not error on console. However it is the only message I got.
It is from eclipse toolkit.
The method addListener(ContextLoaderListener) is undefined for the type ServletContext
than recommendation is Add cast to 'container'
To follow up on what #JuneyoungOh has commented, turns out that the problem is because of conflicting dependency. And these are the ways to solve this problem :
* make version 3.0.1 and artifactId 'javax.servlet-api' or
* add tomcat(in my case 7.0) to project build path and remove servlet dependency.
In my case the problem was because of Spring-Support which is depended on "javax.servlet" and I just excluded it:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-support</artifactId>
<version>${spring-support.version}</version>
<exclusions>
<exclusion>
<artifactId>servlet-api</artifactId>
<groupId>javax.servlet</groupId>
</exclusion>
</exclusions>
</dependency>
In my case there was:
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
notice, that artifactId is servlet-api, not javax.servlet-api.
I have created a legacy MVC project, that's why I had this package. When I tried to convert .xml configuration to Java, I came across this problem.
Certainly it's not the same as in the question, but it shows up as the first result in google search.
In my case I just had to comment out the javax.servlet:servlet-api dependency as depicted here:
<!-- dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>7.0.47</version>
</dependency>
This looks like the same idea presented here: https://stackoverflow.com/a/30231246/2597758

Trouble starting Hibernate Validator due to Bean Validation API

I'm trying to use Hibernate Validator in my project, but it isn't working. On the following line:
SessionFactory sessions = config.buildSessionFactory(builder.build());
I get the following exception:
org.hibernate.cfg.beanvalidation.IntegrationException: Error activating Bean Validation integration
at org.hibernate.cfg.beanvalidation.BeanValidationIntegrator.integrate(BeanValidationIntegrator.java:154)
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:311)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1857)
at net.myProject.server.util.HibernateUtil.<clinit>(HibernateUtil.java:32)
... 36 more
Caused by: java.lang.NoSuchMethodError: javax.validation.spi.ConfigurationState.getParameterNameProvider()Ljavax/validation/ParameterNameProvider;
at org.hibernate.validator.internal.engine.ValidatorFactoryImpl.<init>(ValidatorFactoryImpl.java:119)
at org.hibernate.validator.HibernateValidator.buildValidatorFactory(HibernateValidator.java:45)
at org.hibernate.validator.internal.engine.ConfigurationImpl.buildValidatorFactory(ConfigurationImpl.java:217)
at javax.validation.Validation.buildDefaultValidatorFactory(Validation.java:111)
I found this question which seems quite similar to my problem. He describes his solution as
I had yet another bean validator jar in the class path. But not from
maven, so i didn't realize it. Removing that solved the problem.
I think my problem is the same. On http://hibernate.org/validator/documentation/getting-started/ it says:
This transitively pulls in the dependency to the Bean Validation API
(javax.validation:validation-api:1.1.0.Final)
That must be causing this issue, since reverting to an older version (4.3.1.Final) fixes the issue. Is there a way to force Hibernate to not pull in the Bean Validation API?
Edit: I've tried to exclude the javax-validation api:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.0.3.Final</version>
<exclusions>
<exclusion>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</exclusion>
</exclusions>
</dependency>
But it didn't seem to have any effect.
Try adding this dependency to your pom.xml
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.0.0.GA</version>
</dependency>
If not consider using hibernate-validator4.2.0.Final I have that one in my config and it is working fine.
For me, the 1.1.0.Final version javax.validation.validation-api had worked. Because, the javax.validation.spi.ConfigurationState interface of 1.1.0.Final has getParameterNameProvider method, which was absent in 1.0.0.GA.
I added the below dependency in pom.xml
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
<scope>test</scope>
</dependency>
I had the problem again. Thats how I've fixed that:
1-Exclude spring.validator from the 'web' dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</exclusion>
</exclusions>
</dependency>
2-After insert the dependecy with a previous version:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.1.3.Final</version>
</dependency>
in my case i just deleted the hibernate-validator and it worked .(i also had a combo of both validation api and hibernate-validator and tried everything) or you can go to your maven repository-->org and then delete the hibernate folder and rebuild your project again..
hope it helps..
I thought it would be useful to explain what is going on here.
Hibernate is calling ConfigurationState.getParameterNameProvider:
ValidatorFactoryImpl.java:
public ValidatorFactoryImpl(ConfigurationState configurationState) {
...
configurationState.getParameterNameProvider()
...
}
You can find the documentation of getParameterNameProvider:
getParameterNameProvider
ParameterNameProvider getParameterNameProvider()
Returns the parameter name provider for this configuration.
Returns:
parameter name provider instance or null if not defined
Since:
1.1
So what's the problem? The problem is that the method didn't always exist. It was added at some point in the future.
And the rule when creating interfaces is that they are set in concrete: you shall not change an interface ever. Instead the JavaX validator changed the ConfigurationState interface, and added a few new methods over the years.
The java validation code is passing the Hiberate an outdated ConfiguationState interface; one that doesn't implement the required interfaces.
You need to ensure that javax.validation.Validation.buildDefaultValidatorFactory is updated to to support version 1.1.
Removing this jar javax.validation:validation-api:1.1.0.Final solved my problem.
Make sure you have only one validation jar. If we have two jars then they may conflict resulting in error.
Go to the dependecies project and delete, hibernate.validator, and reinstall that in the most recent version. It has solved the problem for me.

Categories