What are annotations?
The Retention and Target
strategy |
describe |
Source |
The compiler discards annotations |
Class |
Annotations are recorded in class files generated by the compiler, but do not require the Java Virtual Machine (JVM) reservation that processes class files at run time. |
Runtime |
Annotations are recorded in class files by the compiler and retained by the JVM at run time |
The target |
describe |
Annotation Type |
Annotation another annotation |
Constructor |
Annotation constructor |
Field |
Annotate a field, such as a class instance variable or enumeration constant |
Local variable |
Annotation local variable |
Method |
Annotation class methods |
Module |
Annotation module (new in Java 9) |
Package |
Annotations package |
Parameter |
Annotated arguments to a method or constructor |
Type |
Annotate a type, such as a class, interface, annotation type, or enumeration declaration |
Type Parameter |
Annotate type parameters, such as those used as generic parameter forms |
Type Use |
The use of annotation types, such as when creating an object of type using the new keyword, when casting an object to a specified type, when a class implements an interface, or when declaring the type of a throwable object using the throws keyword (for more information, See Type Annotations and Pluggable Type Systems Oracle Tutorial) |
Annotation parameters
How do I create annotations?
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface JsonField {
public String value(a) default "";
}Copy the code
The core of our declaration is the public @Interface JsonField, which declares annotations with the public modifier — allowing our annotations to be used in any package (assuming the package is imported correctly in another module). The annotation declares a parameter of type String value. The default value is an empty String.
How are annotations used?
public class Car {
@JsonField("manufacturer")
private final String make;
@JsonField
private final String model;
private final String year;
public Car(String make, String model, String year) {
this.make = make;
this.model = model;
this.year = year;
}
public String getMake(a) {
return make;
}
public String getModel(a) {
return model;
}
public String getYear(a) {
return year;
}
@Override
public String toString(a) {
return year + "" + make + ""+ model; }}Copy the code
This class uses the @jsonfield annotation for two main purposes :(1) having explicit values, and (2) having default values. We could also annotate a field with @jsonField (value = “someName”), but this style is verbose and does not help readability. Therefore, unless the annotation parameter name is included in the single-element annotation to increase the readability of the code, it should be omitted. For annotations with multiple parameters, you need to explicitly specify the name of each parameter to distinguish the parameters (unless only one parameter is provided, in which case the parameter is mapped to the value parameter if the name is not explicitly provided).
How are annotations handled?
public class JsonSerializer {
public String serialize(Object object) throws JsonSerializeException {
try{ Class<? > objectClass = requireNonNull(object).getClass(); Map<String, String> jsonElements =new HashMap<>();
for (Field field : objectClass.getDeclaredFields()) {
field.setAccessible(true);
if (field.isAnnotationPresent(JsonField.class)) {
jsonElements.put(getSerializedKey(field), (String) field.get(object));
}
}
System.out.println(toJsonString(jsonElements));
return toJsonString(jsonElements);
} catch (IllegalAccessException e) {
throw newJsonSerializeException(e.getMessage()); }}private String toJsonString(Map<String, String> jsonMap) {
String elementsString = jsonMap.entrySet().stream().map(entry -> "\" " + entry.getKey() + "\", \ "" + entry.getValue() + "\" ").collect(Collectors.joining(","));
return "{" + elementsString + "}";
}
private static String getSerializedKey(Field field) {
String annotationValue = field.getAnnotation(JsonField.class).value();
if (annotationValue.isEmpty()) {
return field.getName();
} else {
returnannotationValue; }}}Copy the code
Note that multiple functions have been merged into this class for brevity. About the serializer class refactoring version, please refer to the codebase repository of the branch (https://github.com/albanoj2/dzone-json-serializer/tree/srp_generalization). We also create an exception to indicate whether an error occurred when the serialize method processed an object:
public class JsonSerializeException extends Exception {
private static final long serialVersionUID = -8845242379503538623L;
public JsonSerializeException(String message) {
super(message); }}Copy the code
Although the JsonSerializer class may seem complex, it contains three main tasks: (1) Find all fields that use the @JsonField annotation, (2) record the names (or explicitly supplied field names) and values of all fields that contain the @JsonField annotation, and (3) convert the key-value pairs of the recorded field names and values to JSON strings.
Car car=new Car("Ford"."F150"."2018");
JsonSerializer serializer=new JsonSerializer();
serializer.serialize(car); Copy the code
Output:
{"model":"F150"."manufacturer":"Ford"}Copy the code