禁用Jackson mapper对于特定注释

7

使用Jackson,可以轻松地为给定的 ObjectMapper 禁用所有注解。 有没有一种方法只禁用一个给定的注解?

// disable all
ObjectMapper mapper = new ObjectMapper()
mapper.disable(MapperFeature.USE_ANNOTATIONS);

// disable one?
ObjectMapper mapper = new ObjectMapper()
mapper.disable(@JsonIgnore);

使用@JacksonAnnotationsInside,我定义了一个自定义的Jackson注释,并且我只想在特定情况下使用它。


似乎没有使用此禁用调用的方法,但是您的自定义注释是做什么的?可能有另一种方法来实现所需的行为。 - Usman Ismail
该注释添加了一个自定义的序列化/反序列化器,但这并不是此映射器所需要的。 - yves amsellem
Jackson视图不足以满足您的需求吗?如果您在自定义de/serializer中所做的全部工作都是过滤读取或写入哪些字段,那么视图也可以完成同样的工作。请参见此处(http://www.techtraits.com/Programming/2011/08/12/implementing-jackson-views/)。 - Usman Ismail
de/serializer将字符串转换为MongoDB ObjectId。此问题与此github帖子有关。 - yves amsellem
你是在建议将de/serializer提取到对象方法中吗?因为这意味着需要在每个需要它的对象上复制其代码... - yves amsellem
显示剩余2条评论
4个回答

2

这是我遇到过的最好的方法。我想我在Jackson用户组论坛上看到过它。

本质上,它创建了一个自定义注释内省器,如果发现具有特定注释(在本例中为JsonTypeInfo),则返回null。

JacksonAnnotationIntrospector ignoreJsonTypeInfoIntrospector = new JacksonAnnotationIntrospector() {
            @Override
            protected TypeResolverBuilder<?> _findTypeResolver(
                    MapperConfig<?> config, Annotated ann, JavaType baseType) {
                if (!ann.hasAnnotation(JsonTypeInfo.class)) {
                    return super._findTypeResolver(config, ann, baseType);
                }
                return null;
            }
        };

        mapper.setAnnotationIntrospector(ignoreJsonTypeInfoIntrospector);

2
在这个解决方案中有一个重要的注意事项:与其返回null,你应该返回StdTypeResolverBuilder.noTypeInfoBuilder()。在我的情况下,我在Jersey中使用Jackson作为我的JSON处理器。当使用某些Jersey功能(例如EntityFiltering)时,在注释内省器阶段序列化JSON的处理工作流程不像预期的那样工作。在我的特定情况下,当findTypeResovler返回null时,Jersey Filtering使用其“次要”注释内省器成功地序列化JsonTypeInfo。 - ChrisO
这是使用Jackson 2.8.9完成的。 - ChrisO

0

这个解决方案对我有效。请查看this获取更多信息。

 private static final JacksonAnnotationIntrospector IGNORE_ENUM_ALIAS_ANNOTATIONS = new JacksonAnnotationIntrospector() {

    @Override
    protected <A extends Annotation> A _findAnnotation(final Annotated annotated, final Class<A> annoClass) {
        if (!annotated.hasAnnotation(JsonEnumAliasSerializer.class)) {
            return super._findAnnotation(annotated, annoClass);
        }
        return null;
    }
};

还有我的自定义注解:

@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonSerialize(using = JsonEnumSerializer.class)
public @interface JsonEnumAliasSerializer {
}

还有ObjectMapper:

    final ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.setAnnotationIntrospector(IGNORE_ENUM_ALIAS_ANNOTATIONS);

尝试使用Jackson 2.11.0,但出现了NullPointerExceptions。打分降低。 - Dave Moten

0

我认为更好的方法是像这样覆盖 findPropertiesToIgnore 方法:

    JacksonAnnotationIntrospector ignoreJsonTypeInfoIntrospector = new JacksonAnnotationIntrospector() {
        @Override
        public String[] findPropertiesToIgnore(AnnotatedClass ac) {
            ArrayList<String> ret = new ArrayList<String>();
            for (Method m : ac.getRawType().getMethods()) {
                if(ReflectionUtils.isGetter(m)){
                    if(m.getAnnotation(Transient.class) != null)
                        ret.add(ReflectionUtils.getPropertyName(m));

                }
            };
            return ret.toArray(new String[]{});
        }
    };
    objectMapper = new ObjectMapper();
    objectMapper.setAnnotationIntrospector(ignoreJsonTypeInfoIntrospector);

0
以下是一种更简单的方法(2022年8月)在Kotlin中实现它(如果你真的想要,你可以将其翻译成Java):
(我在一个Ktor/KMongo项目中使用它来防止“Transient”属性被持久化,因为KMongo需要“@JsonIgnore”,这也会防止我的其他映射器序列化这些属性!)
@Target(PROPERTY_GETTER)
annotation class Transient

private val TransientIntrospector: JacksonAnnotationIntrospector = object : JacksonAnnotationIntrospector() {
    override fun hasIgnoreMarker(m: AnnotatedMember): Boolean =
        m.allAnnotations.has(Transient::class.java) || super.hasIgnoreMarker(m)
}

private class IgnoreTransientModule : SimpleModule() {
    override fun setupModule(context: SetupContext) {
        super.setupModule(context)
        context.appendAnnotationIntrospector(TransientIntrospector)
    }
}

// Just register the module in your `ObjectMapper` instance:
val ignoreTransientMapper = with(ObjectMapper()) {
    registerModule(IgnoreTransientModule())
}

// And here is how to use it:
data class Customer(
    val id: String? = null,
    val firstName: String,
    val lastName: String,
) {
    @get:Transient
    val fullName: String
        get() = "$firstName $lastName"
}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接