Java 忽略单元测试的Jackon-JsonProperty访问

Java 忽略单元测试的Jackon-JsonProperty访问,java,json,unit-testing,jackson,objectmapper,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 UUI

我使用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);
}
导致仅具有写入权限的字段被忽略(原因很明显)。因此,在序列化对象中,我看到
publicCertificate
privateCertificate
的空值

我确实尝试过设置
mapper.setVisibility(PropertyAccessor.FIELD,jsonautodect.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();
    }
}

类似地,为嵌套对象添加并注册了自定义序列化程序,
publicCertificate
privateCertificate

,虽然指定的解决方案可以工作,但对于需求来说,这是一种过分的要求。如果您只想覆盖注释,则不需要自定义序列化程序。Jackson对这些琐碎的要求有一个很好的解释

考虑以下简化的POJO:

public class TestDTO
{
    public String regularAccessProperty;
    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
    public String writeAccessProperty;
}
如果要覆盖
@JsonProperty
注释,请创建另一个POJO,该POJO具有与完全相同的名称(或相同的getter/setter名称):

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

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;
}
}

}

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

解决方案:
convertObjectToJsonBytes
方法中,您可以使用:

mapper.disable(MapperFeature.USE_ANNOTATIONS);
参考资料:

/**
*用于确定注释是否自省的功能
*用于配置;如果启用,则为已配置
*将使用{@link AnnotationIntrospector}:如果禁用,
*不考虑任何注释。
*
*默认情况下,功能处于启用状态。
*/
使用注释(true),

注意:这将禁用给定
对象映射器的所有注释

将您的标记为解决方案,因为它不太麻烦,无需覆盖JsonProperty注释,并且使用mixin功能,只需使用相同字段的重复DTO,不要在重复DTO的字段上定义任何JsonProperty注释。@YogaGowda,您的注释不清楚。“重复DTO”(具有相同字段和不同名称的类)是什么意思这是一个mixinHi@SharonBenAsher,是的,并且没有在复制文件中的字段上定义任何JsonPropertyDTO@YogaGowda我不知道这是怎么回事,也许你可以用一个例子来启发我们。请用例子代码重新阅读这个问题。问题是关于序列化而不是反序列化Hey@Sharon,我错过了这一点,但我们仍然可以实现序列化而无需混入,看看更新的示例代码,添加克隆方法只是为了方便测试。不需要克隆。因此,此解决方案需要创建一个具有原始属性的相同类,并对其进行复制,这需要额外的开发(克隆可能并不总是足够的)以及对运行时性能的影响。我的解决方案要求创建一个只包含需要在json注释中更改的属性的类。就这样,没有克隆或复制。只有json注释的“成本”。至少每个解决方案都有利弊。现在,想象一个具有200个属性的类。在我的解决方案中,很明显需要mixin的区别是什么。在您的解决方案中,开发人员很难收集这两个庞然大物类之间的差异。此外,设想一个类随着每个软件版本的变化而变化,随着产品需求的变化而添加/删除属性。您的解决方案需要每次重复这些更改。坦白地说,我一点也不觉得你的解决方案有什么好处。我喜欢这个!
@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) { }

    }
mapper.disable(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),