I need to serialize my POJO object that relies on JAXB annotations. I can easily do this with Jackson (adding JaxbAnnotationIntrospector). Is possible without any explicit coding?
It would be really nice to write it fluently akin to this:
port(Integer.valueOf(port)).
log().all().
contentType(ContentType.JSON).
body(criteria, ObjectMapperType.JACKSON_2)
Yet this one ignores JAXB. I want to find some neat and clean solution. Jackson + JAXB is very common practice, it will be such a shame if RestAssured is not equipped with it under the hood. I found something like this on the forum:
RestAssured.config = RestAssuredConfig.config().objectMapperConfig(new ObjectMapperConfig().jackson2ObjectMapperFactory(
new Jackson2ObjectMapperFactory() {
#Override
public ObjectMapper create(Class aClass, String s) {
FilterProvider filter = new SimpleFilterProvider().addFilter(...);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setFilters(filter);
return objectMapper;
}
}
));
but this will be my last resort.
If this is a common use case please add it as an issue and I'll try to integrate it as default.
Related
I'm using Jackson 2.7.5 with Jersey 2.25.1. I'm trying to fix existing production code that is now failing with "UnrecognizedPropertyException: Unrecognized field" when it gets an unexpected field in the JSON input.
In researching this, I found several old posts (5+ years) suggesting various fixes that were very different from my current code. I didn't pay much attention to these, because they were for old versions of Jackson/Jersey. And more recent suggestions, including Jersey's own documentation (https://jersey.github.io/documentation/latest/media.html#json.jackson), look very similar to what I already have in place. In fact, to my eyes, it looks like my existing code is already following the current practice. However, Jersey seems to be ignoring my custom ObjectMapper setting of...
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false
I'm pretty sure that setting should fix the error, but Jersey seems to be using a default ObjectMapper instead of my custom settings.
First, here is the dependency information, which I believe matches what is shown in the Jersey documentation (https://jersey.github.io/documentation/latest/media.html#json.jackson).
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>${jersey.version}</version>
</dependency>
Here is the call that is returning the error:
// this will throw an exception if it can't convert the string to the class
PropSearchResponse propResponse = null;
try {
propResponse = getResponse.readEntity(PropSearchResponse.class);
} catch(final ProcessingException e) {
throw new ProcessResultException(Code.FAILED, "failed to map from prop response", e);
}
Here is the original code for my custom ObjectMapper:
#Provider()
#Produces(value = MediaType.APPLICATION_JSON)
public class OutMapperProvider implements ContextResolver<ObjectMapper> {
private final ObjectMapper mapper;
public OutMapperProvider() {
mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.configure(JsonGenerator.Feature.ESCAPE_NON_ASCII, true);
mapper.setSerializationInclusion(Include.NON_NULL);
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"));
}
#Override()
public ObjectMapper getContext(final Class<?> type) {
return mapper;
}
}
Here is the example from the Jersey documentation:
#Provider
public class MyObjectMapperProvider implements ContextResolver<ObjectMapper> {
final ObjectMapper defaultObjectMapper;
public MyObjectMapperProvider() {
defaultObjectMapper = createDefaultMapper();
}
#Override
public ObjectMapper getContext(Class<?> type) {
return defaultObjectMapper;
}
private static ObjectMapper createDefaultMapper() {
final ObjectMapper result = new ObjectMapper();
result.configure(Feature.INDENT_OUTPUT, true);
return result;
}
}
I have tried the Jersey example (changing the names to match mine, of course) as well as several other examples I found online. The Jersey example does the customization after the #Override. Most other examples do it before the #Override, but they all seem substantially similar to each other and to my existing code. But it doesn't seem to make any difference. No matter what I have tried, the custom configuration is ignored and Jersey calls a default ObjectMapper, which fails on unexpected JSON fields.
Disclaimer: This is my first experience with both Jersey and Jackson. I don't have a good understanding of the underlying mechanism yet. I'm just trying to follow the patterns of the examples.
Update: I believe the code above is basically correct. But Paul's comment below says that I need to register the custom ObjectMapper. I have tried reproducing several examples I have found on the web (Example 4.2 at https://docs.huihoo.com/jersey/2.13/deployment.html#environmenmt.appmodel, for example), but without success. For my current attempt, I have tried adding a new MyApplication class to an existing config package (com.dmx.repl.config) using Jersey's ResourceConfig. The code is below. But still, it is not working.
Edit: Ignore this code, it didn't work. See solution below.
package com.dmx.repl.config;
import org.glassfish.jersey.server.ResourceConfig;
import com.dmx.repl.commons.OutMapperProvider;
/**
*
* #author Greg
* #version 1.0
*/
// Attempt to register custom ObjectMapper
public class MyApplication extends ResourceConfig {
public MyApplication() {
// I've tried both of these.
//register(OutMapperProvider.class);
packages("com.dmx.repl.commons");
}
}
It's working now. Jersey is now recognizing the custom ObjectMapper, which is configured to ignore unknown JSON fields with "FAIL_ON_UNKNOWN_PROPERTIES, false".
The ObjectMapper code above is correct. The problem (as suggested by Paul in the comments) was that the client had not registered the custom ObjectMapper. This was fixed very simply, by adding the following line to the client setup method, following client setup with ClientBuilder.
this.client.register(OutMapperProvider.class);
In my project i used a lot com.fasterxml.jackson.databind.ObjectMapper to deal with JSON, for example:
ObjectMapper mapper = new ObjectMapper();
A a = mapper.readValue(file.getBytes(), A.class);
At first sight I think it's better it's better to make the readValue method static, then we can use it as ObjectMapper.readValue(), much more clear. But I know there must be some reasons that it shouldn't, does anyone know it?
Other reason is with each instance of ObjectMapper you bind certain specific confuguration ready by ObjectMapper while serialization and desrialization process somethinglike below.
So you can configure different startegies while object conversion process.
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
String json = mapper.writeValueAsString(new MyBean());
Heres a question for Jackson 2.3 I don't have the possibility to change to other frameworks.
I want to serialize objects to json using Jackson 2.3.
Some of the Objects are from a third party library implementing a particular (external) interface.
What I want to achieve is to prevent certain fields in those objects to be serialized.
I do not have access to modifying this class so #JsonIgnore wont cut it.
Heres an example
public interface ThirdParty{
public char[] getPassword();
public String getUser();
public Department getDepartment();
}
I'm new to Jackson, but have a feeling that it should be fairly simple to do something like this
ObjectMapper mapper=new ObjectMapper();
SimpleModule testModule = new SimpleModule("DemoModule",VersionUtil.versionFor(this.getClass()));
testModule.addSerializer(ThirdParty.class, new Some_Serializer_That_Can_Ignore_Password()));
mapper.registerModule(testModule);
(I don't think there is something called a Some_Serializer_That_Can_Ignore_Password, what I want is something that does NOT serialize the field)
I would prefer not to write a lot of code to make it work, I've seen quite verbose examples for older versions of Jackson, but none for Jackson 2.3.
Thanks!
Not really an answer for the original question, but I found a way that worked for excluding particular types, this code ensures that any StackTraceElements are not serialized.
SimpleModule testModule = new SimpleModule("DemoModule", VersionUtil.versionFor(this.getClass()));
testModule.addSerializer(StackTraceElement.class,new JsonSerializer<StackTraceElement>() {
#Override
public void serialize(StackTraceElement value, JsonGenerator jgen, SerializerProvider provider){/*Do not serialize*/}
});
mapper.registerModule(testModule);
Needed to have support for Scala Lists and Options when storing to Riak. Looks like the Scala Module for Jackson would work for this. However, how would it be hooked into the object mapper in Riak? Not sure if I need to override something or if there's an annotation that can easily solve it.
https://github.com/FasterXML/jackson-module-scala
A few releases ago I added a getObjectMapper() method to the JSONConverter as someone had requested it. This is the Converter that is used for fetch/store operations if you're passing in POJOs and haven't created and passed in your own.
You'd want to instantiate the JSONConverter yourself and get the ObjectMapper from it:
JsonConverter<MyClass> converter = new JSONConverter<MyClass>(MyClass.class, bucketName);
ObjectMapper om = converter.getObjectMapper();
You can now register the module with the ObjectMapper and then use the JSONConverter with your fetch/store operations (using the withConverter() method of the StoreObject and FetchObject).
I think that's what you're looking for. If you needed more control over serializing/deserializing your objects you could also write your own Converter- I've written a cookbook entry on the subject here: https://github.com/basho/riak-java-client/wiki/Using-a-custom-Converter
Typefactory class at jackson has many deprecated methods inside it. I am using it like that:
public List<T> getX(Class<T> clz) {
ObjectMapper mapper = new ObjectMapper();
try {
String jsonData = mapper.writeValueAsString(data);
a = mapper.readValue(jsonData, TypeFactory.collectionType(List.class, clz));
} catch (Exception e) {
System.out.println(e.getMessage());
}
return a;// a is a global variable
}
and it warns me that collectionType is deprecated. What to use instead of it?
TypeFactory itself is NOT deprecated, just static methods; instance methods like "constructType" are available. So question is rather where do you get a TypeFactory instance to use.
Most often you get an instance from ObjectMapper using its getTypeFactory method; or from SerializationConfig / DeserializationConfig. They carry an instance around.
If none of these works, there is TypeFactory.instance as well that you can use.
The reason for deprecation is that some extension modules will want to replace the standard factory: specifically, Scala module needs to extend type handling with Scala Collection (etc) types -- these will not work by default, since Scala does not extend java.util versions.