Jackson은 'is'를 제거하여 기본 부울 필드의 이름을 바꿉니다.


93

중복 일 수 있습니다. 그러나 내 문제에 대한 해결책을 찾을 수 없습니다.

나는 수업이있다

public class MyResponse implements Serializable {

    private boolean isSuccess;

    public boolean isSuccess() {
        return isSuccess;
    }

    public void setSuccess(boolean isSuccess) {
        this.isSuccess = isSuccess;
    }
}

Getter 및 Setter는 Eclipse에서 생성됩니다.

다른 클래스에서 값을 true로 설정하고 JSON 문자열로 씁니다.

System.out.println(new ObjectMapper().writeValueAsString(myResponse));

JSON에서 키는 {"success": true}.

isSuccess자체를 원합니다 . 직렬화 중에 Jackson이 setter 메서드를 사용하고 있습니까? 키를 필드 이름 자체로 만드는 방법은 무엇입니까?


1
귀하의 속성 이름이 liek 인 경우 isSuccess메서드 이름은 isIsSuccess내가 생각 해야합니다
Jens

이해 했어요. SetSuccess Eclipse에서 생성 한 것이 더 낫다고 생각했습니다 . (표준에
따름

답변:


119

이것은 약간 늦은 답변이지만이 페이지를 방문하는 다른 사람에게 유용 할 수 있습니다.

Jackson이 JSON으로 직렬화 할 때 사용할 이름을 변경하는 간단한 해결책은 @JsonProperty 주석 을 사용하는 것이므로 예제는 다음과 같습니다.

public class MyResponse implements Serializable {

    private boolean isSuccess;

    @JsonProperty(value="isSuccess")        
    public boolean isSuccess() {
        return isSuccess;
    }

    public void setSuccess(boolean isSuccess) {
        this.isSuccess = isSuccess;
    }
}

그런 다음 JSON으로 직렬화 {"isSuccess":true}되지만 getter 메서드 이름을 수정할 필요가 없다는 이점이 있습니다.

이 경우 @JsonProperty("isSuccess")단일 value요소 만 있으므로 주석을 작성할 수도 있습니다.


이 방법은 타사 종속성에서 비롯된 클래스이므로 내 소유가 아니기 때문에 내 경우에는 작동하지 않습니다. 이러한 경우 아래 내 대답을 참조하십시오.
edmundpie 19.11.

4
나는 jackson과 함께 스프링 부트를 사용하고 있지만 두 개의 필드를 얻는 것은 "성공"이고 다른 하나는 "isSuccess"이고 하나의 필드 "isSuccess"보다 원시적 인 부울을 사용하지 않을 때
Vishal Singla

@VishalSingla 동일한 문제가 있습니다.이 솔루션은 Spring Boot에서 두 개의 필드를 생성합니다
Aron Fiechter

22

나는 최근 에이 문제를 만났고 이것이 내가 찾은 것입니다. Jackson은 getter 및 setter에 대해 전달하는 모든 클래스를 검사하고 직렬화 및 역 직렬화에 해당 메서드를 사용합니다. 이러한 메소드에서 "get", "is"및 "set"뒤에 오는 것은 JSON 필드의 키로 사용됩니다 (getIsValid 및 setIsValid의 경우 "isValid").

public class JacksonExample {   

    private boolean isValid = false;

    public boolean getIsValid() {
        return isValid;
    }

    public void setIsValid(boolean isValid) {
        this.isValid = isValid;
    }
} 

유사하게 "isSuccess"는 "isIsSuccess"또는 "getIsSuccess"로 이름이 변경되지 않는 한 "success"가됩니다.

여기에서 더 읽기 : http://www.citrine.io/blog/2015/5/20/jackson-json-processor


6
isValid는 Java의 부울 데이터 유형에 대한 올바른 명명 규칙이 아닙니다. 유효해야하며 isValid (), setValid ()
vels4j

2
하지만 정확히 그럴 필요가 없나요? 컨벤션? 존재하는 경우 JSON 필드로 getter 이름을 사용하는 Jackson 참조에 연결할 수 있습니까? 아니면 잘못된 디자인 선택이라고 생각하십니까?
Abhinav Vishak

2
나는 이것에 대한 경고가 있었다 소원
RyPope

@ vels4j 명명 규칙은 매우 구체적인 구현을 다룰 때 창 밖으로 나갑니다.
Dragas

13

아래의 두 주석을 모두 사용하면 출력 JSON에 다음이 포함됩니다 is_xxx.

@get:JsonProperty("is_something")
@param:JsonProperty("is_something")

이것이이 질문에 대한 최선의 대답입니다.
dustinevan 19.11.22

1
그게 자바인가요? 어쩌면 Kotlin일까요?
spottedmahn

5

ObjectMapper다음과 같이 구성 할 수 있습니다 .

mapper.setPropertyNamingStrategy(new PropertyNamingStrategy() {
            @Override
            public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName)
            {
                if(method.hasReturnType() && (method.getRawReturnType() == Boolean.class || method.getRawReturnType() == boolean.class)
                        && method.getName().startsWith("is")) {
                    return method.getName();
                }
                return super.nameForGetterMethod(config, method, defaultName);
            }
        });

1
구성을 통해이 문제를 해결하려는 것이 좋습니다. 그러나 이것은 항상 부울 필드와 JSON 속성에 "is"를 접두사로 지정하는 경우에만 작동합니다 . 직렬화하려는 "enabled"라는 이름의 또 다른 부울 필드가 있다고 가정합니다. 생성 된 메소드가 "isEnabled ()"이기 때문에 위의 코드는 "enabled"대신 "isEnabled"로 직렬화합니다. 궁극적으로 문제는 "x"및 "isX"필드 모두에 대해 Eclipse가 "isX ()"메서드를 생성한다는 것입니다. 따라서 필드와 일치하는 속성 이름을 유추 할 수 없습니다.
David Siegal 19

@DavidSiegal base on burak answer 그런 경우를 지원하기 위해 아래 답변을 확장했습니다.
edmundpie 19.11.22

4

Kotlin 및 데이터 클래스를 사용하는 경우 :

data class Dto(
    @get:JsonProperty("isSuccess") val isSuccess: Boolean
)

@param:JsonProperty("isSuccess")JSON도 역 직렬화 하려는 경우 추가해야 할 수 있습니다 .


2

Utkarsh의 대답을 기반으로 구축 ..

get / is를 제외한 Getter 이름 이 JSON 이름으로 사용됩니다.

public class Example{
    private String radcliffe; 

    public getHarryPotter(){
        return radcliffe; 
    }
}

{ "harryPotter": "whateverYouGaveHere"} 로 저장됩니다 .


Deserialization의 경우 Jackson은 setter와 필드 이름을 모두 확인합니다. Json String { "word1": "example"}의 경우 아래 두 가지 모두 유효합니다.

public class Example{
    private String word1; 

    public setword2( String pqr){
        this.word1 = pqr; 
    }
}

public class Example2{
    private String word2; 

    public setWord1(String pqr){
        this.word2 = pqr ; 
    }
}

더 흥미로운 질문은 Jackson이 deserialization을 위해 고려하는 순서입니다. { "word1": "myName"}을 다음같이 deserialize하려고하면

public class Example3{
    private String word1;
    private String word2; 

    public setWord1( String parameter){
        this.word2 = parameter ; 
    }
}

위의 경우를 테스트하지는 않았지만 word1 & word2 의 값을 보는 것은 흥미로울 것입니다 .

참고 : 어떤 필드가 동일해야하는지 강조하기 위해 완전히 다른 이름을 사용했습니다.


1

이 문제에 대한 또 다른 방법이 있습니다.

새 하위 클래스를 정의하면 PropertyNamingStrategy가 확장되고 ObjectMapper 인스턴스에 전달됩니다.

다음은 더 많은 도움이 될 수있는 코드 스 니펫입니다.

mapper.setPropertyNamingStrategy(new PropertyNamingStrategy() {
        @Override
        public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) {
            String input = defaultName;
            if(method.getName().startsWith("is")){
                input = method.getName();
            }

            //copy from LowerCaseWithUnderscoresStrategy
            if (input == null) return input; // garbage in, garbage out
            int length = input.length();
            StringBuilder result = new StringBuilder(length * 2);
            int resultLength = 0;
            boolean wasPrevTranslated = false;
            for (int i = 0; i < length; i++)
            {
                char c = input.charAt(i);
                if (i > 0 || c != '_') // skip first starting underscore
                {
                    if (Character.isUpperCase(c))
                    {
                        if (!wasPrevTranslated && resultLength > 0 && result.charAt(resultLength - 1) != '_')
                        {
                            result.append('_');
                            resultLength++;
                        }
                        c = Character.toLowerCase(c);
                        wasPrevTranslated = true;
                    }
                    else
                    {
                        wasPrevTranslated = false;
                    }
                    result.append(c);
                    resultLength++;
                }
            }
            return resultLength > 0 ? result.toString() : input;
        }
    });

1

사용자 지정 명명 전략을 엉망으로 만들고 일부 접근자를 다시 만들고 싶지 않았습니다.
코드가 적을수록 더 행복해집니다.

이것은 우리를 위해 트릭을했습니다.

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

@JsonIgnoreProperties({"success", "deleted"}) // <- Prevents serialization duplicates 
public class MyResponse {

    private String id;
    private @JsonProperty("isSuccess") boolean isSuccess; // <- Forces field name
    private @JsonProperty("isDeleted") boolean isDeleted;

}

1

수락 된 답변이 제 경우에는 작동하지 않습니다.

제 경우 수업은 제가 소유 한 것이 아닙니다. 문제가있는 클래스는 타사 종속성에서 비롯되었으므로 @JsonProperty주석을 추가 할 수는 없습니다 .

위의 @burak 답변에서 영감을 받아이를 해결하기 위해 PropertyNamingStrategy다음과 같은 사용자 지정 을 만들었습니다 .

mapper.setPropertyNamingStrategy(new PropertyNamingStrategy() {
  @Override
  public String nameForSetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName)
  {
    if (method.getParameterCount() == 1 &&
            (method.getRawParameterType(0) == Boolean.class || method.getRawParameterType(0) == boolean.class) &&
            method.getName().startsWith("set")) {

      Class<?> containingClass = method.getDeclaringClass();
      String potentialFieldName = "is" + method.getName().substring(3);

      try {
        containingClass.getDeclaredField(potentialFieldName);
        return potentialFieldName;
      } catch (NoSuchFieldException e) {
        // do nothing and fall through
      }
    }

    return super.nameForSetterMethod(config, method, defaultName);
  }

  @Override
  public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName)
  {
    if(method.hasReturnType() && (method.getRawReturnType() == Boolean.class || method.getRawReturnType() == boolean.class)
        && method.getName().startsWith("is")) {

      Class<?> containingClass = method.getDeclaringClass();
      String potentialFieldName = method.getName();

      try {
        containingClass.getDeclaredField(potentialFieldName);
        return potentialFieldName;
      } catch (NoSuchFieldException e) {
        // do nothing and fall through
      }
    }
    return super.nameForGetterMethod(config, method, defaultName);
  }
});

기본적으로 이것이하는 일은 직렬화 및 역 직렬화하기 전에 대상 / 소스 클래스에서 어떤 속성 이름이 클래스에 있는지 isEnabled또는 enabled속성 인지 확인하는 것입니다 .

이를 기반으로 매퍼는 존재하는 속성 이름으로 직렬화 및 역 직렬화합니다.


0

기본 부울을 java.lang.Boolean으로 변경할 수 있습니다 (+ 사용 @JsonPropery).

@JsonProperty("isA")
private Boolean isA = false;

public Boolean getA() {
    return this.isA;
}

public void setA(Boolean a) {
    this.isA = a;
}

나를 위해 훌륭하게 일했습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.