3

I'm trying to serialize a String field as a JSON if it contains a JSON object. For this I wrote a custom serializer:

public class TryJsonStringSerializer extends JsonSerializer<String> {
    @Override
    public void serialize(String value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) 
            throws IOException, JsonProcessingException {
        if (value == null) {
            return;
        }
        value = value.trim();
        if (value.startsWith("{") && value.endsWith("}")) {
            jsonGenerator.writeRaw(value);
        } else {
            jsonGenerator.writeString(value);
        }
    }

}

but I get the following error:

org.codehaus.jackson.JsonGenerationException: Can not write a field name, expecting a value
org.codehaus.jackson.impl.JsonGeneratorBase._reportError(JsonGeneratorBase.java:480)
org.codehaus.jackson.impl.Utf8Generator.writeFieldName(Utf8Generator.java:292)
org.codehaus.jackson.map.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:422)
org.codehaus.jackson.map.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:150)
org.codehaus.jackson.map.ser.BeanSerializer.serialize(BeanSerializer.java:112)
org.codehaus.jackson.map.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:446)
org.codehaus.jackson.map.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:150)
org.codehaus.jackson.map.ser.BeanSerializer.serialize(BeanSerializer.java:112)
org.codehaus.jackson.map.ser.std.StdContainerSerializers$IndexedListSerializer.serializeContents(StdContainerSerializers.java:122)
org.codehaus.jackson.map.ser.std.StdContainerSerializers$IndexedListSerializer.serializeContents(StdContainerSerializers.java:71)
org.codehaus.jackson.map.ser.std.AsArraySerializerBase.serialize(AsArraySerializerBase.java:86)
org.codehaus.jackson.map.ser.StdSerializerProvider._serializeValue(StdSerializerProvider.java:610)
org.codehaus.jackson.map.ser.StdSerializerProvider.serializeValue(StdSerializerProvider.java:256)
org.codehaus.jackson.map.ObjectMapper.writeValue(ObjectMapper.java:1613)
...

What will be the best way to achieve this?

2
  • The above exception trace doesn't show your method. Are you sure that's what's failing? Commented Dec 11, 2013 at 18:42
  • If I put jsonGenerator.writeString(value); instead of jsonGenerator.writeRaw(value); everything works. Commented Dec 11, 2013 at 19:22

2 Answers 2

6
public class TryJsonStringSerializer extends JsonSerializer<String> {

    private RawSerializer<String> rawSerializer = new RawSerializer<String>(String.class);
    private ToStringSerializer stringSerializer = ToStringSerializer.instance;

    @Override
    public void serialize(String value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) 
            throws IOException, JsonProcessingException {
        if (value == null) {
            return;
        }
        value = value.trim();
        if (value.startsWith("{") && value.endsWith("}")) {
            rawSerializer.serialize(value, jsonGenerator, serializerProvider);
        } else {
            stringSerializer.serialize(value, jsonGenerator, serializerProvider);
        }
    }

}
Sign up to request clarification or add additional context in comments.

Comments

1

You may want to use special annotation: @JsonRawValue, see docs

5 Comments

I want to still treat it as a string if it's not a valid JSON. How can I do this?
Perhaps there is some way of doing that, but I'd better move this logic outside of serialization and related stuff. If you don't know for sure if there's a valid JSON or not - then it's String literally. And your check for leading { or trailing } doesn't mean that content is valid JSON.
Checking for {} is not enough, but I can try to parse it and if this passes, it should be enough. If not then I can write it as a string. I was trying to maintain the logic in the example as simple as possible.
I'd suggest to either subclass some base class with adding extra fields of type JSON and String, or (my preferred way) make some aggregation class with generic property. Then it will be easier to understand what are you working with - JSON object or plain String. Having some "magic" objects, which behave in different way for different content never was a good idea. IMHO.
I found a way to do it, but your observations are very good. +1.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.