20

Jackson でカスタム シリアライザーを使用する方法は知っていますが (を拡張することによりJsonSerializer)、カスタム シリアライザーを使用してオーバーライドしたい 1 つのフィールドだけを除いて、すべてのフィールドでデフォルトのシリアライザーを機能させたいと考えています。

生成されたクラスを (Thrift から) シリアライズしているため、注釈はオプションではありません。

カスタム jackson シリアライザーを作成するときに、特定のフィールドのみをオーバーライドするように指定するにはどうすればよいですか?

アップデート:

シリアライズしたいクラスは次のとおりです。

class Student {
    int age;
    String firstName;
    String lastName;
    double average;
    int numSubjects

    // .. more such properties ...
}

上記のクラスには多くのプロパティがあり、そのほとんどはネイティブ型を使用しています。カスタム シリアライザーのいくつかのプロパティをオーバーライドするだけで、残りは通常どおり Jackson に処理させたいと考えています。たとえば、「年齢」フィールドをカスタム出力に変換したいだけです。

4

5 に答える 5

14

あなたのターゲットクラスが

public class Student {
    int age;
    String firstName;
    String lastName;
    double average;
    int numSubjects;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public double getAverage() {
        return average;
    }

    public void setAverage(double average) {
        this.average = average;
    }

    public int getNumSubjects() {
        return numSubjects;
    }

    public void setNumSubjects(int numSubjects) {
        this.numSubjects = numSubjects;
    }

}

以下に示すように、カスタムシリアライザーを作成する必要があります

public class MyCustomSerializer extends JsonSerializer<Student> {

    @Override
    public void serialize(Student value, JsonGenerator jgen,
            SerializerProvider provider) throws IOException,
            JsonProcessingException {
        if (value != null) {
            jgen.writeStartObject();
            jgen.writeStringField("age", "Age: " + value.getAge()); //Here a custom way to render age field is used
            jgen.writeStringField("firstName", value.getFirstName());
            jgen.writeStringField("lastName", value.getLastName());
            jgen.writeNumberField("average", value.getAverage());
            jgen.writeNumberField("numSubjects", value.getNumSubjects());
            //Write other properties
            jgen.writeEndObject();
        }
    }

}

次に、それを ObjectMapper に追加します

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule("custom",
        Version.unknownVersion());
module.addSerializer(Student.class, new MyCustomSerializer());
mapper.registerModule(module);

次に、次のように使用します

Student s = new Student();
s.setAge(2);
s.setAverage(3.4);
s.setFirstName("first");
s.setLastName("last");
s.setNumSubjects(3);

StringWriter sw = new StringWriter();
mapper.writeValue(sw, s);
System.out.println(sw.toString());

それは ao/p のようなものを生成します

{"age":"Age: 2","firstName":"first","lastName":"last","average":3.4,"numSubjects":3}

于 2013-03-13T07:24:09.200 に答える
14

クラスを変更できないからといって、注釈を使用できないわけではありません。ミックスイン注釈を使用してください。これを使用する方法については、たとえばこのブログ エントリを参照してください (または、"jackson mixin 注釈" で詳細については google を参照してください)。

私は特に protobuf およびthrift で生成されたクラスで Jackson を使用しましたが、それらは非常にうまく機能します。以前の Thrift のバージョンでは、特定のプロパティが明示的に設定されているかどうかを確認するために Thrift が生成するメソッドである「is-setter」の検出を無効にする必要がありましたが、それ以外の場合は問題なく機能していました。

于 2013-03-13T23:57:10.903 に答える
0

@JsonView の助けを借りて、10 個のプロパティを持つ 1 つのコア クラスを持つことができますが、クライアントに必要な 5 つのプロパティのみをシリアル化できます。それだけ

次のクラスを作成するだけでビューを定義します。

public class Views
{
    static class Android{};
    static class IOS{};
    static class Web{};
}

ビューを持つ注釈付きモデル クラス:

public class Demo 
{
    public Demo() 
    {
    }

@JsonView(Views.IOS.class)
private String iosField;

@JsonView(Views.Android.class)
private String androidField;

@JsonView(Views.Web.class)
private String webField;

 // getters/setters
...
..
}

ここで、Spring から HttpMessageConverter クラスを次のように拡張するだけで、カスタム json コンバーターを作成する必要があります。

    public class CustomJacksonConverter implements HttpMessageConverter<Object> 
    {
    public CustomJacksonConverter() 
        {
            super();
        //this.delegate.getObjectMapper().setConfig(this.delegate.getObjectMapper().getSerializationConfig().withView(Views.ClientView.class));
        this.delegate.getObjectMapper().configure(MapperFeature.DEFAULT_VIEW_INCLUSION, true);
        this.delegate.getObjectMapper().setSerializationInclusion(Include.NON_NULL);

    }

    // a real message converter that will respond to methods and do the actual work
    private MappingJackson2HttpMessageConverter delegate = new MappingJackson2HttpMessageConverter();

    @Override
    public boolean canRead(Class<?> clazz, MediaType mediaType) {
        return delegate.canRead(clazz, mediaType);
    }

    @Override
    public boolean canWrite(Class<?> clazz, MediaType mediaType) {
        return delegate.canWrite(clazz, mediaType);
    }

    @Override
    public List<MediaType> getSupportedMediaTypes() {
        return delegate.getSupportedMediaTypes();
    }

    @Override
    public Object read(Class<? extends Object> clazz,
            HttpInputMessage inputMessage) throws IOException,
            HttpMessageNotReadableException {
        return delegate.read(clazz, inputMessage);
    }

    @Override
    public void write(Object obj, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException 
    {
        synchronized(this) 
        {
            String userAgent = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getHeader("userAgent");
            if ( userAgent != null ) 
            {
                switch (userAgent) 
                {
                case "IOS" :
                    this.delegate.getObjectMapper().setConfig(this.delegate.getObjectMapper().getSerializationConfig().withView(Views.IOS.class));
                    break;
                case "Android" :
                    this.delegate.getObjectMapper().setConfig(this.delegate.getObjectMapper().getSerializationConfig().withView(Views.Android.class));
                    break;
                case "Web" :
                    this.delegate.getObjectMapper().setConfig(this.delegate.getObjectMapper().getSerializationConfig().withView( Views.Web.class));
                    break;
                default:
                    this.delegate.getObjectMapper().setConfig(this.delegate.getObjectMapper().getSerializationConfig().withView( null ));
                    break;
                }
            }
            else
            {
                // reset to default view
                this.delegate.getObjectMapper().setConfig(this.delegate.getObjectMapper().getSerializationConfig().withView( null ));
            }
            delegate.write(obj, contentType, outputMessage);
        }
    }

}

これを単にdispatcher-servlet.xmlに入れるだけで、このカスタムjson変換を使用するようにSpringに指示する必要があります

<mvc:annotation-driven>
        <mvc:message-converters register-defaults="true">
            <bean id="jsonConverter" class="com.mactores.org.CustomJacksonConverter" >
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

これにより、シリアル化するフィールドを決定できます。

ありがとう

于 2016-07-12T06:28:36.837 に答える