忽略Jackon JsonProperty访问单元测试

时间:2017-03-13 23:15:54

标签: java json unit-testing jackson objectmapper

我使用Jackson在Spring Boot项目中进行序列化/反序列化。

我有一个具有以下结构的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访问权限的字段被忽略(原因很明显)。因此,在序列化对象中,我看到publicCertificateprivateCertificate的空值。

我确实尝试设置mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)

是否有其他方法可以忽略单元测试的这些属性?

4 个答案:

答案 0 :(得分:3)

<块引用>

是否有其他方法可以忽略单元测试的这些属性?

解决方案:在您的 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 的所有注释。

答案 1 :(得分:2)

虽然指定的解决方案有效,但对于该要求来说却是一种过度杀伤力。如果您只想覆盖注释,则不需要自定义序列化程序。杰克逊有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;
}

您通过Simplemodule将原始POJO和mixin关联起来:

simpleModule.setMixInAnnotation(TestDTO.class, UnitTestDTO.class);

答案 2 :(得分:0)

这是通过为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);

为嵌套对象publicCertificateprivateCertificate添加和注册自定义序列化程序。

答案 3 :(得分:-1)

这是一个简单的例子

@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) { }

    }

}