在我的代码中,我多次使用以下注释:
@JsonSerialize(using = classOf[CustomColorRGBASerializer])
为了保持我的代码简短和DRY,我想创建一个这样的快捷方式,例如:
class JsonSerializeARGB
extends @JsonSerialize(using = classOf[CustomColorRGBASerializer])
然后我可以将其用作新的@JsonSerializeARGB
注释
我可以使用注释,但我不知道如何定义它们,因此我的尝试看起来很幼稚而且明显不正确,但我希望它具有意义。
我已阅读How do you define an @interface in Scala?和How to create annotations and get them in scala,但它们对我没什么帮助,因为我不想创建全新的注释,而是创建现有注释的“子类”。可以这样做吗?
如果没有Scala解决方案,可以用Java完成这样的事情吗? (我正在使用的Jackson annotations无论如何都是用Java定义的。)
答案 0 :(得分:4)
我担心有no way to subtype annotation with Java(和Scala)语言机制。我认为唯一的解决方案是制作Scala macro with the annotation。
对于Scala编译器,Macro annotations可以使用Macro Paradise plugin。希望他们将被包含在Scala 2.13中。要为Macro Paradise配置SBT,您可能需要关注this question。还有一个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.")
}
}
}
答案 1 :(得分:2)
看看Java,没有合理的方法可以做到这一点。 Annotations cannot be extended in current Java versions,所以最简单的方法失败了。另一种可能性是使用反射来替换所有出现的JsonSerializeARGB
JsonSerialize
,尽管这只能在运行时,而不是在编译时。然而,Java Reflection API仅支持reading annotations,而不是添加它们。
所以有两种理论方法:
JsonSerializeARGB
注释。我不熟悉Scala,所以我不知道那里是否还有其他选择。但是我怀疑Scala提供了添加或扩展Java没有的注释的方法。
答案 2 :(得分:1)
采取不同的方法。杰克逊支持以编程方式定义序列化程序。因此,您可以定义自己的注释,然后使用反射来查找带有注释的所有类,并添加序列化器映射。
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);
答案 3 :(得分:1)
以下是我尝试使用fasterXML库进行操作的示例:
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();
}
}
从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 {}
@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;
}
}
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