Jackson Annotations - @JsonProperty,etc; Other - @ApiModelProperty

我理解的serialize deserialize是,比如把POJO class <-> JSON相互转换
serialize POJO -> Json
deserialize Json -> POJO

1. Jackson Annotations

Jackson Serialization Annotations: @JsonAnyGetter, @JsonGetter, @JsonPropertyOrder, @JsonRawValue, @JsonValue, @JsonRootName, @JsonSerialize,
Jackson Deserialization Annotations:@JsonCreator, @JacksonInject, @JsonAnySetter, @JsonSetter, @JsonDeserialize, @JsonAlias
Jackson Property Inclusion Annotations:@JsonIgnoreProperties, @JsonIgnore, @JsonIgnoreType, @JsonInclude, @JsonAutoDetect
Jackson Polymorphic Type Handling Annotations:@JsonTypeInfo – indicates details of what type information to include in serialization
@JsonSubTypes – indicates sub-types of the annotated type
@JsonTypeName – defines a logical type name to use for annotated class
Jackson General Annotations:@JsonProperty, @JsonFormat, @JsonUnwrapped, @JsonView, @JsonManagedReference, @JsonBackReference, @JsonIdentityInfo, @JsonFilter,
Custom Jackson Annotation: We can make use of the @JacksonAnnotationsInside annotation:
Jackson MixIn Annotations:

@JsonIgnoreType
public class MyMixInForIgnoreType {}
...
mapper.addMixIn(User.class, MyMixInForIgnoreType.class);

Disable Jackson Annotation: mapper.disable(MapperFeature.USE_ANNOTATIONS);

挑几个我用过的:

1.1 @JsonGetter, @JsonSetter, @JsonProperty

  1. The @JsonGetter annotation is an alternative to the @JsonProperty annotation to mark a method as a getter method.
  2. @JsonSetter is an alternative to @JsonProperty – that marks the method as a setter method.
    This is super useful when we need to read some JSON data but the target entity class doesn’t exactly match that data, and so we need to tune the process to make it fit.

1.2 @JsonAlias

defines one or more alternative names for a property during deserialization.

@JsonAlias({ "fName", "f_name" })
private String firstName;

3 names: fName, f_name, firstName.

1.3 @JsonIgnoreProperties

@JsonIgnoreProperties is a class-level annotation that marks a property or a list of properties that Jackson will ignore.
ignoring the property id from serialization:

@JsonIgnoreProperties({ "id" })  // ignoring the property id from serialization:
public class BeanWithIgnore {
    public int id;
    public String name;
}

我理解的上面的是serialization和deserialization都会ignore,下面的这是deserialization:
To ignore any unknown properties in JSON input without exception, we can set ignoreUnknown=true of @JsonIgnoreProperties annotation.

@JsonIgnoreProperties(value={ “bookName”, “bookCategory” }, allowGetters= true), in this,@JsonIgnoreProperties will take part in JSON serialization but not in deserialization.

1.4 @JsonIgnore

The @JsonIgnore annotation is used to mark a property to be ignored at the field level.
Let’s use @JsonIgnore to ignore the property id from serialization:

public class BeanWithIgnore {
    @JsonIgnore
    public int id;
 
    public String name;
}

The @JsonIgnore annotation marks a field of a POJO to be ignored by Jackson during serialization and deserialization. Jackson ignores the field both JSON serialization and deserialization. An example of Java class that uses the @JsonIgnore annotation is this.

1.5 @JsonInclude

We can use @JsonInclude to exclude properties with empty/null/default values.

@JsonInclude(Include.NON_NULL)
public class MyBean {
    public int id;
    public String name;
}

1.6 @JsonProperty

We can add the @JsonProperty annotation to indicate the property name in JSON.

Let’s use @JsonProperty to serialize/deserialize the property name when we’re dealing with non-standard getters and setters:

public class MyBean {
    public int id;
    private String name;
 
    @JsonProperty("name")
    public void setTheName(String name) {
        this.name = name;
    }
 
    @JsonProperty("name")
    public String getTheName() {
        return name;
    }
}

2. Difference Between JsonIgnoreProperties(ignoreUnknown=true) and JsonInclude(Include.NON_EMPTY)

@JsonIgnoreProperties can also be used at serialization, check 1.3. @JsonIgnoreProperties(ignoreUnknown=true) is applicable at deserialization of JSON to Java object (POJO) only. If your POJO does not contain certain properties that JSON does contain, they are ignored and no error is thrown.
On the other hand @JsonInclude(Include.NON_EMPTY) is used at serialization of POJO to JSON and it says, skip POJO properties that are: null or what is considered empty are not to be included. Definition of emptiness is data type-specific.

3. @JsonProperty on field vs. on getter and setter

private String fileName;

@JsonProperty("fileName")
public String getFileName()
{
    return fileName;
}

@JsonProperty("fileName1")
public void setFileName(String fileName)
{
    this.fileName = fileName;
}

The getter is annotated with fileName and will be used for serialization (from object instance to string), while the setter, annotated with fileName1, will be used deserialization (from string to object instance)

If all the three @JsonProperty differ from the default property name of fileName, it would just pick one of them as the attribute(FILENAME), and had any on of the three differed, it would have thrown an exception:
java.lang.IllegalStateException: Conflicting property name definitions


In Jackson 1.8 and prior, only field and getter annotations were used when determining what and how to serialize (writing JSON); and only setter annotations for deserialization (reading JSON). This sometimes required addition of “extra” annotations, like annotating both getter and setter.

With Jackson 1.9 and above these extra annotations are NOT needed. It is still possible to add those; and if different names are used, one can create “split” properties (serializing using one name, deserializing using other): this is occasionally useful for sort of renaming.


我用了Lombok @Data, 所以只在field上注解了@JsonProperty,好像也是可以的。

4. When is the @JsonProperty property used and what is it used for?

  1. give alias name
  2. well for what its worth now… JsonProperty is ALSO used to specify getter and setter methods for the variable apart from usual serialization and deserialization. For example suppose you have a payload like this:

For example suppose you have a payload like this:

{
  "check": true
}

and a Deserializer class:

public class Check {

  @JsonProperty("check")    // It is needed else Jackson will look got getCheck method and will fail
  private Boolean check;

  public Boolean isCheck() {
     return check;
  }
}
public class Check {

  //@JsonProperty("check")    Not needed anymore
  private Boolean check;

  public Boolean getCheck() {
     return check;
  }
}

除此之外,我记得我有个比较奇怪的class,之前报了不能deserialize的错,是用@JsonProperty解决的…以及有时候得加上JsonIgnore等,还得整理一下这一部分。

@Data
@Builder
// @AllArgsConstructor // can't add
public class OuterClass{
	
	private InnerClass innerClass;

	@Data
	private class InnerClass{
	    @JsonProperty("someMultiValuedFieldName")
		private ArrayList<String> myList = new ArrayList<String>();
		private String value;
	}
	
	OuterClass() {
		innerClass = new InnerClass();
		innerClass.setMyList(new ArrayList<String>() {{
			add("str1");
			add("str2");
		}});
	}
}

5. Hide fields in Swagger, or also in (de)serialize

5.1 Hide certain fields from a spring request body in swagger

add @JsonIgnore on field. 但是这个也会从serialize和deserialize中被ignored。所以还有一种方法是:@ApiModelProperty(readOnly = true) :

5.2 How to hide a request field in Swagger API

when add jsonIgnore, readEntity cannot parse json
maybe add json ignore only for request body

@JsonProperty(access = JsonProperty.Access.READ_ONLY)
@ApiModelProperty(readOnly = true)  //但和JsonProperty一起就失去作用
private String id;

5.3 Enum JsonProperty.Access

  1. AUTO
    Access setting which means that visibility rules are to be used to automatically determine read- and/or write-access of this property.
  2. READ_ONLY
    Access setting that means that the property may only be read for serialization(I think is POJO to JSON), but not written (set) during deserialization.
  3. READ_WRITE
    Access setting that means that the property will be accessed for both serialization (writing out values as external representation) and deserialization (reading values from external representation), regardless of visibility rules.
  4. WRITE_ONLY
    Access setting that means that the property may only be written (set) for deserialization, but will not be read (get) on serialization, that is, the value of the property is not included in serialization.

5.4 综上,我的情况

responseType: application/json is needed when readEntity, but want hide in swagger, I tried

@ApiModelProperty(hidden = true)
@JsonProperty(access = JsonProperty.Access.READ_ONLY)

it works, But not hidden from swagger…swagger里request body还是有responseType:

{
...
responseType: ""
}

但是加access = JsonProperty.Access.READ_ONLY)之前,responseType:""是会报错的:can’t parse JSON. 每次必须手动更改swagger里的request body:

{
...
responseType: "application/json"
}

但是加了access = JsonProperty.Access.READ_ONLY)之后,由于是Read_only, responseType并没有被写成“”,而是首先采用了POJO中的@Builder.Default这个注解:

@Builder.Default
String responseType = "application/json";  

综上:requestBody的jJSON -> POJO,是deserialize,Read_only是只允许serialization

而且,试了一下改成WRITE_ONLY是会报错的,进一步验证了上述理解

@ApiModelProperty(hidden = true)
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY) 

但是由于@ApiModelProperty(hidden = true)和@JsonProperty一起失去了效果,而且我的这个endpoint不是显示给user调用的,而是给另一个backend service用的,所以我最后就改成了:

@ApiModelProperty(hidden = true)

5.5 Why ApiModelProperty has no effect?

We don’t want ever to have a case where the serialization model is different from whats being documented.

Actually the existence of @ApiModelProperty is explained by the fact that we want to use the same annotations that swagger-core uses. However we take the philosophy of using the annotations just to supplement documentation. If for e.g. you’ve annotated your models with @JsonProperty etc we don’t want to duplicate that using @ApiModelProperty as it is very easy to get out of sync.

(我用的是lombok的@Data) 所以我猜测,是不是也可以用:

@JsonProperty(access = JsonProperty.Access.READ_ONLY)
@JsonIgnore  //掉个位也没用
String responseType = "application/json";

但是也没有hide from swagger,而且也没有READ_ONLY…

@JsonProperty(access = JsonProperty.Access.READ_ONLY)
String responseType = "application/json";

只有@JsonProperty倒是可以READ_ONLY…但是没有hide from swagger

@JsonIgnore
String responseType = "application/json";

只有@JsonIgnore倒是也可以hide from swagger,但是没有READ_ONLY…

怎么一起就两个都不行了呢???
https://github.com/FasterXML/jackson-databind/issues/751

试试:

@JsonIgnoreProperties(ignoreUnknown = true, value={"name"}, allowGetters = true)   // should be on class level

这个是可以的,又可以hide from swagger,又能READ_ONLY。也就是说,jackson annotation中是有可以替代@ApiModelProperty(hidden = true)的。

5.6 readEntity for Jax Response

ReadEntity:
Read the message entity input stream as an instance of specified Java type using a MessageBodyReader that supports mapping the message entity stream onto the requested type.

MessageBodyReader:
Contract for a provider that supports the conversion of a stream to a Java type. A MessageBodyReader implementation may be annotated with Consumes to restrict the media types for which it will be considered suitable.
Providers implementing MessageBodyReader contract must be either programmatically registered in a JAX-RS runtime or must be annotated with @Provider annotation to be automatically discovered by the JAX-RS runtime during a provider scanning phase.

所以感觉ReadEntity是在deserialize啊(JSON->POJO)

6. Jackson @JsonIgnore, @JsonIgnoreProperties and @JsonIgnoreType

@JsonIgnore is annotated at a class property level to ignore it.
@JsonIgnoreProperties is annotated at class level and we need to specify the logical properties of that class to ignore them.
@JsonIgnoreType is annotated at class level and it ignores the complete class.

@JsonIgnore and @JsonIgnoreType has an element value which accepts Boolean values to make it active and inactive.
@JsonIgnoreProperties has elements that are allowGetters, allowSetters, ignoreUnknown and value. The element value in @JsonIgnoreProperties specifies the names of properties to ignore.

6. 遇到的几个问题

6.1 initiate inner class in outer class

Error: can only instantiate non-static inner class by using default no-argument constructor

error

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class OuterClass{
	private class InnerClass{
	    // error
		private ArrayList<String> myList = new ArrayList<String>() ({
			add("str1");
			add("str2");
		}};
	}
}

error

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class OuterClass{

	private class InnerClass{
	    // still error
		private ArrayList<String> myList = new ArrayList<String>();
		
		InnterClass() {
			myList.add("str1");
			myList.add("str2");
		}
	}
}

not error, but… not sure if are errors later…

@Data
@Builder
// @AllArgsConstructor // can't 
public class OuterClass{
	
	private InnerClass innerClass;

	@Data
	private class InnerClass{
	    @JsonProperty("someMultiValuedField")
		private ArrayList<String> myList = new ArrayList<String>();
	}
	
	OuterClass() {
		innerClass = new InnerClass();
		innerClass.setMyList(new ArrayList<String>() {{
			add("str1");
			add("str2");
		}});
	}
}

6.2 java.util.arraylist out of VALUE_STRING token

java.util.arraylist out of VALUE_STRING token

https://stackoverflow.com/questions/54198875/exception-can-not-deserialize-instance-of-java-util-arraylist-out-of-start-obje
it’s a deserialize thing.

先work了,后来又不行了,而且String[] ArrayList都不可以了,猜测可能是cache没更新???
后来感觉可能@JsonProperty(“someValue”)重名了,有个变量也叫: private SomeValue someValue.

用String[]也可以…但感觉这样太奇怪了,没有用inner class了,另外定义了一个class,然后用的final String = “str1, str2”… 当然应该也可以用enum。。。最后重构了代码,完全换了个思路,也就没纠结这一块了。

@Data
@Builder
@AllArgsConstructor 
@NoArgsConstructor
public class OuterClass{
	
	private InnerClass innerClass;

	@Data
	private class InnerClass{
	    @JsonProperty("someMultiValuedField")
		private ArrayList<String> myList = new ArrayList<String>({
			{add("str1"); add("str2");}
		});

		// or:
		@JsonProperty("someMultiValuedField")
		private String[] myList = new String[]{"str1", "str2"};
	}
}

你可能感兴趣的:(One,week,Learning,Notes)