如何正确覆盖 JacksonAnnotationIntrospector._findAnnotation 以替换元素的注释 [英] How to properly override JacksonAnnotationIntrospector._findAnnotation to replace an annotation of the element

查看:106
本文介绍了如何正确覆盖 JacksonAnnotationIntrospector._findAnnotation 以替换元素的注释的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一些可由 Jackson 序列化的类.我想用标准的 Jackson 注释来注释一些元素(在这个例子中让我们考虑 JsonIgnore),但我希望它们只在我的特定映射器中有效.

I am trying to create some classes serializable by Jackson. I want to annotate some elements with standard Jackson annotation (let's consider JsonIgnore for this example) but I want them to have effect only in my specific mapper.

所以我决定像标准的一样创建我自己的注释(例如 MyJsonIgnore),并且只在我的映射器使用的注释内省器中处理它们.我发现了可覆盖的方法 _findAnnotation.Javadoc 说明如下:

So I decided to create my own annotations like standard ones (e. g. MyJsonIgnore) and process them only in an annotation introspector used by my mapper. I've found overridable method _findAnnotation. Javadoc says the following:

...overridable that sub-classes may, if they choose to, 
mangle actual access block access ("hide" annotations) 
or perhaps change it.

我找到了一种阻止某些注释的方法(但它涉及覆盖 _hasAnnotation,而不是 _findAnnotation),但我完全坚持更改注释.

I've found a way to block some annotations (however it involves overriding _hasAnnotation, not _findAnnotation) but I am completely stuck with changing annotations.

这是我正在尝试做的一些最小的例子:

Here is some minimal example of what I am trying to do:

object Mappers {
    /**
     * Same as JsonIgnore but mapper-specific
     */
    annotation class MyJsonIgnore(val value: Boolean = true)

    private class MyIntrospector : JacksonAnnotationIntrospector() {
        override fun <A : Annotation> _findAnnotation(
            annotated: Annotated,
            annoClass: Class<A>
        ): A {
            if (annoClass == JsonIgnore::class.java && _hasAnnotation(annotated, MyJsonIgnore::class.java)) {
                val mji = _findAnnotation(annotated, MyJsonIgnore::class.java)
                return JsonIgnore(mji.value) // Does not compile, type mismatch
                // return JsonIgnore(mji.value) as A // Does not compile, annotation class cannot be instantiated, same as Java, see below
            }
            return super._findAnnotation(annotated, annoClass)
        }
    }

    fun myMapper(): ObjectMapper {
        return ObjectMapper().setAnnotationIntrospector(MyIntrospector())
    }
}

我也不能用 Java 来做:

I also cannot do it with Java:

public class Mappers {
    /**
     * Same as JsonIgnore but mapper-specific
     */
    public @interface MyJsonIgnore {
        boolean value() default true;
    }

    private static class MyIntrospector extends JacksonAnnotationIntrospector {
        @Override
        protected <A extends Annotation> A _findAnnotation(Annotated annotated,
                                                           Class<A> annoClass) {
            if (annoClass == JsonIgnore.class && _hasAnnotation(annotated, MyJsonIgnore.class)) {
                MyJsonIgnore mji = _findAnnotation(annotated, MyJsonIgnore.class);
                return new JsonIgnore(mji.value()); // Does not compile, JsonIgnore is abstract
            }
            return super._findAnnotation(annotated, annoClass);
        }
    }

    static ObjectMapper myMapper() {
        return new ObjectMapper().setAnnotationIntrospector(new MyIntrospector())
    }
}

那么通过覆盖此方法来更改注释的假设方法是什么?有没有?我的方法是对的还是应该以其他方式做?

So what is the supposed way to change annotations by overriding this method? Is there any? Is my approach right or should I do it other way?

推荐答案

这里的主要问题是不能实例化注解类.不过有一个解决方案:您可以存储 一个注释作为另一个注释的成员 像这样:

The main problem here is that you can't instantiate the annotation class. There is one solution though: you could store one annotation as a member of another annotation like this:

@Retention(AnnotationRetention.RUNTIME) // don't forget 
@Target(AnnotationTarget.FIELD)         // these annotations
annotation class MyJsonIgnore(val value: Boolean = true, val jsonIgnore: JsonIgnore = JsonIgnore())

所以 MyJsonIgnore 里面会有一个实例化的 JsonIgnore .然后你可以在你的 AnnotationIntrospector 中使用它:

So MyJsonIgnore will have an instantiated JsonIgnore inside. And then you can use it in your AnnotationIntrospector:

private class MyIntrospector : JacksonAnnotationIntrospector() {
    override fun <A : Annotation> _findAnnotation(
            annotated: Annotated,
            annoClass: Class<A>
    ): A? {
        if (annoClass == JsonIgnore::class.java && _hasAnnotation(annotated, MyJsonIgnore::class.java)) {
            val mji = _findAnnotation(annotated, MyJsonIgnore::class.java)
            if (mji?.value == true) {
                return mji.jsonIgnore as A // this cast should be safe because we have checked
                                           // the annotation class
            }
        }
        return super._findAnnotation(annotated, annoClass)
    }
}

我已经用以下课程对此进行了测试

I've tested this with the following class

class Test {
    @MyJsonIgnore
    val ignoreMe = "IGNORE"
    val field = "NOT IGNORE"
}

和方法

fun main() {
    println(Mappers.myMapper().writeValueAsString(Test()))
    println(ObjectMapper().writeValueAsString(Test()))
}

输出是

{"field":"NOT IGNORE"}
{"ignoreMe":"IGNORE","field":"NOT IGNORE"}

这篇关于如何正确覆盖 JacksonAnnotationIntrospector._findAnnotation 以替换元素的注释的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆