programing

잭슨과의 JSON 필드 복제

stoneblock 2023. 3. 10. 21:02

잭슨과의 JSON 필드 복제

Jackson을 Spring과 연계하여 JSON(디)시리얼라이제이션에 사용하고 있습니다.그러나 필드가 두 번인 경우가 있어 문제가 있습니다.

추상 수업이 있습니다.

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "mimeType")
@JsonSubTypes({
    @JsonSubTypes.Type(value = ImageBookmarkJsonModel.class, name = "image/jpeg"),
    @JsonSubTypes.Type(value = EpubBookmarkJsonModel.class, name = "application/epub+zip")
})
public abstract class AbstractBookmarkJsonModel extends AbstractJsonModel {
    protected String mimeType;
    // Removed other fields for brevity

    public String getMimeType() {
        return mimeType;
    }

    public void setMimeType(String mimeType) {
        this.mimeType = mimeType;
    }

    @Override
    public String toString() {
        ObjectMapper mapper = new ObjectMapper();

        try {
            return mapper.writeValueAsString(this);
        } catch (IOException e) {
            throw new IllegalStateException("Cannot convert object of type " + this.getClass().toString() + " to JSON", e);
        }
    }
}

구체적인 클래스는 추상적인 내용을 확장합니다.

public class EpubBookmarkJsonModel extends AbstractBookmarkJsonModel {
    private static final long serialVersionUID = 1L;
    // Removed other fields for brevity

    public EpubBookmarkJsonModel() {
        this.mimeType = "application/epub+zip";
    }
}

문제는 이 JSON을 시리얼화하면 중복이 발생한다는 것입니다.mimeType필드:

{
  "mimeType": "application/epub+zip",
  "mimeType": "application/epub+zip",
  "userId": 24,
  "acid": "ACID-000000000029087",
  "added": "2013-08-14T12:02:17Z",
  "epubBookmarkId": 34,
  "cfi": "epubcfi(/6/4!/2/68)",
  "context": "CONTEXT"
}

이전 계약자의 추천을 사용하여@JsonAutoDetect클래스 필드만 사용하도록 지정하는 주석과 클래스 필드 설정ObjectMapper단, 이것으로 문제가 해결되지는 않습니다.

주석:

@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE,
        setterVisibility = JsonAutoDetect.Visibility.NONE, creatorVisibility = JsonAutoDetect.Visibility.NONE,
        isGetterVisibility = JsonAutoDetect.Visibility.NONE)

오브젝트 맵퍼:

    ObjectMapper mapper = new ObjectMapper();
    mapper.getSerializationConfig().getDefaultVisibilityChecker()
            .withFieldVisibility(JsonAutoDetect.Visibility.ANY)
            .withGetterVisibility(JsonAutoDetect.Visibility.NONE)
            .withSetterVisibility(JsonAutoDetect.Visibility.NONE)
            .withCreatorVisibility(JsonAutoDetect.Visibility.NONE);

이 문제를 해결하려면JsonTypeInfo.As.EXISTING_PROPERTY@JsonTypeInfo 주석으로 지정합니다.

이 프로젝트는 오픈 소스입니다.여기에서 확인하세요: ANS.java

중복 출력에 대해 똑같은 문제가 발생했습니다.다른 속성을 포함하지 않는 솔루션을 찾아 원래 속성을 제거하지 않도록 했습니다.먼저 JsonTypeInfo의 표시 플래그를 true로 설정합니다.그런 다음 속성 선언과 getter(세터가 아닌)에 JsonIgnore 주석을 추가했습니다.이것은 지금까지 타입 속성의 키를 1개만 사용하여 JSON을 올바르게 출력하고 있습니다.

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, visible = true, property = "mimeType")
@JsonSubTypes({
    @JsonSubTypes.Type(value = ImageBookmarkJsonModel.class, name = "image/jpeg"),
    @JsonSubTypes.Type(value = EpubBookmarkJsonModel.class, name = "application/epub+zip")
})
public abstract class AbstractBookmarkJsonModel extends AbstractJsonModel {
    @JsonIgnore
    @JsonProperty("mimeType")
    protected String mimeType;

    @JsonIgnore
    @JsonProperty("mimeType")
    public String getMimeType() {
        return mimeType;
    }

    @JsonProperty("mimeType")
    public void setMimeType(String mimeType) {
        this.mimeType = mimeType;
    }

}

주의: 이것은 fasterxml jackson-databind 2.1.1 입니다.

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.1.1</version>
</dependency>

이 동작은 클래스에 배치된 주석으로 인해 발생합니다.AbstractBookmarkJsonModel:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "mimeType")
@JsonSubTypes({
    @JsonSubTypes.Type(value = ImageBookmarkJsonModel.class, name = "image/jpeg"),
    @JsonSubTypes.Type(value = EpubBookmarkJsonModel.class, name = "application/epub+zip")
})

@JsonTypeInfo는, 잭슨에게 논리 타입명을 시리얼 하도록 지시합니다(JsonTypeInfo.Id.NAME속성( )JsonTypeInfo.As.PROPERTY이름 포함)mimeType(property = "mimeType")와 함께@JsonSubTypes.Type논리명을 할당합니다.application/epub+zip로.EpubBookmarkJsonModel.

시리얼라이제이션의 경우 잭슨은 논리명을 속성으로 시리얼라이제이션 합니다.mimeType = "application/epub+zip"그리고 그들 중 물체의 특성.mimeType논리명과 같은 값을 가지고 있습니다.application/epub+zip(컨스트럭터에 추가).

생각합니다mimeType로 변경되어야 한다objectType에서@JsonTypeInfo주석 또는 더 나은 주석 제거mimeType잭슨이 유형 정보 연재를 통해 처리할 것이기 때문입니다.

이 케이스는 Jacson lib의 레거시 버전만으로 해결됩니다.@JsonProperty(value = "Your_CUSTOM_Name")들판에서 게터까지.

같은 문제가 있었어.우리는 Lombok을 사용하고 있고, 나는 @JsonProperty 액세스로 이 작업을 얻었다.

  @Getter
  @Setter
  @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) // Prevents duplication when serializing to JSON (subtype discriminator property)
  private RuleType ruleType;

이 솔루션이 마음에 드는 이유는 다음과 같습니다.

  • 다른 lib에 의존하지 않음
  • 데이터 모델을 변경할 필요가 없었습니다.
  • Lombok과 연동 (정돈 없음)

예, 속성을 채우려면 visible=true가 필요합니다.우리의 경우 동작 디스패치 기능이 있는 Enum이기 때문에 목적에 꼭 필요하고 Json의 아형 판별에도 사용할 수 있다는 것은 매우 좋은 일입니다.

@JsonTypeInfo(
  use = JsonTypeInfo.Id.NAME,
  property = "ruleType",
  visible = true)

언급URL : https://stackoverflow.com/questions/18237222/duplicate-json-field-with-jackson