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);
Related
I need to use two jackson 2 object mappers.
Both mappers work with the same set of classes.
In the first I need to use standard serialization.
In the second i want to use ARRAY shape type for all classes (see https://fasterxml.github.io/jackson-annotations/javadoc/2.2.0/com/fasterxml/jackson/annotation/JsonFormat.Shape.html#ARRAY).
But i want to global set this feature for my second ObjectMapper. Something like mapper.setShape(...)
How to do it?
UPD:
I found a way to override the config for the class:
mapper.configOverride(MyClass.class)
.setFormat(JsonFormat.Value.forShape(JsonFormat.Shape.ARRAY));
So I can change for all my classes using Reflection API.
It is embarrassing that I override the global setting, but I can not directly set it.
As #JsonFormat annotation works on field, you can't set it to Shape.Array at global level. This would mean all the fields would be serialized and deserialised into array values (imagine if a field is already a list, in this case, it will be wrapped into another list which is something we might not want).
You can however, write your own serializer for a type (that converts a value into an array) and configure it in ObjectMapper, e.g.:
class CustomDeserializer extends JsonSerializer<String>{
#Override
public void serialize(String value, JsonGenerator gen, SerializerProvider serializers)
throws IOException, JsonProcessingException {
gen.writeStartArray();
gen.writeString(value);
gen.writeEndArray();
}
}
And configure it to ObjectMaper instance, e.g.:
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(String.class, new CustomDeserializer());
mapper.registerModule(module);
I have inherited some legacy code that uses Jackson 1.9.2 and am wanting to upgrade it to Jackson 2.x. One point of contention is the following:
class CustomObjectMapper extends ObjectMapper {
CustomObjectMapper(KeySerializer keySerializer) {
// StdSerializerProvider doesn't exist in Jackson 2.x
final StdSerializerProvider sp = new StdSerializerProvider();
sp.setNullValueSerializer(new NullSerializer());
sp.setDefaultKeySerializer(keySerializer);
setSerializerProvider(sp);
}
}
The trouble I am having is that StdSerializerProvider exists in Jackson 1.9.x, but not in Jackson 2.x. Is there an equivalent class for this that will preserve the existing behavior? Or is a replacement necessary at all?
The DefaultSerializerProvider must be what you're looking for. Note that they both this and the StdSerializerProvider of Jackson 1.x are subclasses of SerializerProvider. They also have very similar methods.
Note that StdSerializerProvider is a concrete class while DefaultSerializerProvider is abstract. However, you can create a new DefaultSerializerProvider.Impl to create a concrete class.
I'm trying to code domain objects that can create themselves from other objects which implement the same interface. I'm also coding it so they can transform themselves into other implementations, basically simple domain transfer objects. I'm using jackson to automatically convert between implementations to reduce error prone boiler plate of manual object conversion.
It's probably easier to show with an example:
//base class
public abstract class DO<T extends Object> {
public abstract T toDTO();
public abstract DO<T> fromDTO(T t);
}
//concrete implementation
public class MyDO extends DO<MyDOInterface> implements MyDOInterface {
public MyDO fromDTO(MyDTO r){
ObjectMapper mapper = new ObjectMapper();
return mapper.convertValue(r, MyDO.class);
}
public MyDTO toDTO() {
ObjectMapper mapper = new ObjectMapper();
return mapper.convertValue(this, MyDO.class);
}
//getters and setters from MyDOInterface
}
Now this works fine when creating DTOs, but is a bit of a pain the other way around. To create my domain objects I'm having to do this:
MyDO myDO = new MyDO().fromDTO(aDTOInstance);
Which creates an empty object in order to call fromDTO(...) on it.
I've got a feeling I'm missing something simple that would either allow me to pass the DTO in a constructor or a static method to avoid this. Or even a factory method in DO itself but I can't work out what it is. Can anyone see a way of making this work?
Maybe have a look at #JsonCreator annotation: it allows you to mark constructors and (static) factory methods to be used. Specifically, so-called "delegating" creator like:
Another possibility when serializing would be #JsonValue, which allows certain conversions during serialization process.
I don't know if these help with specific problem, since you are doing more conversion than reading/writing JSON, but they seem related.
I want to use method canDeserialize, because at moment deserialization i want to get type class for apply at custom deserialization, as about next example :
public T deserialize(byte[] bytes) throws SerializationException {
bolean isAccount = this.objectMapper.canDeserialize(??????).
T t = null;
if(isAccount)
t = (T)this.objectMapper.readValue(bytes,Account.class);
else
t = (T) this.objectMapper.readValue(bytes, 0, bytes.length, new TypeReference<Object>(){});
return t;
}
In this case Account class have annotation #JsonDeserialize for a custom deserialization .
To directly answer your question, this is how you use the canDeserialize method:
final ObjectMapper mapper = new ObjectMapper();
mapper.canDeserialize(mapper.constructType(Bean.class));
Where Bean is the name of your Java class to be checked.
But wait, you are trying to solve the wrong problem. You are struggling with the logic for your method because it has not been designed properly. You are really asking too much of the Java runtime (and Jackson library), by trying to make them infer all the required information about the type to be instantiated (based on the parameterized return). To solve this you should include the class representing the type to be deserialized as a parameter to the method, greatly simplifying the logic:
public <T> T deserialize(byte[] bytes, Class<T> clazz) throws IOException,
JsonProcessingException {
return new ObjectMapper().readValue(bytes, clazz);
}
At this point you have probably realized that the method above provides no additional functionality over just calling ObjectMapper.readValue directly, so ... just do that! No need to define custom methods, just use ObjectMapper and you are good to go. Keep in mind that you do not need to do anything explicit to trigger custom deserialization of classes. The Jackson runtime automatically detects when a class has a custom deserializer and invokes it.
I want to convert a JSON string into java object, but the class of this object contains abstract fields, which Jackson can't instantiate, and doesn't produce the object. What is the easiest way to tell it about some default implementation of an abstract class, like
setDefault(AbstractAnimal.class, Cat.class);
or to decide about the implementation class based on JSON attribute name, eg. for JSON object:
{
...
cat: {...}
...
}
i would just wite:
setImpl("cat", Cat.class);
I know it's possible in Jackson to embed class information inside JSON, but I don't want to complicate the JSON format I use. I want to decide what class to use just by setting default implementation class, or by the attribute name ('cat') - like in XStream library, where you write:
xStream.alias("cat", Cat.class);
Is there a way to do so, especially in one line, or does it require some more code?
There are multiple ways; before version 1.8, simplest way is probably to do:
#JsonDeserialize(as=Cat.class)
public abstract class AbstractAnimal { ... }
as to deciding based on attribute, that is best done using #JsonTypeInfo, which does automatic embeddeding (when writing) and use of type information.
There are multiple kinds of type info (class name, logical type name), as well as inclusion mechanisms (as-included-property, as-wrapper-array, as-wrapper-object). This page: https://github.com/FasterXML/jackson-docs/wiki/JacksonPolymorphicDeserialization explains some of the concepts.
A full fledged answer with a very clear example can be found here: https://stackoverflow.com/a/30386694/584947
Jackson refers to this as Polymorphic Deserialization.
It definitely helped me with my issue. I had an abstract class that I was saving in a database and needed to unmarshal it to a concrete instance of a class (understandably).
It will show you how to properly annotate the parent abstract class and how to teach jackson how to pick among the available sub-class candidates at run-time when unmarshaling.
If you want to pollute neither your JSON with extra fields nor your classes with annotation, you can write a very simple module and deserializer that uses the default subclass you want. It is more than one line due to some boilerplate code, but it is still relatively simple.
class AnimalDeserializer extends StdDeserializer<Animal> {
public AnimalDeserializer() {
super(Animal.class);
}
public Animal deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException {
return jsonParser.readValueAs(Cat.class);
}
}
class AnimalModule extends SimpleModule {
{
addDeserializer(Animal.class, new AnimalDeserializer());
}
}
Then register this module for the ObjectMapper and that's it (Zoo is the container class that has an Animal field).
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new AnimalModule());
return objectMapper.readValue(json, Zoo.class);
The problem can be solved with the annotation #JsonDeserialize on the abstract class.
Refers to Jackson Exceptions Problems and Solutions for more info