Hello!

I'm trying to write a custom serializer that can transform the following 
structure

{
    "a": {
        "@context": "context-a",
        "aKey": "aValue"
    },
    "b": {
        "@context": "context-b",
        "anotherbKey": "anotherbValue",
        "bKey": "bValue"
    }
}

into this:

{
    "@context" : ["context-a", "context-b"],
    "a": {
        "aKey": "aValue"
    },
    "b": {
        "anotherbKey": "anotherbValue",
        "bKey": "bValue"
    }
}

The reason to do this is to put all json-ld headers at the beginning of the 
serialized json. I have a utility class that extract all @context attribute 
from a bean hierarchy (ContextsCrawler in the snippet below) and my current 
serializer attempt is this:

public class JsonLdModelSerializer extends JsonSerializer<Object> {

    private static Optional<String> baseContext;
    private static ContextsCrawler ctxCrawler = new ContextsCrawler();

    public static void scanClassForContexts(Map<Class<?>, Class<?>> mixins) 
{
        ctxCrawler.scanClassForContexts(mixins);
    }
    
    public static void setBaseContext(String baseContext) {
        JsonLdModelSerializer.baseContext = Optional.of(baseContext);
    }

    @Override
    public void serialize(Object value, JsonGenerator jgen, 
SerializerProvider serializers)
            throws IOException, JsonProcessingException {
        
        jgen.writeStartObject();
        // Add contexts elements in top level element only:
        if (jgen.getOutputContext().getParent().inRoot()) {
            Collection<String> cxts = ctxCrawler.getContexts(value);
            if (cxts != null) {
                Set<String> ctxset = new HashSet<>();
                baseContext.ifPresent(ctx -> ctxset.add(ctx));
                ctxset.addAll(cxts);
                jgen.writeObjectField("@context", ctxset);
            }
        }
        JavaType javaType = serializers.constructType(value.getClass());
        BeanDescription beanDesc = serializers.getConfig().introspect(
javaType);
        JsonSerializer<Object> serializer = BeanSerializerFactory.instance.
findBeanSerializer(serializers,
                javaType,
                beanDesc);
        serializer.unwrappingSerializer(null).serialize(value, jgen, 
serializers);

        jgen.writeEndObject();
    }
}


Then I simply define a mixin for each class that contains a @context 
element like this:

@JsonSerialize(using = JsonLdModelSerializer.class)
@JsonIgnoreProperties("context")
public class CapabilityMixIn extends Capability {
 @Override
 @JsonLdContextProvider // used by ContextsCrawler
 public List<String> getContext() {
  return super.getContext();
 } 
}

It works but it has two main problems:

1. I don't know it the direct usage of BeanSerializerFactory in serialize 
method is OK since I read that this is not the best approach to use. I'm 
also worried about performance implications;
2. For some reason this serializer doesn't play nice with beans that 
contains Map<String,Object> that are decorated with @JsonAnyGetter: the 
resulting json does not contain the map elements

Could you please provide guidance? What is the right approach to implement 
such a JsonLdModelSerializer? 

Thank you,
Matteo 

-- 
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 jackson-user+unsubscr...@googlegroups.com.
To post to this group, send email to jackson-user@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to