0

일부 Jackson 다형성 문제로 붙어 있습니다.Jakson 다형성 열거 형 케이스

웹 JDR 캐릭터 편집기 개인 프로젝트에서 작업합니다. 나는 스프링 부트를 사용하고 철학을 고수하려고 노력한다. 게다가, 나는 실제 작업을위한 연구 케이스 (다른 springboot 프로젝트) 때문에 독립 패키지를 만들려고한다.

잭슨 구성이 없으므로 Competence의 serialization에는 아무런 문제가 없습니다. 그러나 웹 에디터에서 수정을 시도 할 때 Jackson이 Competence의 비 직렬화를 수행 할 때 "종속성"속성에 문제가 발생합니다.

내가 직렬화하려고 한/역 직렬화 :

public interface AttributTemplate extends ComposanteTemplate {}

두 개의 서브 클래스 : 나는 문제가

public class Competence implements Composante, ComposanteTemplate { 

    public enum Categorie { 
     APPRENTI, 
     COMPAGNON 
    } 

    private String nom; 
    private String description; 
    private Categorie categorie; 
    private Chapitre chapitre; 
    private AttributTemplate dependance; 
    private List sousCompetences = new ArrayList(); 

    public String getNom() { 
     return nom; 
    } 

    public void setNom(String nom) { 
     this.nom = nom; 
    } 

    public String getDescription() { 
     return description; 
    } 

    public void setDescription(String description) { 
     this.description = description; 
    } 

    public Competence getTemplate() { 
     return this; 
    } 

    public Categorie getCategorie() { 
     return categorie; 
    } 

    public void setCategorie(Categorie categorie) { 
     this.categorie = categorie; 
    } 

    public Chapitre getChapitre() { 
     return chapitre; 
    } 

    public void setChapitre(Chapitre chapitre) { 
     this.chapitre = chapitre; 
    } 

    public AttributTemplate getDependance() { 
     return dependance; 
    } 

    public void setDependance(AttributTemplate dependance) { 
     this.dependance = dependance; 
    } 

    public List getSousCompetences() { 
     return sousCompetences; 
    } 

    public void setSousCompetences(List sousCompetences) { 
     this.sousCompetences = sousCompetences; 
    } 

    public boolean isOuverte() { 
     return !sousCompetences.isEmpty(); 
    } 
}

속성의 슈퍼 클래스 다음

내 클래스입니다 능력 # 의존성 재산을 위해 사용될 수있는 :

public enum Carac implements AttributTemplate, Attribut { 

    FORT(Type.PHYSIQUE), 
    AGILE(Type.PHYSIQUE), 
    RESISTANT(Type.PHYSIQUE), 
    OBSERVATEUR(Type.PHYSIQUE), 
    SAVANT(Type.MENTALE), 
    RUSE(Type.MENTALE), 
    TALENTUEUX(Type.MENTALE), 
    CHARMEUR(Type.MENTALE); 

    public enum Type { 
     PHYSIQUE, 
     MENTALE 
    } 

    public final Type type; 
    public final String nom = name().toLowerCase(); 

    private String description; 

    Carac(Type type) { 
     this.type = type; 
    } 

    @Override 
    public String getNom() { return nom; } 

    @Override 
    public String getDescription() { return description; } 

    @Override 
    public Carac getTemplate() { return this; } 

    public void setDescription(String description) { this.description = description; } 

}
public enum ArtTemplate implements AttributTemplate { 

    ART_GUERRIER(2, 1), 
    ART_ETRANGE(1, 2), 
    ART_GUILDIEN(1, 1); 

    public static final String ART_PREFIX = "ART"; 

    public final String nom = name().toLowerCase().replace("_", " "); 
    public final int nbCaracsPhysiques; 
    public final int nbCaracsMentales; 

    private String description; 

    ArtTemplate(int nbCaracsPhysiques, int nbCaracsMentales) { 
     this.nbCaracsMentales = nbCaracsMentales; 
     this.nbCaracsPhysiques = nbCaracsPhysiques; 
    } 

    @Override 
    public String getNom() { 
     return nom; 
    } 

    @Override 
    public String getDescription() { 
     return description; 
    } 

    public void setDescription(String description) { 
     this.description = description; 
    } 

    public int getNbCaracs() { 
     return nbCaracsPhysiques + nbCaracsMentales; 
    } 

}

결과를 JSON (그리고 나는 보내는 JSON)입니다 :

{"nom":"Comp_1489746646510","description":"ezbuixnwrclfvmgwdviubcauenzytpzzvumnohwyhpuynxaqhkjdbqygtrmbtlschthovuyoiolkauucwokkfjnaujnufshrjboykuqce","categorie":"APPRENTI","chapitre":"GUERRE","dependance":"ART_ETRANGE","ouverte":false,"sousCompetences":[]}

질문 : 나는 내 문제는 추상적 인 관계 AttributTemplate에 의해 발생을 이해하고 잭슨하려고 할 때 deserialize, 그는 Carac 또는 ArtTemplate 클래스 중 어느 클래스를 사용할 지 알지 못합니다. 나는 변함없는 역량 (능력은 외부 항아리에서 왔음)을 유지하려고하므로,이 등급에 대한 주석이 가능하지 않습니다. 내가 찾은 솔루션 (Jackson 1.5: Polymorphic Type Handling, first steps)와 일했다 유일한 많이 시도했습니다

는 DeserializationProblemHandler

mapper.addHandler(new DeserializationProblemHandler() { 
@Override 
public Object handleMissingInstantiator(DeserializationContext ctxt, Class<?> instClass, JsonParser p, String msg) throws IOException { 
    if (instClass == AttributTemplate.class) { 
     String name = p.getText(); 
     return !name.startsWith(ArtTemplate.ART_PREFIX) ? Carac.valueOf(name) : ArtTemplate.valueOf(name); 
    } 
    return super.handleMissingInstantiator(ctxt, instClass, p, msg); 
} 
을 정의하는 것이었다

});

그러나 나는이 해결책으로 나쁘다고 느낍니다. 다른 아름다운 것이 있다고 확신하기 때문입니다.

그래서 AttributTemplate을 얻기 위해 Carac 또는 ArtTemplate을 사용해야하는지 판단 할 수 있도록 매퍼를 구성 할 수 있습니까?


편집 : 당신이 난 볼 수있는 것처럼이 같은 매퍼

 
    abstract class CompetenceMixIn { 

     private AttributTemplate dependance; 

     @JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.EXISTING_PROPERTY, property="dependance") 
     @JsonSubTypes({ @JsonSubTypes.Type(value = Carac.class, name = "carac"), @JsonSubTypes.Type(value = ArtTemplate.class, name = "artTemplate") }) 
     public void setDependance(AttributTemplate dependance) { 
      this.dependance = dependance; 
     } 
    }
ObjectMapper mapper = jsonConverter.getObjectMapper(); 
mapper.addMixIn(Competence.class, CompetenceMixIn.class);

을 구성하여

{"nom":"Comp_1489756873433","description":"kruzueemlwisibshlkotasayfkhdqkqolvhlqgsnntndkpvbmmgklqysabiakaolempmupeyiqaztdcrhwimdksgzybbdzttwnwqjxhfo","categorie":"COMPAGNON","chapitre":"GUERRE","dependance":["mova.ged.perso.inne.Carac","AGILE"],"ouverte":true,"sousCompetences":[...]}

: 나는 이것을 가지고 관리 를 감싸는 배열로 아직도 parasited값. 나는 (...)"dependance": "AGILE", (...)이 아닐 것이다 (...)"dependance":["mova.ged.perso.inne.Carac", "AGILE"], (...)
그리고 나는 이것을 가지고 있기 위해 무엇을 바꿀 지 모른다.

+0

이전에 비슷한 질문에 대답했습니다. Jackson은 이것을 구성 할 수 있습니다.귀하의 특정 사건에 대해 이것을 재발견하고 싶지 않으므로 여기를 참고하십시오 : http://stackoverflow.com/questions/38501574/rules-for-jersey-to-parse-json-jackson-subtype-deserialisation/ 38523801 # 38523801 예제는 매우 간단합니다. Params 클래스에는 2 개의 구현이 있고 그것을 재 직렬화하는 방법을 찾기 위해 사용할 속성을 jackson에게 전합니다. – pandaadb

+0

예제를 시도하지만 여전히 실제 솔루션을 찾을 수 없습니다. 나는 당신 덕분에 발견 된 해결책의 시작 부분에서 나의 글을 수정했다. – Mohicane

+0

아직도 문제가 .... 나는 나에게 그렇게 단순한 것처럼 보이는 그런 문제가 있다고 상상할 수 없다 ?? – Mohicane

답변

1

나는 당신이하려는 것을 조사해 왔습니다. 유감스럽게도 Enums + 상속에 문제가 있다고 생각합니다.

사용자 지정 작성자를 사용하고 알 수없는 속성을 무시하는 대신 사용할 수있는 대체 솔루션이 있습니다. 다음 예제를 참조하십시오 :

public class JacksonInheritance { 

    public static void main(String[] args) throws IOException { 
     ObjectMapper mapper = new ObjectMapper(); 

     Competence c = new Competence(); 
     c.desc = "desc"; 
     c.nome = "nome"; 
     c.template = Att1.TEST_Att1; 
     String test = mapper.writeValueAsString(c); 
     System.out.println(test); 

     Competence readValue = mapper.readValue(test, Competence.class); 
     System.out.println(readValue.template); 
    } 

    @JsonIgnoreProperties(ignoreUnknown = true) 
    public static class Competence { 

     private static final Map<String, AttributeTemplate> templates; 
     static { 
      templates = new HashMap<>(); 
      Stream.of(Att1.values()).forEach(a -> templates.put(a.name(), a)); 
      Stream.of(Att2.values()).forEach(a -> templates.put(a.name(), a)); 
     } 

     @JsonProperty 
     String nome; 
     @JsonProperty 
     String desc; 
     @JsonIgnore 
     AttributeTemplate template; 

     @JsonProperty("template_type") 
     public String getTempl() { 
      // Here you can do whichever way uou would like to serialise your template. This will be the key 
      return template.toString(); 
     } 

     @JsonCreator 
     public static Competence create(@JsonProperty("template_type") String templateType) { 
      Competence c = new Competence(); 
      c.template = templates.get(templateType); 
      return c; 
     } 
    } 

    public static interface AttributeTemplate { 
    } 

    public static enum Att1 implements AttributeTemplate { 
     TEST_Att1; 
    } 

    public static enum Att2 implements AttributeTemplate { 

     TEST2_Att2; 
    } 
} 

여기에서 저는 Jackson 논리에서 열거 로직을 분리하고 있습니다. 사용자 지정 직렬화가 필요하지 않습니다.

나는 기본적으로 내 열거 형을 값으로 serialize한다고 말합니다. (당신은 분명히 어떤 속성을 원하는지 선택할 수 있습니다). 지금은 정보가 나는 template_type 속성에서 올바른 열거 템플릿 유형을 구성 할 필요가 있음을 알고

{"template_type":"TEST_Att1","nome":"nome","desc":"desc"} 

반환 단계 :로

내 출력 JSON은 보인다. 이것은 내 공장 방법 create에 주입 할 수있는 것입니다.

생성시 내 정적으로 생성 된 맵을 사용하여 개체에 올바른 열거 형을 채울 수 있습니다. 열거 형은 유한하고 정적이어서이 맵을 정적으로 만들 수 있습니다.

이것의 아름다움은 생성기가 생성에만 사용된다는 것입니다. @JsonIgnoreProperties(ignoreUnknown = true)을 사용하면 jackson에게 json의 모든 사용자 정의 요소에 의해 괴롭히지 않을 것이라고 말할 수 있습니다. 우리는 열거 형 해상도로 사용자 정의 template_type을 사용하기 때문에 감지 할 수 있고 다른 필드를 남겨 둘 수있는 필드를 비 순차적으로 단순화합니다.

마지막으로, 잭슨이 그걸 만들 수 없기 때문에 마지막으로 내 콩에서 실제 template을 무시합니다.

나는 당신이/당신을 위해 효과가 있기를 바랍니다. 지연에 대해 유감스럽게 생각합니다. 상속을 사용하지 않는

이유 :

  1. 는 잭슨의 열거 + 상속 문제가 될 것 같다. 특히 jackson은 기본적으로 리플렉션을 사용하고 생성을 위해 열거 형의 전용 생성자를 호출합니다. 위와 비슷한 방법으로 제작자를 만들 수 있습니다.

  2. 비 직렬화는 템플릿을 필요로합니다. 나는 열거 형의 모든 요소를 ​​반드시 직렬화하고 싶지는 않다는 가정을 할 것이다. 내 이름이 TEST_Att1 인 enum 이름이 enum을 고유하게 만들기 때문입니다. 이러한 열거 형의 모든 다른 속성을 직렬화하고 보낼 필요가 없습니다. 그러나 Deserialization with @JsonSubTypes for no value - missing property error은 jackson이 최소한 템플릿 필드를 필요로한다는 것을 보여줍니다. 이 위해 외부 속성을 사용할 수 있기 때문이 최선의 해결책이 될 수 없습니다

대신 (단지 잭슨을 행복하게하기 위해 JSON에 제안 왜 널 필드를 포함), AA 약간의 문제입니다 , 그러나 나는 그것이 제한을 받으면서 비교적 우아하다라고 생각한다. 도움이 되었으면 좋겠습니다.

Artur

+0

compentance 클래스를 변경할 수 없다면 클래스를 확장하고 해당 클래스에 jsoncreator를 추가 할 수 있습니다. 그 옵션이 아닌 경우, 나는 원래 제시된 귀하의 솔루션이 완벽하게 훌륭하다고 생각합니다 – pandaadb

+0

귀하의 옵션을 시도하겠습니다. 그러나 저는 제 직업에 의해 독점되어 있습니다. – Mohicane

+0

마침내 (이 모든 시간 이후!) 귀하의 솔루션을 사용해보십시오. 앞서 말했듯이 필자는 Competence 클래스를 수정할 수 없습니다. 그런 다음 MixIn 가능성을 사용하여 주석과 작성자를 추가합니다. 그러나 제작자가 이런 식으로 사용하지 않는 것 같습니다. – Mohicane