11

次のクラス階層がある場合、クラス階層で使用されているコンテキストに応じて、Fooを異なる方法でシリアル化する必要があります。

public class Foo {
    public String bar;
    public String biz;
}

public class FooContainer {
    public Foo fooA;
    public Foo fooB;
}

FooContainerをシリアル化するときにbiz属性がfooBに表示されないようにしたいと思います。したがって、出力は次のようになります。

{
  "fooA": {"bar": "asdf", "biz": "fdsa"},
  "fooB": {"bar": "qwer"}
}

JsonViewを使用するつもりでしたが、クラスのすべてのインスタンスのマッパーレイヤーで適用する必要があり、これはコンテキストに依存します。


Jacksonユーザーのメーリングリストで、Tatuは最も単純なソリューション(2.0で動作)を提供しました。これはおそらく今のところ使用することになります。答えはカスタムアノテーションを使用してジャクソンを拡張する方法の素晴らしい例であるため、jlabedoに賞金を授与します。

public class FooContainer {
    public Foo fooA;

    @JsonIgnoreProperties({ "biz" })
    public Foo fooB;
}
4

4 に答える 4

11

JsonViewsを使用して、カスタムシリアライザーとカスタムプロパティフィルターを組み合わせて使用​​できます。これがJackson2.0で動作するコードです

カスタム注釈を定義します。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface FilterUsingView {
    Class<?>[] value();
}

いくつかのビューを定義します。

// Define your views here
public static class Views {
    public class Public {};
    public class Internal extends Public{};
}

次に、このようにエンティティを記述できます。を使用する代わりに、独自の注釈を定義できることに注意してください@JsonView

public class Foo {
    @JsonView(Views.Public.class)
    public String bar;
    @JsonView(Views.Internal.class)
    public String biz;
}

public class FooContainer {
    public Foo fooA;
    @FilterUsingView(Views.Public.class)
    public Foo fooB;
}

次に、ここからコードが始まります:)最初にカスタムフィルター:

public static class CustomFilter extends SimpleBeanPropertyFilter {

    private Class<?>[] _nextViews;

    public void setNextViews(Class<?>[] clazz){
        _nextViews = clazz;
    }

    @Override
    public void serializeAsField(Object bean, JsonGenerator jgen,
            SerializerProvider prov, BeanPropertyWriter writer)
            throws Exception {

        Class<?>[] propViews = writer.getViews();

        if(propViews != null && _nextViews != null){
            for(Class<?> propView : propViews){
                System.out.println(propView.getName());
                for(Class<?> currentView : _nextViews){
                    if(!propView.isAssignableFrom(currentView)){
                        // Do the filtering!
                        return;
                    }
                }
            }
        }
        // The property is not filtered
        writer.serializeAsField(bean, jgen, prov);
    }
}

AnnotationIntrospector次に、 2つのことを行うカスタム:

  1. 任意のBeanに対してカスタムフィルターを有効にします...クラスで別のフィルターが定義されていない限り(つまり、私が言っていることを理解している場合は、両方を使用することはできません)
  2. @FilterUsingView彼が注釈を見つけた場合は、CustomSerializerを有効にします。

これがコードです

public class CustomAnnotationIntrospector extends AnnotationIntrospector {
    @Override
    public Version version() {
        return DatabindVersion.instance.version();
    }

    @Override
    public Object findFilterId(AnnotatedClass ac) {
      // CustomFilter is used for EVERY Bean, unless another filter is defined
      Object id = super.findFilterId(ac);
      if (id == null) {
        id = "CustomFilter";
      }
      return id;
    }

    @Override
    public Object findSerializer(Annotated am) {
        FilterUsingView annotation = am.getAnnotation(FilterUsingView.class);
        if(annotation == null){
            return null;
        }
        return new CustomSerializer(annotation.value());
    }
}

これがカスタムシリアライザーです。アノテーションの値をカスタムフィルターに渡すだけで、デフォルトのシリアライザーに処理を任せることができます。

public class CustomSerializer extends JsonSerializer<Object> {

    private Class<?>[] _activeViews;

    public CustomSerializer(Class<?>[] view){
        _activeViews = view;
    }

    @Override
    public void serialize(Object value, JsonGenerator jgen,
            SerializerProvider provider) throws IOException,
            JsonProcessingException {

        BeanPropertyFilter filter = provider.getConfig().getFilterProvider().findFilter("CustomFilter");
        if(filter instanceof CustomFilter){
            CustomFilter customFilter = (CustomFilter) filter;

            // Tell the filter that we will filter our next property
            customFilter.setNextViews(_activeViews);

            provider.defaultSerializeValue(value, jgen);

            // Property has been filtered and written, do not filter anymore
            customFilter.setNextViews(null);
        }else{
            // You did not define a CustomFilter ? Well this serializer is useless...
            provider.defaultSerializeValue(value, jgen);
        }
    }
}

ついに !これをすべてまとめましょう:

public class CustomModule extends SimpleModule {

    public CustomModule() {
        super("custom-module", new Version(0, 1, 0, "", "", ""));
    }

    @Override
    public void setupModule(SetupContext context) {
        super.setupModule(context);
        AnnotationIntrospector ai = new CustomAnnotationIntrospector();
        context.appendAnnotationIntrospector(ai);
    }

}



@Test
public void customField() throws Exception {
    FooContainer object = new FooContainer();
    object.fooA = new Foo();
    object.fooA.bar = "asdf";
    object.fooA.biz = "fdsa";
    object.fooB = new Foo();
    object.fooB.bar = "qwer";
    object.fooB.biz = "test";

    ObjectMapper mapper = new ObjectMapper();
    mapper.registerModule(new CustomModule());

    FilterProvider fp = new SimpleFilterProvider().addFilter("CustomFilter", new CustomFilter());
    StringWriter writer = new StringWriter();

    mapper.writer(fp).writeValue(writer, object);

    String expected = "{\"fooA\":{\"bar\":\"asdf\",\"biz\":\"fdsa\"},\"fooB\":{\"bar\":\"qwer\"}}";

    Assert.assertEquals(expected, writer.toString());
}
于 2012-10-06T15:30:29.973 に答える
0
import static org.junit.Assert.*;

import java.io.IOException;
import java.io.StringWriter;
import java.lang.reflect.Type;

import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializerProvider;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.codehaus.jackson.map.ser.SerializerBase;
import org.junit.Test;

class Foo {
    public String bar;
    public String biz;
}

class FooContainer {
    public Foo fooA;
    @JsonSerialize(using = FooCustomSerializer.class)
    public Foo fooB;
}

class FooCustomSerializer extends SerializerBase<Foo> {

    public FooCustomSerializer() {
        super(Foo.class);
    }

    @Override
    public void serialize(Foo foo, JsonGenerator generator, SerializerProvider provider) throws IOException, JsonGenerationException {
        generator.writeStartObject();
        generator.writeObjectField("bar", foo.bar);
        generator.writeEndObject();
    }

    @Override
    public JsonNode getSchema(SerializerProvider arg0, Type arg1) throws JsonMappingException {
        return null;
    }

}

public class JacksonTest {

    @Test
    public void customField() throws Exception {
        FooContainer object = new FooContainer();
        object.fooA = new Foo();
        object.fooA.bar = "asdf";
        object.fooA.biz = "fdsa";
        object.fooB = new Foo();
        object.fooB.bar = "qwer";
        object.fooB.biz = "test";
        ObjectMapper mapper = new ObjectMapper();
        StringWriter writer = new StringWriter();
        mapper.writeValue(writer, object);
        String expected = "{\"fooA\":{\"bar\":\"asdf\",\"biz\":\"fdsa\"},\"fooB\":{\"bar\":\"qwer\"}}";
        assertEquals(expected, writer.toString());
    }

}

パブリックFoofooBで@JsonSerialize(using = FooCustomSerializer.class)を使用します。分野。

http://jackson.codehaus.org/1.9.9/javadoc/org/codehaus/jackson/map/annotate/JsonSerialize.html

于 2012-10-04T16:21:12.867 に答える
0

ここでグーグルコードgsonの
ドキュメントを使用しますhttps://code.google.com/p/google-gson/Maven
の 依存関係は次のとおりです。

<dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.2.1</version>
        </dependency>

アノテーションは次のようになります。フィールドユーザーにアノテーション
を公開する には解析されたjsonユーザーにフィールドの特別な名前を生成するにはアノテーションしたがっ て、クラスは次のようになります。@Expose
@SerializedName("fieldNameInJSON")

    public class Foo {
@SerializedName("bar")
    @Expose
        public String bar;
@SerializedName("biz")
    @Expose
        public String biz;
    }

    public class FooContainer {
@SerializedName("fooA")
    @Expose
        public Foo fooA;
@SerializedName("fooB")
    @Expose
        public Foo fooB;
    }

JSONにシリアル化するには、次のようなコードを使用します。

public String convertToJSON(FooContainer fc) {
        if (fc != null) {
            GsonBuilder gson = new GsonBuilder();
            return gson.excludeFieldsWithoutExposeAnnotation().create().toJson(fc);
        }
        return "";
    }

たとえば、リストの場合も同じように見えます。

public String convertToJSON(List<FooContainer> fcs) {
            if (fcs != null) {
                GsonBuilder gson = new GsonBuilder();
                return gson.excludeFieldsWithoutExposeAnnotation().create().toJson(fcs);
            }
            return "";
        }
于 2012-10-06T15:47:05.037 に答える
0

@JsonIgnorePropertiesアノテーションをプロパティで使用してfooB、その特定のコンテキストでのみプロパティFooContainerを無視できます。biz

public class FooContainer {
    public Foo fooA;

    @JsonIgnoreProperties({ "biz" })
    public Foo fooB;
}

注:2012年に行った編集でこれについて言及されましたが、この特定の問題に対する最善の解決策であると感じたため、これを独自の回答として書いています。

于 2021-05-12T19:35:11.320 に答える