How to configure Jackson in Wildfly? - java

I've got a Session Bean with the following method:
#POST
#Consumes("application/x-www-form-urlencoded")
#Path("/calculate")
#Produces("application/json")
public CalculationResult calculate(#FormParam("childProfile") String childProfile,
#FormParam("parentProfile") String parentProfile) {
...
}
The returned CalculationResult cannot be mapped to JSON and the following exception occurs:
Caused by: com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class com.test.UniqueName and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)...
How can I configure Jackson and its SerializationFeature in Wildfly?

"How can I configure Jackson and its SerializationFeature in Wildfly?"
You don't need to configure it in Wildfly, you can configure it in the JAX-RS applciation. Just use a ContextResolver to configure the ObjectMapper (see more here). Something like
#Provider
public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {
private final ObjectMapper mapper;
public ObjectMapperContextResolver() {
mapper = new ObjectMapper();
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
}
#Override
public ObjectMapper getContext(Class<?> type) {
return mapper;
}
}
If you don't already have the Jackson dependency, you need that, just as a compile-time dependency
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson-provider</artifactId>
<version>3.0.8.Final</version>
<scope>provided</scope>
</dependency>
If you are using scanning to discover your resource classes and provider classes, the ContextResolver should be discovered automatically. If you explicitly registering all your resource and providers, then you'll need to register this one also. It should be registered as a singleton.
UPDATE
As #KozProv mentions in a comment, it should actually be resteasy-jackson2-provider as the artifactId for the Maven dependency. -jackson- uses the older org.codehaus (Jackson 1.x), while the -jackson2- uses the new com.fasterxml (Jackson 2.x). Wildfly by default uses The Jackson 2 version.

Wildfly 9
pom.xml
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson2-provider</artifactId>
<version>3.0.8.Final</version>
<scope>provided</scope>
</dependency>
Java class
#com.fasterxml.jackson.annotation.JsonIgnoreProperties(ignoreUnknown = true)
public class SomePojo implements Serializable {
}

Related

Springfox-boot-starter swagger Instant handling

I have a problem with swagger documentation using SpringBoot with Springfox-boot-starter.
I use java.time.Instant wrapped in java.util.Optional in my REST API which works fine:
#GetMapping("/{subscriptionId}/{variableAlias}")
public PaginatedResultDTO<MonitoredVariableDTO> getReportedVariables(
#PathVariable String subscriptionId,
#PathVariable String variableAlias,
Optional<Instant> from,
Optional<Instant> to) { ... }
But for some reason, Swagger documentation cannot handle the Optional type correctly and seems to handle it through reflection as EpochSeconds and Nano attributes instead of one field:
I would like to make swagger expect from and to instants in ISO format, just like Spring does and how I use it in Insomnia:
When I tried to remove the Optional wrapper, it seems to work
Is there a way to make this work with the Optional? Thanks for any advice!
Spring boot version:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
<relativePath />
</parent>
Springfox-boot-starter version
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
We had exactly the same problem that you.
We solved it with this SpringFox configuration:
#Configuration
#EnableSwagger2
public class SpringfoxConfiguration {
#Value("${api-doc.version}")
private String apiInfoVersion;
#Autowired
private TypeResolver typeResolver;
#Bean
public Docket customDocket(){
return new Docket(DocumentationType.SWAGGER_2)
.groupName("xxx")
//Some other code unrelated to this problem
.alternateTypeRules(
// Rule to correctly process Optional<Instant> variables
// and generate "type: string, format: date-time", as for Instant variables,
// instead of "$ref" : "#/definitions/Instant"
AlternateTypeRules.newRule(
typeResolver.resolve(Optional.class, Instant.class),
typeResolver.resolve(Date.class),
Ordered.HIGHEST_PRECEDENCE
))
.genericModelSubstitutes(Optional.class)
.select()
//Some more code unrelated to this problem
.build();
}
}
With spring fox the problem is it doesn't use the custom ObjectMapper which you have defined as a Bean.
Springfox creates own ObjectMapper using new keyword. Hence, any module you register with your custom ObjectMapper is pointless for SpringFox. However, Springfox provides an interface to register modules with it's own ObjectMapper.
Create a configuration bean like below in your project and it should work.
#Configuration
public class ObjectMapperModuleRegistrar implements JacksonModuleRegistrar {
#Override
public void maybeRegisterModule(ObjectMapper objectMapper) {
objectMapper.registerModule(new ParameterNamesModule())
.registerModule(new Jdk8Module())
.registerModule(new JavaTimeModule())
.findAndRegisterModules();
}
}

Is there any option to register Serializer/Deserializer only once for java.time.* packages using Jackson in Spring Boot?

Hello Team,
I am working on a Spring Boot Project (Version 2.3.4 Release) in which I am using java.time.LocalDate, java.time.LocalDateTime and java.time.LocalTime datatypes for some of the properties in several beans.
However, these fields are not getting deserialized automatically unless I am explicitly providing following annotations to them along with my custom deserializer.
#JsonFormat(pattern="dd-MMM-yyyy")
#JsonDeserialize(using= LocalDateWithStringsDeserializer.class)
private LocalDate date_of_joining;
It is really a time consuming job to add these annotations to all the beans as there are more than 400-500 beans in this project.
If these annotations were not provided, I get below error.
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `java.time.LocalDate` (no Creators, like default construct, exist): no String-argument constructor/factory method to deserialize from String value ('27-May-1999')
I have also tried defining a explicit Bean for overriding Spring Boot objectmapper with my custom deserializers but that even didn't helped me. The code snippet of the same is mentioned below.
#Bean
#Primary
public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
ObjectMapper objectMapper = builder.build();
objectMapper.findAndRegisterModules();
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.setDateFormat(dateformat);
SimpleModule module = new SimpleModule();
module.addDeserializer(LocalDateTime.class, new MillisOrLocalDateTimeDeserializer());
module.addDeserializer(LocalDate.class, new LocalDateWithStringsDeserializer());
module.addDeserializer(LocalTime.class, new LocalTimeWithStringDeserializer());
objectMapper.registerModule(module);
return objectMapper;
}
I have even added following dependencies to pom.xml file in my project.
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-parameter-names</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</dependency>
Please suggest a solution.
So I figured out the solution. There were some other object mappers previously configured which were using Joda Time in a project which was added to the build path of my project as a required library.
Modifying the existing object mappers and registering Java Time module and custom deserializers for Date & Time with them in that project like I have mentioned in this question resolved this issue.

java.lang.IllegalArgumentException: No converter found for return value of type

With this code
#RequestMapping(value = "/bar/foo", method = RequestMethod.GET)
public ResponseEntity<foo> foo() {
Foo model;
...
return ResponseEntity.ok(model);
}
}
I get the following exception
java.lang.IllegalArgumentException: No converter found for return value of type
My guess is that the object cannot be converted to JSON because Jackson is missing. I don't understand why because I thought that Jackson was built in with spring boot.
Then I have tried to add Jackson to the pom.xml but I still have the same error
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.4.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.4.3</version>
</dependency>
Do I have to change any spring boot properties to make this work?
The problem was that one of the nested objects in Foo didn't have any getter/setter
Add the below dependency to your pom.xml:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.0.pr3</version>
</dependency>
Add the getter/setter missing inside the bean mentioned in the error message.
Use #ResponseBody and getter/setter. Hope it will solve your issue.
#RequestMapping(value = "/bar/foo", method = RequestMethod.GET)
#ResponseBody
public ResponseEntity<foo> foo() {
and update your mvc-dispatcher-servlet.xml:
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
The answer written by #Marc is also valid. But the concrete answer is the Getter method is required. You don't even need a Setter.
The issue occurred in my case because spring framework couldn't fetch the properties of nested objects. Getters/Setters is one way of solving. Making the properties public is another quick and dirty solution to validate if this is indeed the problem.
#EnableWebMvc annotation on config class resolved my problem. (Spring 5, no web.xml, initialized by AbstractAnnotationConfigDispatcherServletInitializer)
I had the very same problem, and unfortunately it could not be solved by adding getter methods, or adding jackson dependencies.
I then looked at Official Spring Guide, and followed their example as given here - https://spring.io/guides/gs/actuator-service/ - where the example also shows the conversion of returned object to JSON format.
I then again made my own project, with the difference that this time I also added the dependencies and build plugins that's present in the pom.xml file of the Official Spring Guide example I mentioned above.
The modified dependencies and build part of XML file looks like this!
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
You can see the same in the mentioned link above.
And magically, atleast for me, it works. So, if you have already exhausted your other options, you might want to try this out, as was the case with me.
Just a side note, it didn't work for me when I added the dependencies in my previous project and did Maven install and update project stuff. So, I had to again make my project from scratch. I didn't bother much about it as mine is an example project, but you might want to look for that too!
I was getting the same error for a while.I had verify getter methods were available for all properties.Still was getting the same error.
To resolve an issue Configure MVC xml(configuration) with
<mvc:annotation-driven/>
.This is required for Spring to detect the presence of jackson and setup the corresponding converters.
While using Spring Boot 2.2 I run into a similiar error message and while googling my error message
No converter for [class java.util.ArrayList] with preset Content-Type 'null'
this question here is on top, but all answers here did not work for me, so I think it's a good idea to add the answer I found myself:
I had to add the following dependencies to the pom.xml:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
</dependency>
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.11.1</version>
</dependency>
After this I need to add the following to the WebApplication class:
#SpringBootApplication
public class WebApplication
{
// ...
#Bean
public HttpMessageConverter<Object> createXmlHttpMessageConverter()
{
final MarshallingHttpMessageConverter xmlConverter = new MarshallingHttpMessageConverter();
final XStreamMarshaller xstreamMarshaller = new XStreamMarshaller();
xstreamMarshaller.setAutodetectAnnotations(true);
xmlConverter.setMarshaller(xstreamMarshaller);
xmlConverter.setUnmarshaller(xstreamMarshaller);
return xmlConverter;
}
}
Last but not least within my #Controller I used:
#GetMapping(produces = {MediaType.APPLICATION_XML_VALUE, MediaType. APPLICATION_JSON_VALUE})
#ResponseBody
public List<MeterTypeEntity> listXmlJson(final Model model)
{
return this.service.list();
}
So now I got JSON and XML return values depending on the requests Accept header.
To make the XML output more readable (remove the complete package name from tag names) you could also add #XStreamAlias the following to your entity class:
#Table("ExampleTypes")
#XStreamAlias("ExampleType")
public class ExampleTypeEntity
{
// ...
}
Hopefully this will help others with the same problem.
In my case i'm using spring boot , and i have encountered a similar error :
No converter for [class java.util.ArrayList] with preset Content-Type 'null'
turns out that i have a controller with
#GetMapping(produces = { "application/xml", "application/json" })
and shamefully i wasn't adding the Accept header to my requests
you didn't have any getter/setter methods.
In my case, I was returning Boolean in Response Entity
and had :
produces = MediaType.TEXT_PLAIN_VALUE,
When i changed it to below
produces = MediaType.APPLICATION_JSON_VALUE
It worked!
Example of what i had.
#PostMapping(value = "/xxx-xxxx",
produces = MediaType.APPLICATION_JSON_VALUE,
consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Boolean> yyyy(
I was facing same issue for long time then comes to know have to convert object into JSON using Object Mapper and pass it as JSON Object
#RequestMapping(value = "/getTags", method = RequestMethod.GET)
public #ResponseBody String getTags(#RequestParam String tagName) throws
JsonGenerationException, JsonMappingException, IOException {
List<Tag> result = new ArrayList<Tag>();
for (Tag tag : data) {
if (tag.getTagName().contains(tagName)) {
result.add(tag);
}
}
ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writeValueAsString(result);
return json;
}
I also experienced such error when by accident put two #JsonProperty("some_value") identical lines on different properties inside the class
In my case, I forgot to add library jackson-core.jar, I only added jackson-annotations.jar and jackson-databind.jar. When I added jackson-core.jar, it fixed the problem.
I saw the same error when the scope of the jackson-databind dependency had been set to test:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.9</version>
<scope>test</scope>
</dependency>
Removing the <scope> line fixed the issue.
Faced same error recently - the pojo had getters/setters and all jackson dependencies were imported in pom correctly but some how "< scope > " was "provided" for jackson dependency and this caused the issue. Removing " < Scope > " from jackson dependency fixed the issue
I faced the same problem but I was using Lombok and my UploadFileResponse pojo was a builder.
public ResponseEntity<UploadFileResponse>
To solve I added #Getter annotation:
#Builder
#NoArgsConstructor
#AllArgsConstructor
#Getter
public class UploadFileResponse
Add below dependency in pom.xml:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.10.1</version>
</dependency>
Was facing the same issue as the return type cannot be bind with the MediaType of Class Foo. After adding the dependency it worked.
This might also happen due low Jackson version; e.g. Spring Boot 2.4 default Jackson version is too low when using Java records; you need at least 2.5 to serialize them properly.
I also encountered the same error on a Spring 5 project (not Spring Boot), by running a SpringMVC JUnit test-case on a method that returns ResponseEntity<List<MyPojo>>
Error: No converter found for return value of type: class java.util.ArrayList
I thought I had all the correct Jackson artifacts in my pom, but later realized that I had the legacy versions. The Maven groupId changed on the Jackson jars from org.codehaus.jacksonto com.fasterxml.jackson.core. After switching to the new jars the error went away.
Updated maven pom.xml:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.7</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.7</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.7</version>
</dependency>
You are missing an Annotation #ResponseBody

How to call a Spring managed object from a POJO?

I am running a web-app, which has one exposed class ( available to other POJO classes) and that has one autowired private member.
Spring managed class
public class EPSQueueSender {
#Autowired
private AmqpTemplate epsMessageTemplate;
public void dosomething(...){
epsMessageTemplate.convertAndSend(...); // Here epsMessageTemplate is null if instance of EPSQueueSender taken from other POJO
}
}
POJO class
public class Test{
EPSQueueSender sender = new EPSQueueSender();
sender.dosomething(....); // gives null exception on epsMessageTemplate
}
Spring code ( running as WebApp) and POJO class code( different Jar) are on same JVM. The POJO is not able to get initialized autowired object. However it is initialized if I use it in webApp project.
Can someone please give some suggestion how can I overcome this problem?
Last thing I would like to try is to hit webserver as http request from POJO.
beans can be pojo or xml many examples might help. You already have #autowired but you did not create the #bean method itself that belongs in a class annotated with #Configuration
Your problem could be overcome using #Configurable feature of spring. For it you have configure in xml with a code like belove
<context:annotation-config/>
<context:spring-configured/>
<context:load-time-weaver/>
in Java Congiguration like below:
#Configuration
#EnableAspectJAutoProxy
#EnableSpringConfigured
#EnableLoadTimeWeaving
public class ConfigApplicationContext {
}
with this configuration you can benefit of the load-waving aspect technique that througth the build-in Spring bean AnnotationBeanConfigureAspect you can inject Spring bean in a pojo that is annotated with #Configurable. you colud be have a code like below:
#Configurable
public class Test{
#Autowired
private EPSQueueSender sender;
public void method(){
sender.dosomething(....); // gives null exception on epsMessageTemplate
}
}
of course, since that you are using a load-wave technique you have configure an agent that will perform the istruments. the configuration is very simple and you have add a line like below in the start of the jvm or tomcat:
java -javaagent:path of the jar with the agent/spring-instrument.jar
remember of course of insert the aop and spring aop maven dependency:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>yourVersion</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>4
<version>yourVersion</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-instrument</artifactId>
<version>yourVersion</version>
</dependency>
I hope that this can help you

What is the proper way to validate requests with Resteasy?

I use Resteasy in combination with Google Guice using Resteasy-Guice. I have been looking for ways to validate my request bodies. I want to do for example:
public static class MyPojo {
#NotEmpty private String contents;
}
And then use in my resource
#POST
#ValidateRequest
public void doPost(#Valid MyPojo myPojo) {
// use myPojo only if valid
}
I have been working with the resteasy-hibernate-validator-provider. But since I switched to newer versions, this introduced the (unwanted?) dependency to EJB. See also: RESTEASY-1056. In the comments is stated that you should switch to the newer validator-11 instead:
Switch to resteasy-validator-provider-11, which implements the newer Bean Validation 1.1 specification.
The docs say:
Validation is turned on by default (assuming resteasy-validator-provider-11-.jar is available), though parameter and return value validation can be turned off or modified in the validation.xml configuration file. See the Hibernate Validator documentation for the details.
I however do not manage to get this working to my configuration, because I find myself including dependencies like hibernate-validator, javax.el-api, javax.el and hibernate-validator-cdi and annotations like ValidateOnExecution. I however do not find any of this being instantiated or invalid requests being rejected.
What is the preferred, lightweight, and working way to do validation with Resteasy?
You do not have to specify any annotation on the resource itself or do additional configuration. Just the constraint annotations on POJOs are enough get it working.
My setup is as follows:
The resource method:
#POST
public void doPost(#Valid MyPojo myPojo) {
// use myPojo only if valid
}
The POJO:
public static class MyPojo {
#NotEmpty private String contents;
}
Tested with the following dependencies:
javax.validation version 1.1.0.Final
resteasy-validator-provider-11 version 3.0.11.Final
hibernate-validator version 5.0.0.Final and 5.0.1.Final
I accidentally had a transitive dependency to the hibernate-validator-provider which caused previous tries to fail. Ensure that you do not have a transitive dependency to the hibernate-validator-provider. For me this caused the following exception: issues.jboss.org/browse/RESTEASY-826 .
Based on Thomas answer I added dependencies to javax.validation, resteasy-validator-provider-11, hibernate-validator.
Then I still received exceptions (java.lang.NoClassDefFoundError: javax/el/PropertyNotFoundException). Based on this answer I added javax.el-api and el-impl as dependencies. I think this is because I use an embedded servlet container.
I had to remove the #ValidateOnRequest annotation on the resources, they are not necessary anymore
Final working configuration:
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-validator-provider-11</artifactId>
<version>3.0.11.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.0.1.Final</version>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>el-impl</artifactId>
<version>2.2</version>
</dependency>

Categories