On Tuesday, April 16, 2019 at 5:05:14 PM UTC-4, Tatu Saloranta wrote:
>
> On Tue, Apr 16, 2019 at 1:05 PM Chris C <[email protected] <javascript:>>
> wrote:
>
>> I have a map of type
>>
>> Map<Key1, Map<Key2, Integer>>
>>
>> that I want to serialize to json to store in as a field in a database
>> record.
>>
>> Key1 and Key2 are my own classes with getters defined and the
>> constructors annotated as JsonCreators.
>>
>> I have been able to process single level maps for the same purpose by
>> configuring the type factory for the object mapper, but I am unsure how to
>> go about it for nested maps with different keys.
>>
>
> There are 2 challenges:
>
> 1. Expressing `JavaType` to use for deserialization (serialization is
> usually fine, although if you try to serialize Map as root value [Strongly
> Discouraged practice!], then there too)
>
Can you explain what you mean please?
2. Allowing custom Map key types -- may need to register Key deserializers,
> key serializers (common types like `String`, `Number` supported out of the
> box)
> - note: Map keys must be scalar types; read from String, written as
> Strings
>
> First one is done using `TypeFactory`, either with TypeReference:
>
> JavaType mapRef = typeFactory.constructType(new TypeReference<Map<Key1,
> Map<Key2, Integer>>>) {} ())
>
> Or constructing it in two parts, something like
>
> JavaType mapRef = typeFactory.constructMapType(Map.class,
> typeFactory.constructType(Key1.class),
> typeFactory.constructMapType(Map.class,
> typeFactory.constructType(Key2.class),
> typeFactory.constructType(Integer.class)));
>
> Second part may be more involved, but if you have already handled
> non-nested maps with custom types, you probably know how that works.
>
>
I didn't even think to chain the type factory calls here. Before I tackle
the deserialization I ran into serialization.
Expanding on the structure I have the following (was using
https://www.baeldung.com/jackson-map as a starting point)
public class Basket {
// other fields
// this is what I am trying to de/serialize separately
private Map<Seller,Map<BasketItem,Integer>> contents;
// other stuff removed
@JsonSerialize(using = Seller.Serializer.class)
public static final class Seller {
private final Long id;
private final String name;
@JsonCreator
Seller(@JsonProperty("id") Long id, @JsonProperty("name") String
name) {
this.id = id;
this.name = name;
}
// getters, equals, hashcode, tostring
public static class Serializer
extends StdSerializer<Seller> {
private static final long serialVersionUID = 1L;
public Serializer() {
super(Seller.class);
}
public Serializer(Class<Seller> t) {
super(t);
}
@Override
public void serialize(Seller seller, JsonGenerator jsonGenerator
, SerializerProvider serializerProvider)
throws IOException {
jsonGenerator.writeStartObject();
jsonGenerator.writeNumberField("id", seller.getId());
jsonGenerator.writeStringField("name", seller.getName());
jsonGenerator.writeEndObject();
}
}
}
@JsonSerialize(using = BasketItem.Serializer.class)
public static final class BasketItem {
private final Long itemId;
private final String itemName;
private final Price unitPrice;
@JsonCreator
BasketItem(@JsonProperty("itemId") Long itemId,
@JsonProperty("itemName") String itemName,
@JsonProperty("unitPrice") Price unitPrice) {
this.itemId = itemId;
this.itemName = itemName;
this.unitPrice = unitPrice;
}
// getters, equals, hashCode, toString
public static final class Serializer
extends StdSerializer<BasketItem> {
public Serializer() {
super(BasketItem.class);
}
public Serializer(Class<BasketItem> t) {
super(t);
}
@Override
public void serialize(BasketItem basketItem, JsonGenerator
jsonGenerator, SerializerProvider serializerProvider)
throws IOException {
jsonGenerator.writeStartObject();
jsonGenerator.writeNumberField("itemId", basketItem.
getItemId());
jsonGenerator.writeStringField("itemName", basketItem.
getItemName());
jsonGenerator.writeObjectField("unitPrice", basketItem.
getUnitPrice());
jsonGenerator.writeEndObject();
}
}
}
}
public final class Price {
private final BigDecimal amount;
// this is an enum
private final Currency currency;
@JsonCreator
public Price(@JsonProperty("amount") BigDecimal amount, @JsonProperty(
"currency") Currency currency) {
this.amount = amount;
this.currency = currency;
}
// getters, equals, hashCode, toString
}
When I try to serialize this using either
String json = new ObjectMapper().writeValueAsString(contents)
or
final ObjectMapper mapper = new ObjectMapper();
final SimpleModule module = new SimpleModule();
module.addSerializer(BasketItem.class, new BasketItem.Serializer());
module.addSerializer(Seller.class, new Seller.Serializer());
mapper.registerModule(module);
String json = mapper.writeValueAsString(contents);
it uses my toString(), but not the serializer from the annotation. If I
remove my toString, it falls back to Object.toString().
No exceptions are being thrown. Why is my Serializer not being used?
After that, what do I need to implement and register for deserialization?
Thanks
Chris
--
You received this message because you are subscribed to the Google Groups
"jackson-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
For more options, visit https://groups.google.com/d/optout.