忽略单元测试的 Jackon JsonProperty 访问
Ignoring Jackon JsonProperty Access for Unit Tests
我将 Jackson 用于 serialization/deserialization 我的 Spring 引导项目。
我有一个具有以下结构的 DTO 对象,
public class TestDTO implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
private UUID certificateId;
@NotNull
private Long orgId;
@NotNull
private CertificateType certificateType;
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
@Valid
@NotNull
private PublicCertificateDTO publicCertificate;
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
@Valid
private PrivateCertificateDTO privateCertificate;
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
private ZonedDateTime expiryDate;
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
private ZonedDateTime createdDate;
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
private ZonedDateTime updatedDate;
}
在我的单元测试中使用以下方法序列化此对象,
public static byte[] convertObjectToJsonBytes(TestDTO object)
throws IOException {
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
JavaTimeModule module = new JavaTimeModule();
mapper.registerModule(module);
return mapper.writeValueAsBytes(object);
}
导致具有 WRITE_ONLY
访问权限的字段被忽略(原因很明显)。所以在序列化对象中,我看到 publicCertificate
和 privateCertificate
.
的空值
我试过设置mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)
有没有其他方法可以忽略单元测试的这些属性?
已通过为 JUnit 测试添加自定义序列化程序解决此问题。
所以对于 TestDTO
我添加了序列化程序如下。
private class TestJsonSerializer extends StdSerializer<TestDTO> {
public TestJsonSerializer() {
this(null);
}
public TestJsonSerializer(Class<TestDTO> t) {
super(t);
}
@Override
public void serialize(TestDTO value, JsonGenerator gen, SerializerProvider provider) throws IOException {
gen.writeStartObject();
gen.writeNumberField("orgId", value.getOrgId());
gen.writeStringField("certificateType", value.getCertificateType().getType());
if (value.getPublicCertificate() != null) {
gen.writeObjectField("publicCertificate", value.getPublicCertificate());
}
if (value.getPrivateCertificate() != null) {
gen.writeObjectField("privateCertificate", value.getPrivateCertificate());
}
gen.writeObjectField("expiryDate", value.getExpiryDate());
gen.writeObjectField("createdDate", value.getCreatedDate());
gen.writeObjectField("updatedDate", value.getUpdatedDate());
gen.writeEndObject();
}
}
然后我补充说,
ObjectMapper mapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(TestDTO.class, new TestJsonSerializer());
mapper.registerModule(simpleModule);
类似地为嵌套对象添加和注册了自定义序列化程序,publicCertificate
和 privateCertificate
。
虽然指定的解决方案有效,但对于要求来说有点过分了。如果您只想覆盖注释,则不需要自定义序列化程序。杰克逊有一个 mixin feature 如此微不足道的要求
考虑以下简化的 POJO:
public class TestDTO
{
public String regularAccessProperty;
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
public String writeAccessProperty;
}
如果你想覆盖 @JsonProperty
注释,你创建另一个 POJO,它有一个变量 完全相同的名称 (或相同的 getter/setter 名称):
// mixin class that overrides json access annotation
public class UnitTestDTO
{
@JsonProperty(access = JsonProperty.Access.READ_WRITE)
public String writeAccessProperty;
}
您通过简单模块将原始 POJO 和混入相关联:
simpleModule.setMixInAnnotation(TestDTO.class, UnitTestDTO.class);
举个简单的例子
@ToString
@Getter
@Setter
public class Account implements Cloneable {
@JsonProperty(access = Access.WRITE_ONLY)
private Integer accountId;
private String accountType;
private Long balance;
public AccountTest clone() {
AccountTest test = new AccountTest();
test.setAccountId(this.accountId);
test.setAccountType(this.accountType);
test.setBalance(this.balance);
return test;
}
}
@ToString
@Getter
@Setter
public class AccountTest {
private Integer accountId;
private String accountType;
private Long balance;
}
public static void main(String[] args) {
ObjectMapper mapper = new ObjectMapper();
try {
Account account = new Account();
account.setAccountId(1999900);
account.setAccountType("Saving");
account.setBalance(2433l);
AccountTest accountTest = account.clone();
System.out.println(account);
byte[] accountBytes = mapper.writeValueAsBytes(account);
System.out.println(new String(accountBytes));
byte[] accountTestBytes = mapper.writeValueAsBytes(accountTest);
System.out.println(new String(accountTestBytes));
} catch (IOException e) { }
}
}
Is there any other way to ignore these properties for Unit Tests ?
解决方法:在你的convertObjectToJsonBytes
方法中,你可以使用:
mapper.disable(MapperFeature.USE_ANNOTATIONS);
参考: MapperFeature.USE_ANNOTATIONS
/**
* Feature that determines whether annotation introspection
* is used for configuration; if enabled, configured
* {@link AnnotationIntrospector} will be used: if disabled,
* no annotations are considered.
*<p>
* Feature is enabled by default.
*/
USE_ANNOTATIONS(true),
注意: 这将禁用给定 ObjectMapper
.
的所有注释
我将 Jackson 用于 serialization/deserialization 我的 Spring 引导项目。
我有一个具有以下结构的 DTO 对象,
public class TestDTO implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
private UUID certificateId;
@NotNull
private Long orgId;
@NotNull
private CertificateType certificateType;
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
@Valid
@NotNull
private PublicCertificateDTO publicCertificate;
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
@Valid
private PrivateCertificateDTO privateCertificate;
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
private ZonedDateTime expiryDate;
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
private ZonedDateTime createdDate;
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
private ZonedDateTime updatedDate;
}
在我的单元测试中使用以下方法序列化此对象,
public static byte[] convertObjectToJsonBytes(TestDTO object)
throws IOException {
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
JavaTimeModule module = new JavaTimeModule();
mapper.registerModule(module);
return mapper.writeValueAsBytes(object);
}
导致具有 WRITE_ONLY
访问权限的字段被忽略(原因很明显)。所以在序列化对象中,我看到 publicCertificate
和 privateCertificate
.
我试过设置mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)
有没有其他方法可以忽略单元测试的这些属性?
已通过为 JUnit 测试添加自定义序列化程序解决此问题。
所以对于 TestDTO
我添加了序列化程序如下。
private class TestJsonSerializer extends StdSerializer<TestDTO> {
public TestJsonSerializer() {
this(null);
}
public TestJsonSerializer(Class<TestDTO> t) {
super(t);
}
@Override
public void serialize(TestDTO value, JsonGenerator gen, SerializerProvider provider) throws IOException {
gen.writeStartObject();
gen.writeNumberField("orgId", value.getOrgId());
gen.writeStringField("certificateType", value.getCertificateType().getType());
if (value.getPublicCertificate() != null) {
gen.writeObjectField("publicCertificate", value.getPublicCertificate());
}
if (value.getPrivateCertificate() != null) {
gen.writeObjectField("privateCertificate", value.getPrivateCertificate());
}
gen.writeObjectField("expiryDate", value.getExpiryDate());
gen.writeObjectField("createdDate", value.getCreatedDate());
gen.writeObjectField("updatedDate", value.getUpdatedDate());
gen.writeEndObject();
}
}
然后我补充说,
ObjectMapper mapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(TestDTO.class, new TestJsonSerializer());
mapper.registerModule(simpleModule);
类似地为嵌套对象添加和注册了自定义序列化程序,publicCertificate
和 privateCertificate
。
虽然指定的解决方案有效,但对于要求来说有点过分了。如果您只想覆盖注释,则不需要自定义序列化程序。杰克逊有一个 mixin feature 如此微不足道的要求
考虑以下简化的 POJO:
public class TestDTO
{
public String regularAccessProperty;
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
public String writeAccessProperty;
}
如果你想覆盖 @JsonProperty
注释,你创建另一个 POJO,它有一个变量 完全相同的名称 (或相同的 getter/setter 名称):
// mixin class that overrides json access annotation
public class UnitTestDTO
{
@JsonProperty(access = JsonProperty.Access.READ_WRITE)
public String writeAccessProperty;
}
您通过简单模块将原始 POJO 和混入相关联:
simpleModule.setMixInAnnotation(TestDTO.class, UnitTestDTO.class);
举个简单的例子
@ToString
@Getter
@Setter
public class Account implements Cloneable {
@JsonProperty(access = Access.WRITE_ONLY)
private Integer accountId;
private String accountType;
private Long balance;
public AccountTest clone() {
AccountTest test = new AccountTest();
test.setAccountId(this.accountId);
test.setAccountType(this.accountType);
test.setBalance(this.balance);
return test;
}
}
@ToString
@Getter
@Setter
public class AccountTest {
private Integer accountId;
private String accountType;
private Long balance;
}
public static void main(String[] args) {
ObjectMapper mapper = new ObjectMapper();
try {
Account account = new Account();
account.setAccountId(1999900);
account.setAccountType("Saving");
account.setBalance(2433l);
AccountTest accountTest = account.clone();
System.out.println(account);
byte[] accountBytes = mapper.writeValueAsBytes(account);
System.out.println(new String(accountBytes));
byte[] accountTestBytes = mapper.writeValueAsBytes(accountTest);
System.out.println(new String(accountTestBytes));
} catch (IOException e) { }
}
}
Is there any other way to ignore these properties for Unit Tests ?
解决方法:在你的convertObjectToJsonBytes
方法中,你可以使用:
mapper.disable(MapperFeature.USE_ANNOTATIONS);
参考: MapperFeature.USE_ANNOTATIONS
/**
* Feature that determines whether annotation introspection
* is used for configuration; if enabled, configured
* {@link AnnotationIntrospector} will be used: if disabled,
* no annotations are considered.
*<p>
* Feature is enabled by default.
*/
USE_ANNOTATIONS(true),
注意: 这将禁用给定 ObjectMapper
.