简体   繁体   中英

Extending a jackson custom serializer

Given MyClass2 extends MyClass1 and just adds two more properties to MyClass1, I wrote two Jackson custom serializers for the two classes like so:

public class MyClass1Serializer extends JsonSerializer<MyClass1> {

    @Override
    public void serialize(MyClass1 myClass1, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {

        jsonGenerator.writeStartObject();
        jsonGenerator.writeStringField("ApplicationName", myClass1.getApplicationName());
        jsonGenerator.writeStringField("UserName", myClass1.getUserName());
    }       
}

and

public class MyClass2Serializer extends JsonSerializer<MyClass2> {

    @Override
    public void serialize(MyClass2 myClass2, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {

        jsonGenerator.writeStartObject();
        jsonGenerator.writeStringField("ApplicationName", myClass2.getApplicationName());       
        jsonGenerator.writeStringField("ErrorMessage", myClass2.getErrorMessage());
        jsonGenerator.writeStringField("ResultCode", myClass2.getResultCode());
        jsonGenerator.writeStringField("UserName", myClass2.getUserName());
    }       
}

Which works fine, and gives me the following output:

{"ApplicationName":"FakeApp","UserName":"Joe the Schmoe"}

{"ApplicationName":"AnotherApp","ErrorMessage":"Uh oh!","ResultCode":"Errrrm, not good...","UserName":"John Doe"}

Well, to me, it looks like there is code duplication in the two serialize methods, and could I subclass the second serializer from the first? Hmmmm...

Ummm, well, I tried this:

public class MyClass1Serializer<T extends MyClass1> extends JsonSerializer<MyClass1> {

    @Override
    public void serialize(MyClass1 myClass1, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {

        jsonGenerator.writeStartObject();
        jsonGenerator.writeStringField("ApplicationName", myClass1.getApplicationName());
        jsonGenerator.writeStringField("UserName", myClass1.getUserName());
    }       
}

and

public class MyClass2Serializer extends MyClass1Serializer<MyClass2> {

    public void serialize(MyClass2 myClass2, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {

        super.serialize(myClass2, jsonGenerator, serializerProvider);
        jsonGenerator.writeStringField("ErrorMessage", myClass2.getErrorMessage());
        jsonGenerator.writeStringField("ResultCode", myClass2.getResultCode());
    }       
}

Which compiles and runs, but gives me this output:

{"ApplicationName":"FakeApp","UserName":"Joe the Schmoe"}

{"ApplicationName":"AnotherApp","UserName":"John Doe"}

Pretty clear to me that MyClass2Serializer is now completely ignored and Jackson finds the MyClass1Serializer and uses it for MyClass2. (Since it doesn't directly subclass JsonSerializer?)

Granted for this simple situation, no big deal, but my real-world class structure at work could really benefit by "chaining" custom serializers together instead of starting each one from scratch.

Just in case it matters, I tell Jackson which serializer to use for which class using an annotation on the class:

@JsonSerialize(using=MyClass1Serializer.class)
public class MyClass1 {

Possible future question: Assuming subclassing a custom serializer is even possible, can subclassing a custom deserializer work as well? A pointer to some sample code or tutorial would be awesome!

funny thing: I tried to replicate the problem, but it seems to work:

import java.io.*;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.*;

public class Test
{
    public static void main(String[] args) {
        MyClass1 myc1 = new MyClass1("app1", "user1");
        MyClass1 myc2 = new MyClass2("app2", "user2", "err2", "rc2");

        try {
            System.out.println(new ObjectMapper().writeValueAsString(myc1));
            System.out.println(new ObjectMapper().writeValueAsString(myc2));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @JsonSerialize(using = MyClass1Serializer.class)
    public static class MyClass1 {
        protected String applicationName;
        protected String userName;

        public MyClass1() {}

        public MyClass1(String applicationName, String userName) {
            this.applicationName = applicationName;
            this.userName = userName;
        }

        public String getApplicationName() { return applicationName; }
        public String getUserName()        { return userName; }
    }

    @JsonSerialize(using = MyClass2Serializer.class)
    public static class MyClass2 extends MyClass1 {
        protected String errorMessage;
        protected String resultCode;

        public MyClass2() {}

        public MyClass2(String applicationName, String userName, String errorMessage, String resultCode) {
            super(applicationName, userName);
            this.errorMessage = errorMessage;
            this.resultCode = resultCode;
        }

        public String getErrorMessage() { return errorMessage; }
        public String getResultCode()   { return resultCode; }
    }

    public static class MyClass1Serializer<T extends MyClass1> extends JsonSerializer<T> {
        @Override
        public void serialize(MyClass1 myClass1, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
                throws IOException
        {
            jsonGenerator.writeStartObject();
            jsonGenerator.writeStringField("ApplicationName", myClass1.getApplicationName());
            jsonGenerator.writeStringField("UserName", myClass1.getUserName());
            //jsonGenerator.writeEndObject();
        }
    }

    public static class MyClass2Serializer extends MyClass1Serializer<MyClass2> {
        @Override
        public void serialize(MyClass2 myClass2, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
                throws IOException
        {
            super.serialize(myClass2, jsonGenerator, serializerProvider);
            jsonGenerator.writeStringField("ErrorMessage", myClass2.getErrorMessage());
            jsonGenerator.writeStringField("ResultCode", myClass2.getResultCode());
            //jsonGenerator.writeEndObject();
        }
    }
}

Output:

{"ApplicationName":"app1","UserName":"user1"}
{"ApplicationName":"app2","UserName":"user2","ErrorMessage":"err2","ResultCode":"rc2"}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM