package ioinformarics.oss.jackson.module.jsonld.internal; import com.fasterxml.jackson.core.JsonGenerationException; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier; import com.fasterxml.jackson.databind.deser.std.DelegatingDeserializer; import com.github.jsonldjava.core.JsonLdError; import com.github.jsonldjava.core.JsonLdOptions; import com.github.jsonldjava.core.JsonLdProcessor; import ioinformarics.oss.jackson.module.jsonld.annotation.JsonldType; import java.io.IOException; import java.util.List; import java.util.Map; import java.util.function.Supplier; /** * @author Alexander De Leon */ public class JsonldBeanDeserializerModifier extends BeanDeserializerModifier { private final ObjectMapper mapper = new ObjectMapper(); private final Supplier<Object> contextSupplier; public JsonldBeanDeserializerModifier(Supplier<Object> contextSupplier){ this.contextSupplier = contextSupplier; } @Override public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) { if(beanDesc.getClassInfo().hasAnnotation(JsonldType.class)){ return new JsonldDelegatingDeserializer(deserializer); } return deserializer; } class JsonldDelegatingDeserializer extends DelegatingDeserializer { public JsonldDelegatingDeserializer(JsonDeserializer<?> delegatee) { super(delegatee); } @Override public Object deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { Object input = parseJsonldObject(jp); if(input == null) { return super.deserialize(jp, ctxt); } try { JsonLdOptions options = new JsonLdOptions(); Object context = contextSupplier.get(); if(context instanceof JsonNode){ context = parseJsonldObject(initParser(mapper.treeAsTokens((JsonNode)context))); } Object obj = JsonLdProcessor.compact(input, context, options); JsonParser newParser = initParser(mapper.getFactory().createParser(mapper.valueToTree(obj).toString())); return super.deserialize(newParser, ctxt); } catch (JsonLdError e) { throw new JsonGenerationException("Failed to flatten json-ld", e); } } @Override protected JsonDeserializer<?> newDelegatingInstance(JsonDeserializer<?> newDelegatee) { return new JsonldDelegatingDeserializer(newDelegatee); } private Object parseJsonldObject(JsonParser jp) throws IOException { Object rval = null; final JsonToken initialToken = jp.getCurrentToken(); if (initialToken == JsonToken.START_ARRAY) { jp.setCodec(mapper); rval = jp.readValueAs(List.class); } else if (initialToken == JsonToken.START_OBJECT) { jp.setCodec(mapper); rval = jp.readValueAs(Map.class); } else if (initialToken == JsonToken.VALUE_STRING) { jp.setCodec(mapper); rval = jp.readValueAs(String.class); } else if (initialToken == JsonToken.VALUE_FALSE || initialToken == JsonToken.VALUE_TRUE) { jp.setCodec(mapper); rval = jp.readValueAs(Boolean.class); } else if (initialToken == JsonToken.VALUE_NUMBER_FLOAT || initialToken == JsonToken.VALUE_NUMBER_INT) { jp.setCodec(mapper); rval = jp.readValueAs(Number.class); } else if (initialToken == JsonToken.VALUE_NULL) { rval = null; } return rval; } } private static JsonParser initParser(JsonParser jp) throws IOException{ jp.nextToken(); //put the parser at the start token return jp; } }