@JsonView не распространяется на («вложенный») пользовательский сериализатор - PullRequest
0 голосов
/ 26 ноября 2018

В приведенном ниже модульном тесте есть два bean-компонента: beanA и beanB, где beanA содержит ссылку на beanB.

При сериализации bean-компонентов, предоставляющих JSON View с пользовательскими сериализаторами customСериализатор beanB не знает о предоставленном JSON View, так как вывод теста:

{
  "clazz" : "BeanA",
  "activeView" : "ViewTest",
  "beanB" : {
    "clazz" : "BeanB",
    "activeView" : null
  }
}

Единственный способ распространения activeView, который я нашел, - это: (см. полный исходный код ниже)

ObjectMapper mapper = (ObjectMapper) gen.getCodec();
mapper.setConfig(provider.getConfig());

Но JavaDoc от setConfig () говорит: «Используйте этот метод, только если вы знаете, что делаете» - чего я, очевидно, не делаю ...

Итак, мои вопросы:

  1. Это способ распространения JSON View нормально?
  2. Есть ли лучший способ?
  3. Может кто-нибудь объяснить поведение по умолчанию?

(есть строка, закомментированная с пометкой *** - они интересны только при игре без пользовательских сериализаторов (в этом случае JSON View, похоже, распространяется))

public class ViewTest {

    @Test
    public void hello() throws JsonProcessingException {

        BeanA beanA = new BeanA();
        beanA.beanB = new BeanB();

        String result = new ObjectMapper()
//            .disable(MapperFeature.DEFAULT_VIEW_INCLUSION) // ***
            .writerWithView(ViewTest.class)
            .withDefaultPrettyPrinter()
            .writeValueAsString(beanA);

        System.out.println(result);
    }

    @JsonSerialize(using = BeanASerializer.class)
    static public class BeanA {

//        @JsonView(ViewTest.class) // ***
        public String clazz = this.getClass().getSimpleName();

//        @JsonView(ViewTest.class) // ***
        public BeanB beanB;
    }

    @JsonSerialize(using = BeanBSerializer.class)
    static public class BeanB {

//        @JsonView(ViewTest.class) // ***
        public String clazz = this.getClass().getSimpleName();
    }

    static void writeClazzAndActiveView(String clazz, JsonGenerator gen, SerializerProvider provider) throws IOException {
        gen.writeStringField("clazz", clazz);
        gen.writeFieldName("activeView");
        if (provider.getActiveView() == null) {
            gen.writeNull();
        } else {
            gen.writeString(provider.getActiveView().getSimpleName());
        }
    }

    static class BeanASerializer extends JsonSerializer<BeanA> {

        @Override
        public void serialize(BeanA bean, JsonGenerator gen, SerializerProvider provider) throws IOException, JsonProcessingException {

            gen.writeStartObject();
            writeClazzAndActiveView(bean.clazz, gen, provider);

            // the only way I found to propagate the activeView:
//            ObjectMapper mapper = (ObjectMapper) gen.getCodec();
//            mapper.setConfig(provider.getConfig());

            gen.writeObjectField("beanB", bean.beanB);
            gen.writeEndObject();
        }
    }

    static class BeanBSerializer extends JsonSerializer<BeanB> {

        @Override
        public void serialize(BeanB bean, JsonGenerator gen, SerializerProvider provider) throws IOException, JsonProcessingException {

            gen.writeStartObject();
            writeClazzAndActiveView(bean.clazz, gen, provider);
            gen.writeEndObject();
        }
    }
}

1 Ответ

0 голосов
/ 28 ноября 2018

Актив должен быть правильно распространен через SerializerProvider.И вы правы, вы не должны устанавливать (и не должны устанавливать) представление таким образом - это не потокобезопасно, с одной стороны, и вся конфигурация ObjectMapper должна быть сделана до любого использования (ObjectReaderObjectWriter разрешать изменения для каждого вызова с помощью различных заводских методов).

Почему это происходит, неясно: я думаю, имеет смысл отправлять сообщение об ошибке с информацией о версии и полным воспроизведением (если это больше, чем код).

...