如何创建现有注释的快捷方式?
How to create a shortcut to existing annotation?
在我的代码中,我多次使用以下注释:
@JsonSerialize(using = classOf[CustomColorRGBASerializer])
为了使我的代码简短 DRY,我想为此创建一个快捷方式,例如:
class JsonSerializeARGB
extends @JsonSerialize(using = classOf[CustomColorRGBASerializer])
然后我可以将其用作新的 @JsonSerializeARGB
注释
我可以使用注释,但我不知道如何定义它们,因此我的尝试当然看起来很幼稚而且显然是不正确的,但我希望它能表达意思。
我已阅读 How do you define an @interface in Scala? and How to create annotations and get them in scala,但它们对我帮助不大,因为我不想创建全新的注释,而是“子类化”现有注释。这能做到吗?
如果没有Scala的解决方案,在Java中可以做这样的事情吗? (无论如何,我正在使用的 Jackson annotations 是在 Java 中定义的)。
查看Java,没有合理的方法可以做到这一点。 Annotations cannot be extended in current Java versions, so the easiest approach fails. An other possiblity would be to use reflection to replace all occurrences of a JsonSerializeARGB
with JsonSerialize
, though this would only work at runtime, not at compile time. Yet the Java Reflection API only supports reading annotations,不添加它们。
所以有两种理论方法:
- 弄乱编译的字节码,但没有人真的想这样做。
- 修改 Jackson(或任何其他读取注释的库)以识别您的自定义
JsonSerializeARGB
注释。
我不熟悉Scala,所以我不知道那里是否有其他选择。但我怀疑 Scala 是否提供了添加或扩展 Java 没有的注解的方法。
恐怕还有no way to subtype annotation with Java (and Scala) language mechanisms. I think that the only solution is to make a Scala macro with the annotation。
Macro annotations are available with Macro Paradise plugin for Scala compiler. Hopefully they 'll be included in Scala 2.13. To configure SBT for Macro Paradise you may want to follow this question. There is also a useful example利用宏乐园的项目
我相信这可以做得更好(尤其是 DefDef 匹配),但是类似于这个的宏应该可以解决您的问题:
import scala.reflect.macros._
import scala.annotation.StaticAnnotation
import scala.language.experimental.macros
class JsonSerializeARGB extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro JsonSerializeARGBMacroImpl.impl
}
object JsonSerializeARGBMacroImpl extends JsonSerializeARGBMacro
class JsonSerializeARGBMacro {
def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
import c.universe._
def modifiedDef(d: DefDef) = {
val (mods, name, tparams, paramss, tpt, body) = try {
val q"$mods def $name[..$tparams](...$paramss): $tpt = $body" = d
(mods, name, tparams, paramss, tpt, body)
} catch {
case _: MatchError => c.abort(c.enclosingPosition, "Failed to match...")
}
//TODO there is a problem with modifiers
c.Expr(q"""
@JsonSerialize(using = classOf[CustomColorRGBASerializer])
def $name[..$tparams](...$paramss): $tpt = $body
""")
}
annottees.map(_.tree) match {
case (d: DefDef) :: Nil => modifiedDef(d)
case _ => c.abort(c.enclosingPosition, "Invalid annottee.")
}
}
}
采取不同的方法。 Jackson 支持以编程方式定义序列化程序。所以你可以定义你自己的注释,然后使用反射找到所有带有你的注释的类并添加序列化器映射。
ObjectMapper mapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule("MyModule", new Version(1, 0, 0, null))
// use reflections to find all classes with Annotation the
for (classWithAnnotation <- classesWithAnnotation) {
simpleModule.addSerializer(classWithAnnotation, new CustomColorRGBASerializer());
}
mapper.registerModule(simpleModule);
这里是我试图用 fasterXML 库得到你想做的事情的例子:
1。创建您自己的 CustomSerializer
import java.io.IOException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.core.JsonProcessingException;
public class CustomSerializer extends JsonSerializer<CustomDTO> {
@Override
public void serialize(CustomDTO value, JsonGenerator gen,
com.fasterxml.jackson.databind.SerializerProvider serializers)
throws IOException,
JsonProcessingException {
gen.writeStartObject();
gen.writeStringField("AccentColor", value.getAccentColor());
gen.writeStringField("ButtonColor", value.getButtonColor());
gen.writeEndObject();
}
}
2。创建注释以使用此 CustomSerializer:
从 Scala 2.11 开始,这需要在 Java 中完成,因为在 Scala 中,目前无法定义具有运行时保留的注释。
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonSerialize(using = CustomSerializer.class)
public @interface JsonSeriliazerCustom {}
3。在 CustomDTO 或您的 class 上使用它,如下所示:
@JsonSeriliazerCustom
public class CustomDTO {
private String buttonColor;
private String accentColor;
private String frontColor;
public String getButtonColor() {
return buttonColor;
}
public void setButtonColor(String buttonColor) {
this.buttonColor = buttonColor;
}
public String getAccentColor() {
return accentColor;
}
public void setAccentColor(String accentColor) {
this.accentColor = accentColor;
}
public String getFrontColor() {
return frontColor;
}
public void setFrontColor(String frontColor) {
this.frontColor = frontColor;
}
}
4。像这样写你的主要方法:
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.introspect.VisibilityChecker;
import com.opera.oss.core.dto.CustomDTO;
public class TestJson {
public static void main(String[] args)
{
CustomDTO responseDTO = new CustomDTO();
responseDTO.setAccentColor("red");
responseDTO.setButtonColor("blue");
responseDTO.setFrontColor("yellow");
System.out.println("hey");
ObjectMapper om = new ObjectMapper();
VisibilityChecker<?> checker = om.getSerializationConfig().getDefaultVisibilityChecker();
om.setVisibilityChecker(checker.withFieldVisibility(JsonAutoDetect.Visibility.ANY));
try {
System.out.println(om.writer().writeValueAsString(responseDTO));
} catch (JsonProcessingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
使用的库:fasterXML - 2.5.0 版本 - jackson-core、jackson-data-bind 和 jackson-annotations
在我的代码中,我多次使用以下注释:
@JsonSerialize(using = classOf[CustomColorRGBASerializer])
为了使我的代码简短 DRY,我想为此创建一个快捷方式,例如:
class JsonSerializeARGB
extends @JsonSerialize(using = classOf[CustomColorRGBASerializer])
然后我可以将其用作新的 @JsonSerializeARGB
注释
我可以使用注释,但我不知道如何定义它们,因此我的尝试当然看起来很幼稚而且显然是不正确的,但我希望它能表达意思。
我已阅读 How do you define an @interface in Scala? and How to create annotations and get them in scala,但它们对我帮助不大,因为我不想创建全新的注释,而是“子类化”现有注释。这能做到吗?
如果没有Scala的解决方案,在Java中可以做这样的事情吗? (无论如何,我正在使用的 Jackson annotations 是在 Java 中定义的)。
查看Java,没有合理的方法可以做到这一点。 Annotations cannot be extended in current Java versions, so the easiest approach fails. An other possiblity would be to use reflection to replace all occurrences of a JsonSerializeARGB
with JsonSerialize
, though this would only work at runtime, not at compile time. Yet the Java Reflection API only supports reading annotations,不添加它们。
所以有两种理论方法:
- 弄乱编译的字节码,但没有人真的想这样做。
- 修改 Jackson(或任何其他读取注释的库)以识别您的自定义
JsonSerializeARGB
注释。
我不熟悉Scala,所以我不知道那里是否有其他选择。但我怀疑 Scala 是否提供了添加或扩展 Java 没有的注解的方法。
恐怕还有no way to subtype annotation with Java (and Scala) language mechanisms. I think that the only solution is to make a Scala macro with the annotation。
Macro annotations are available with Macro Paradise plugin for Scala compiler. Hopefully they 'll be included in Scala 2.13. To configure SBT for Macro Paradise you may want to follow this question. There is also a useful example利用宏乐园的项目
我相信这可以做得更好(尤其是 DefDef 匹配),但是类似于这个的宏应该可以解决您的问题:
import scala.reflect.macros._
import scala.annotation.StaticAnnotation
import scala.language.experimental.macros
class JsonSerializeARGB extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro JsonSerializeARGBMacroImpl.impl
}
object JsonSerializeARGBMacroImpl extends JsonSerializeARGBMacro
class JsonSerializeARGBMacro {
def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
import c.universe._
def modifiedDef(d: DefDef) = {
val (mods, name, tparams, paramss, tpt, body) = try {
val q"$mods def $name[..$tparams](...$paramss): $tpt = $body" = d
(mods, name, tparams, paramss, tpt, body)
} catch {
case _: MatchError => c.abort(c.enclosingPosition, "Failed to match...")
}
//TODO there is a problem with modifiers
c.Expr(q"""
@JsonSerialize(using = classOf[CustomColorRGBASerializer])
def $name[..$tparams](...$paramss): $tpt = $body
""")
}
annottees.map(_.tree) match {
case (d: DefDef) :: Nil => modifiedDef(d)
case _ => c.abort(c.enclosingPosition, "Invalid annottee.")
}
}
}
采取不同的方法。 Jackson 支持以编程方式定义序列化程序。所以你可以定义你自己的注释,然后使用反射找到所有带有你的注释的类并添加序列化器映射。
ObjectMapper mapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule("MyModule", new Version(1, 0, 0, null))
// use reflections to find all classes with Annotation the
for (classWithAnnotation <- classesWithAnnotation) {
simpleModule.addSerializer(classWithAnnotation, new CustomColorRGBASerializer());
}
mapper.registerModule(simpleModule);
这里是我试图用 fasterXML 库得到你想做的事情的例子:
1。创建您自己的 CustomSerializer
import java.io.IOException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.core.JsonProcessingException;
public class CustomSerializer extends JsonSerializer<CustomDTO> {
@Override
public void serialize(CustomDTO value, JsonGenerator gen,
com.fasterxml.jackson.databind.SerializerProvider serializers)
throws IOException,
JsonProcessingException {
gen.writeStartObject();
gen.writeStringField("AccentColor", value.getAccentColor());
gen.writeStringField("ButtonColor", value.getButtonColor());
gen.writeEndObject();
}
}
2。创建注释以使用此 CustomSerializer:
从 Scala 2.11 开始,这需要在 Java 中完成,因为在 Scala 中,目前无法定义具有运行时保留的注释。
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonSerialize(using = CustomSerializer.class)
public @interface JsonSeriliazerCustom {}
3。在 CustomDTO 或您的 class 上使用它,如下所示:
@JsonSeriliazerCustom
public class CustomDTO {
private String buttonColor;
private String accentColor;
private String frontColor;
public String getButtonColor() {
return buttonColor;
}
public void setButtonColor(String buttonColor) {
this.buttonColor = buttonColor;
}
public String getAccentColor() {
return accentColor;
}
public void setAccentColor(String accentColor) {
this.accentColor = accentColor;
}
public String getFrontColor() {
return frontColor;
}
public void setFrontColor(String frontColor) {
this.frontColor = frontColor;
}
}
4。像这样写你的主要方法:
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.introspect.VisibilityChecker;
import com.opera.oss.core.dto.CustomDTO;
public class TestJson {
public static void main(String[] args)
{
CustomDTO responseDTO = new CustomDTO();
responseDTO.setAccentColor("red");
responseDTO.setButtonColor("blue");
responseDTO.setFrontColor("yellow");
System.out.println("hey");
ObjectMapper om = new ObjectMapper();
VisibilityChecker<?> checker = om.getSerializationConfig().getDefaultVisibilityChecker();
om.setVisibilityChecker(checker.withFieldVisibility(JsonAutoDetect.Visibility.ANY));
try {
System.out.println(om.writer().writeValueAsString(responseDTO));
} catch (JsonProcessingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
使用的库:fasterXML - 2.5.0 版本 - jackson-core、jackson-data-bind 和 jackson-annotations