I am using Jackson for JSON serialization and have written a couple custom String
serializers, one for each getter method of a class. The methods each return the same type, Set<String>
, but each uses a different serializer.
Unfortunately, Jackson is not using each serializer, one for each method, but is using one serializer for both. It appears to take whatever method comes first alphabetically and uses its serializer for both methods. What I expect is that the serializer annotated on the first method is used for the first method, and the serializer annotated on the second method is used on the second method. Debugging appears to indicate that Jackson has the serializers in a map keyed by return type of the method (which is the same for both).
An Example:
public class FooBar {
private Set<String> foos = new HashSet<String>();
private Set<String> bars = new HashSet<String>();
@JsonProperty("FooWrapper")
@JsonSerialize(contentUsing = FooSerializer.class)
public Set<String> getFoos() {
return foos;
}
@JsonProperty("BarWrapper")
@JsonSerialize(contentUsing = BarSerializer.class)
public Set<String> getBars() {
return bars;
}
}
Any suggestions on how to get the getFoos()
method to serialize with a FooSerializer
, and the getBars()
method to serialize with the BarSerializer
? In this example, the BarSerializer
is invoked for both methods.
Note, if I change the signature of one of the methods to another collection type so they are different - List<String>
for example - the serialization works.
Thanks in advance.
I think what you are trying to achieve isn't possible in version 1.9.xx when using an ObjectMapper
in combination with @JsonSerialize(contentUsing = BarSerializer.class)
.
Jackson does indeed cache the serializers, and it caches them based on the JavaType
(in this case Set<String>
) that's associated with the serializer. See StdSerializerProvider.findValueSerializer(JavaType valueType, BeanProperty property)
.
Although the BeanProperty
is passed to this method, it isn't used as part of the cache key. You could subclass StdSerializerProvider
and take the BeanProperty
parameter into account when caching value serializers, but that's probably not the easiest way to solve your problem.
As a quick fix would be to use @JsonSerialize(using = FooCollectionSerializer.class)
and deal with serializing the collection yourself. By doing this, the serializer is directly coupled to the BeanPropertyWriter
used to serialize the property. When using @JsonSerialize(contentUsing = BarSerializer.class)
there's no serializer coupled to the BeanPropertyWriter
which triggers the serializer lookup that caches the serializers based on the JavaType
public class FooBar {
private Set<String> foos = new HashSet<>();
private Set<String> bars = new HashSet<>();
@JsonProperty("FooWrapper")
@JsonSerialize(using = FooCollectionSerializer.class)
public Set<String> getFoos() {
return foos;
}
@JsonProperty("BarWrapper")
@JsonSerialize(using = BarCollectionSerializer.class)
public Set<String> getBars() {
return bars;
}
public static class FooCollectionSerializer extends JsonSerializer<Collection<String>> {
JsonSerializer<Collection<String>> serializer;
public FooCollectionSerializer() {
//let Jackson deal with serializing the collection and just specify how you want to serialize indivial items
this.serializer = new StringCollectionSerializer(null, new FooSerializer());
}
@Override
public void serialize(Collection<String> value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
serializer.serialize(value, jgen, provider);
}
}
public static class FooSerializer extends SerializerBase<String> {
public FooSerializer() {
super(String.class);
}
@Override
public void serialize(String value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
jgen.writeString(value);
}
}
public static class BarCollectionSerializer extends JsonSerializer<Collection<String>> {
@Override
public void serialize(Collection<String> values, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
//handle serializing the collection yourself
jgen.writeStartArray();
for (String value : values) {
jgen.writeString(value);
}
jgen.writeEndArray();
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With