package com.fasterxml.jackson.datatype.eclipsecollections.deser.map;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
import com.fasterxml.jackson.databind.type.LogicalType;

import java.io.IOException;

Author:yawkat
/** * @author yawkat */
public abstract class EclipseMapDeserializer<T, I, K extends KeyHandler<K>, V extends ValueHandler<V>> extends JsonDeserializer<T> implements ContextualDeserializer { private final K keyHandler; private final V valueHandler; public EclipseMapDeserializer(K keyHandler, V valueHandler) { this.keyHandler = keyHandler; this.valueHandler = valueHandler; } @Override public LogicalType logicalType() { return LogicalType.Map; } protected abstract EclipseMapDeserializer<T, ?, ?, ?> withResolved(K keyHandler, V valueHandler); protected abstract I createIntermediate(); protected abstract void deserializeEntry( I target, K keyHandler, V valueHandler, DeserializationContext ctx, String key, JsonParser valueParser ) throws IOException; protected abstract T finish(I intermediate); @Override public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException { K kc = keyHandler.createContextualKey(ctxt, property); V vc = valueHandler.createContextualValue(ctxt, property); //noinspection ObjectEquality if (kc == keyHandler && vc == valueHandler) { return this; } else { return withResolved(kc, vc); } } @Override public Object deserializeWithType( JsonParser p, DeserializationContext ctxt, TypeDeserializer typeDeserializer ) throws IOException { // note: call "...FromObject" because expected output structure // for value is JSON Object (regardless of contortions used for type id) return typeDeserializer.deserializeTypedFromObject(p, ctxt); } @SuppressWarnings("unchecked") @Override public T deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { // Ok: must point to START_OBJECT or FIELD_NAME JsonToken t = p.getCurrentToken(); if (t == JsonToken.START_OBJECT) { // If START_OBJECT, move to next; may also be END_OBJECT t = p.nextToken(); } if (t != JsonToken.FIELD_NAME && t != JsonToken.END_OBJECT) { return (T) ctxt.handleUnexpectedToken(handledType(), p); } I map = createIntermediate(); for (; p.getCurrentToken() == JsonToken.FIELD_NAME; p.nextToken()) { // Must point to field name now String fieldName = p.getCurrentName(); p.nextToken(); deserializeEntry(map, keyHandler, valueHandler, ctxt, fieldName, p); } return finish(map); } }