当前位置: 首页 > 知识库问答 >
问题:

Jackson向JSON com添加了其他字段。fasterxml。杰克逊。数据绑定。exc.无效定义例外

屈畅
2023-03-14

我正在使用Jackson序列化我的JavaPOJO类。除了字段之外,我JavaPOJO,我想在JSON中添加一些附加信息我正在编写自己的自定义CustomClassSerializer。如果我使用这个类并注册到ObjectMapper,那么我会得到错误:

Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Type id handling not implemented for type org.acme.Tiger (by serializer of type org.acme.CustomModule$CustomClassSerializer)

我无法理解这里可能出了什么问题。如果我删除自定义注册模型,那么一切都可以完美运行。

有人能让我知道这个问题的可能原因吗?我目前使用的是Jackson 2.13.2最新版本依赖项:jackson-core, jackson-datind, jackson-注释, jackson-datatype-jdk8

以下是示例代码:

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import lombok.*;

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, visible = true, property = "type")
@JsonSubTypes({@JsonSubTypes.Type(value = Bat.class, name = "Bat"),
        @JsonSubTypes.Type(value = Tiger.class, name = "Tiger")})
@JsonInclude(JsonInclude.Include.NON_NULL)
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Animal {
    private String type;
    private String name;
}
@JsonInclude(JsonInclude.Include.NON_NULL)
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonTypeName("Tiger")
public class Tiger extends Animal {
    private String livingType;
    private String foundIn;
}
@JsonInclude(JsonInclude.Include.NON_NULL)
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonTypeName("Bat")
public class Bat extends Animal{
    private String livingType;
    private String foundIn;
}
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.BeanSerializerFactory;

import java.io.IOException;

public class CustomModule extends SimpleModule {
    public CustomModule() {
        addSerializer(Tiger.class, new CustomClassSerializer());
    }

    private static class CustomClassSerializer extends JsonSerializer {
        @Override
        public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
            jgen.writeStartObject();
            jgen.writeObjectField("my_extra_field1", "some data");
            jgen.writeObjectField("my_extra_field2", "some more data");
            JavaType javaType = provider.constructType(Tiger.class);
            BeanDescription beanDesc = provider.getConfig().introspect(javaType);
            JsonSerializer<Object> serializer = BeanSerializerFactory.instance.createSerializer(provider, javaType);
            serializer.unwrappingSerializer(null).serialize(value, jgen, provider);
            jgen.writeEndObject();
        }
    }
}
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class TestMain {
    public static void main(String[] args) throws JsonProcessingException {
        final ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        objectMapper.registerModule(new CustomModule());

        Tiger tiger = new Tiger();
        tiger.setType("Tiger");
        tiger.setName("Shera");
        tiger.setFoundIn("Ground");
        tiger.setLivingType("Tree");
        System.out.println(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(tiger));
    }
}

我想知道上述例外情况的原因是什么。

共有1个答案

诸葛康胜
2023-03-14

作为一个面向Gson的人,我不认为我能写出真正高效的Jackson代码,但我想你可以结合以下Q/a来解决你的问题:

  • https://stackoverflow.com/a/27893673/12232870-为了克服你的问题;
  • https://stackoverflow.com/a/31057934/12232870-以便使用默认的序列化策略。

此外,我还想通过使用策略设计模式(如有必要)重构您的代码(很多),使其具有灵活性,并演示如何使用简单的单元测试。

public final class InterceptingSerializerModifier<T>
        extends BeanSerializerModifier {

    public interface IAppender<T> {

        void append(JsonGenerator generator, T value)
                throws IOException;

    }

    private final Class<T> baseClass;
    private final IAppender<? super T> appender;

    private InterceptingSerializerModifier(final Class<T> baseClass, final IAppender<? super T> appender) {
        this.baseClass = baseClass;
        this.appender = appender;
    }

    public static <T> BeanSerializerModifier create(final Class<T> baseClass, final IAppender<? super T> appender) {
        return new InterceptingSerializerModifier<>(baseClass, appender);
    }

    @Override
    public JsonSerializer<?> modifySerializer(final SerializationConfig config, final BeanDescription description, final JsonSerializer<?> serializer) {
        if ( !baseClass.isAssignableFrom(description.getBeanClass()) ) {
            return serializer;
        }
        @SuppressWarnings("unchecked")
        final JsonSerializer<? super T> castSerializer = (JsonSerializer<? super T>) serializer;
        return InterceptingJsonSerializer.create(castSerializer, appender);
    }

    private static final class InterceptingJsonSerializer<T>
            extends JsonSerializer<T> {

        private static final NameTransformer identityNameTransformer = new NameTransformer() {
            @Override
            public String transform(final String name) {
                return name;
            }

            @Override
            public String reverse(final String transformed) {
                return transformed;
            }
        };

        private final JsonSerializer<? super T> unwrappedSerializer;
        private final IAppender<? super T> appender;

        private InterceptingJsonSerializer(final JsonSerializer<? super T> unwrappedSerializer, final IAppender<? super T> appender) {
            this.unwrappedSerializer = unwrappedSerializer;
            this.appender = appender;
        }

        private static <T> JsonSerializer<T> create(final JsonSerializer<? super T> serializer, final IAppender<? super T> appender) {
            return new InterceptingJsonSerializer<>(serializer.unwrappingSerializer(identityNameTransformer), appender);
        }

        @Override
        public void serializeWithType(final T value, final JsonGenerator generator, final SerializerProvider provider, final TypeSerializer serializer)
                throws IOException {
            serializer.writeTypePrefix(generator, serializer.typeId(value, JsonToken.START_OBJECT));
            doSerialize(value, generator, provider);
            serializer.writeTypeSuffix(generator, serializer.typeId(value, JsonToken.START_OBJECT));
        }

        @Override
        public void serialize(final T value, final JsonGenerator generator, final SerializerProvider provider)
                throws IOException {
            generator.writeStartObject();
            doSerialize(value, generator, provider);
            generator.writeEndObject();
        }

        private void doSerialize(final T value, final JsonGenerator generator, final SerializerProvider provider)
                throws IOException {
            unwrappedSerializer.serialize(value, generator, provider);
            appender.append(generator, value);
        }

    }

}
public final class InterceptingSerializerModifierTest {

    private static final BeanSerializerModifier unit = InterceptingSerializerModifier.create(
            IValue.class,
            (generator, value) -> {
                if ( value instanceof Foo foo ) {
                    generator.writeObjectField("@extra.message", "this is from foo: " + foo.value);
                } else if ( value instanceof Bar bar ) {
                    generator.writeObjectField("@extra.message", "this is from bar: " + bar.value);
                } else {
                    generator.writeObjectField("@extra.message", "something else...");
                }
            }
    );

    private static final ObjectMapper objectMapper = new ObjectMapper()
            .registerModule(new SimpleModule()
                    .setSerializerModifier(unit)
            );

    private static Stream<Arguments> test() {
        return Stream.of(
                Arguments.of(
                        "{\"@type\":\"FOO\",\"value\":1,\"@extra.message\":\"this is from foo: 1\"}",
                        new Foo(1)
                ),
                Arguments.of(
                        "{\"@type\":\"BAR\",\"value\":2.0,\"@extra.message\":\"this is from bar: 2.0\"}",
                        new Bar(2)
                )
        );
    }

    @ParameterizedTest
    @MethodSource
    public void test(final String expectedJson, final IValue actualValue)
            throws JsonProcessingException {
        Assertions.assertEquals(expectedJson, objectMapper.writeValueAsString(actualValue));
    }

    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME)
    @JsonSubTypes({
            @JsonSubTypes.Type(value = Foo.class, name = "FOO"),
            @JsonSubTypes.Type(value = Bar.class, name = "BAR")
    })
    private sealed interface IValue
            permits Foo, Bar {
    }

    @RequiredArgsConstructor(access = AccessLevel.PRIVATE)
    private static final class Foo
            implements IValue {

        @Getter
        private final int value;

    }

    @RequiredArgsConstructor(access = AccessLevel.PRIVATE)
    private static final class Bar
            implements IValue {

        @Getter
        private final double value;

    }

}

我希望上面的代码是非常自我解释的。如果您需要使用额外的属性名称转换,您可能还需要增强代码以使标识符Transex也可注入。

与主题无关,但在您的问题中重复JSON对象属性名称,如my_extra_field,可能被认为是不推荐的(不确定是否易受攻击)。请参阅更多:JSON语法是否允许对象中存在重复键。

 类似资料:
  • 当我尝试反序列化汽车类时,我得到了下面的错误。杰克逊正试图在父类中的子元素中搜索字段。我如何确保杰克逊使用适当的子类型进行反序列化?我相信我需要使用混合/客户转换器。但我不确定如何在这个特定场景中使用它们。 注意:在我的例子中,除TestMain之外的所有类都在一个jar文件中,我不能修改源文件。 错误 线程"main"中的异常com.fasterxml.jackson.databind.exc.

  • 我遇到了反序列化问题: 这是我的班级: 我要反序列化的JSON是: 我得到以下例外: 我不想补充: 因为我想得到ResObj... 如果我添加注释,它会通过,但会将其设置为null。。这是我不想要的。

  • 我尝试使用一些类似于以下内容的JSON(来自AlphaVantage): 并使用Jackson解析它( 我的股票类如下所示: 相反,我得到了以下错误: 为什么Jackson在连接到我的股票类时遇到问题?如何将JSON中的符号连接到Stock类中的符号? 编辑:如果我将符号更改为小写,我会收到相同的错误消息:

  • 问题内容: 我有这个JSON反序列化: 我想将其序列化为2种不同的格式: [一个] [B] 我能够将其序列化为1种格式:仅[A]或[B]。这是将其序列化为[B]的代码: 我在这里了解到http://www.baeldung.com/jackson-json-view- annotation(“5 。自定义JSON视图”部分),但它只会更改其值。我想像上面的例子一样更改字段名称。谁能对此提供见解?

  • 问题内容: 我已经更新了我的依赖性,就像您在评论中所说的那样,现在我有了这个: 这是我的新pom: 我必须精确地说,我从未使用过杰克逊,而且运行非常正常。也许是因为auf spring 5? 问题答案: 尝试使用最新的。我将其升级到了,现在可以使用了。

  • 问题内容: 我使用杰克逊将JSON转换为Object类。 JSON: 对象类别: 码: 我的代码抛出这样的异常: 而且我不想在Test类上添加一个道具,我只是想让jackson转换Test中也存在的存在值。 问题答案: Jackson提供了几种不同的机制来配置“额外” JSON元素的处理。以下是将to 配置为not 的示例。 有关其他方法,请参见http://wiki.fasterxml.com/