2013-05-02 8 views
3

내가 방법을 찾을려고하는 JSON 동등한 JAXB/목시 주석 클래스 올바르게 지도 다음 XML/JSON 문서합니다. 내 예에있는 사람을 설명하는 문서의 모델 요소가 자유 것을
주 즉 정적으로 알려져 있지 XML 요소의 모든 종류의/JSON 객체, 수 있습니다.매핑 각종 형태의 XML/목시/JAXB 주석 클래스

XML 문서 :

<form> 
    <title>Person Form</title> 
    <model> 
     <person> 
     <name>John</name> 
     <surname>Smith</surname> 
     <address> 
      <street>Main St.</street> 
      <city>NY</city> 
      <country>USA</country> 
     </address> 
    <person> 
    </model> 
</form> 

등가 JSON 문서 :

{ 
    "title":"Form Title", 
    "model":{ 
     "person":{ 
     "name":"John", 
     "surname":"Smith", 
     "address":{ 
      "street":"Main St.", 
      "city":"NY", 
      "country":"USA" 
     }   
     } 
    } 
} 

가 나는 지도모델 필드를 매핑하는 생각 아마도 기본 타입 또는 지도 자체는입니다. 이 매핑은 내 요구에 충분히 표현할 수 있습니다.

은 내가 @XmlReadTransformer, @XmlWriteTransformer MOXY 주석과 재생 시도했지만 성공하지

@XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) 
public class Form { 
    private String title; 
    private Model model; 
    ....getters and setters.... 
} 

@XmlRootElement 
@XmlAccessorType(XmlAccessType.FIELD) 
public class Model { 

    @XmlElement 
    @XmlReadTransformer(transformerClass = Transformer.class) 
    @XmlWriteTransformers({ @XmlWriteTransformer(xmlPath = "./*", transformerClass = Transformer.class) }) 
    private Map<String, Object> data; 

    public Map<String, Object> getData() { 
     return data; 
    } 

    public void setData(Map<String, Object> data) { 
     this.data = data; 
    } 

    public static class Transformer implements AttributeTransformer, FieldTransformer { 

     private AbstractTransformationMapping tm; 

     public Transformer() { 
     } 

     @Override 
     public void initialize(AbstractTransformationMapping tm) { 
      this.tm = tm; 
     } 

     @Override 
     public Map<String, Object> buildAttributeValue(Record r, Object o, 
       Session s) { 
      Map<String, Object> data = new HashMap<String, Object>(); 
      // TODO: ???? 
      return data; 
     } 

     @Override 
     public Object buildFieldValue(Object arg0, String arg1, Session arg2) { 
// TODO 
      return null; 
     } 

    } 
} 

당신이 나에게의 적절한 방법을 제안 할 수 있습니다 (레코드 매개 변수는 나는 buildAttributeValue 항상 널 얻을) 이 문제 또는 "모델"필드를 모델링하는 다른 방법을 해결 하시겠습니까?

답변

2

런타임에 사용할 수있는 사람 (또는 갖고있는 다른 클래스)이 있습니까? XML/JSON이 어느 클래스에 해당하는지 나타내는 type 속성을 포함하도록 약간 수정 될 수 있습니까? 그래서 여기에 예를 들어 당신에게 도움이 될 수있는 경우 http://blog.bdoughan.com/2012/02/xmlanyelement-and-xmladapter.html

모형은 다음이에서 사용하고있는 당신이 유형을 포함해야이

@XmlAnyElement 
private List<Parameter> data; 

같은 및 링크 된 예에서 ParameterAdapter를 사용하여 속성 것 XML 및 JSON

{ 
    "title" : "Form Title", 
    "model" : { 
     "person" : { 
     "type" : "test.Person", 
     "name" : "John", 
     "surname" : "Smith", 
... 
} 

또는

<form> 
    <title>Person Form</title> 
    <model> 
     <person type="test.Person"> 
     <name>John</name> 
     <surname>Smith</surname> 
... 
</form> 
+0

나는 당신의 제안을 이해하지만 그것이 내 요구에 부합하지 않는다. '모델'입력란은 완전히 동적입니다. 즉, 알 수없는 임의의 XML/JSON입니다 (해당 Java 클래스 없음). 따라서 일반적인 XML/JSON을 객체 지향적 인 방법으로 매핑하는 방법이 필요합니다. 예를 들어 org.w3c.dom.Element (XML) 또는 org.json.JSONObject (JSON)과 같은 것입니다. 그러나 나는 그것을 할 수있는 방법을 찾을 수 없습니다. –

0

ny JAXB (JSR-222) 구현 (EclipseLink MOXy 포함)은 DOM 구조로 정보를 유지할 수 있습니다. XmlAdapter을 사용하여 해당 DOM 구조를지도로 /에서 변환 할 수 있습니다.

(때문에) XmlAdapter (DomMapAdapter) 아래

는 실제로 java.util.Maporg.w3c.dom.Document 사이의 변환을위한 논리를 포함하지 않은 상기 XmlAdapter하는 골격이다.다음은

import java.util.*; 
import javax.xml.bind.annotation.adapters.XmlAdapter; 
import javax.xml.parsers.DocumentBuilderFactory; 
import org.w3c.dom.*; 

public class DomMapAdapter extends XmlAdapter<Object, Map<String, Object>> { 

    private Document document; 

    public DomMapAdapter() { 
     try { 
      document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); 
     } catch(Exception e) { 
      throw new RuntimeException(e); 
     } 
    } 

    @Override 
    public Map<String, Object> unmarshal(Object v) throws Exception { 
     Document document = (Document) v; 
     Map<String, Object> map = new HashMap<String, Object>(); 
     // TODO - Convert Document to Map 
     return map; 
    } 

    @Override 
    public Object marshal(Map<String, Object> v) throws Exception { 
     // TODO - Convert Map to Document 
     return document; 
    } 

} 

모델

당신이 XmlJavaTypeAdapter 주석을 사용하여 XmlAdapter를 지정하는 방법입니다.

import java.util.Map; 
import javax.xml.bind.annotation.*; 
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; 

@XmlRootElement 
@XmlAccessorType(XmlAccessType.FIELD) 
public class Model { 

    @XmlJavaTypeAdapter(DomMapAdapter.class) 
    private Map<String, Object> data; 

} 

내가이 사용 사례를 쉽게 만들 것 다음과 같은 개선 요청을 입력했습니다. 모델은 다음 org.w3c.dom.Node로 데이터를 유지하는 경우

+0

안녕하세요. 나는 이미 그 솔루션을 시도했다. (사실 Docuemnt 대신 Element로 캐스팅했다.) 그러나 XML 문서의 경우에도 작동하지만 JSON 문서를 처리 할 때 예외는 없으므로이 접근 방식을 포기했습니다. 'java.lang.ClassCastException : org.eclipse.persistence.internal.oxm.SAXFragmentBuilder는 org.eclipse.persistence.oxm.record.UnmarshalRecord \t org.eclipse.persistence.internal.oxm.record.json.JSONReader.isTextValue (JSONReader.java:348) ~ [na : na] 에 캐스트하십시오. ... ' –

+0

@MirkoLuchi -보고있는 오류를 재현하지 못했습니다. 오류가 발생하는 동일한 코드와 함께 다음 링크를 사용하여 버그를 입력 할 수 있습니까? : https : //bugs.eclipse.? { "제목": "내 제목", "모델": { "foo는"조직/버그/enter_bug.cgi 제품은 = EclipseLink가 –

+0

는 내가 JSON 모델은 배열을 포함 할 때 예외가 발생하는 것을 발견했다 : [ "bar", "biz" } } 버그를 보내 드리겠습니다. –

2

이 당신을 위해 작동합니다 : 당신이 도움이 될 것입니다 느낌이 어떤 정보를 추가하세요?

@XmlAnyElement 
public Node data; 

그런 다음 목시는이 시나리오를 처리하지만 난 당신이 서식 XML에서 읽은 다음 JSON (출력의 값으로 여분의 줄 바꿈/공백) 밖으로 다시 작성하는 경우 버그가있다 생각합니다. 그러나이 설정으로 제공 한 XML을 읽고 쓸 수 있었고 제공 한 JSON을 읽고 쓸 수있었습니다.

해결 방법에는 한 가지주의 할 점이 있습니다. 현재 JSON 비 정렬 화가 이벤트를보고하는 방식으로 속성과 요소를 구별하려고 시도하고 JSON을 읽고 쓰는 경우 중복 키/값 쌍을 알아 차릴 것입니다. 이 문제 (https://bugs.eclipse.org/bugs/show_bug.cgi?id=407452)에 대한 버그가 있지만 unmarshaller에 UnmarshallerProperties.JSON_ATTRIBUTE_PREFIX 속성을 설정하는 것이 좋습니다.

JSON_ATTRIBUTE_PREFIX가 설정되지 않은 경우 각 키를 요소 및 속성으로보고하여 둘 중 하나와 일치하는지 확인하지만 JSON_ATTRIBUTE_PREFIX를 설정하면 해당 접두어로 시작하는 항목 만 속성으로 처리되므로 설정할 수 있습니다 키 이름은 일반적으로 즉,로 시작하지 않는 아무것도하여 JSON_ATTRIBUTE_PREFIX :

unmarshaller.setProperty(UnmarshallerProperties.JSON_ATTRIBUTE_PREFIX, "@"); 

또는 예에서

unmarshaller.setProperty(UnmarshallerProperties.JSON_ATTRIBUTE_PREFIX, "THIS_STRING_WILL_NEVER_BE_USED_AS_THE_START_OF_A_KEY_NAME"); 

명확하게하기 위해 당신은 또한에 JSON_INCLUDE_ROOT 속성을 설정해야합니다 있습니다 거짓으로 y JSON에 루트가 없다. 즉, JSON에 "양식"키를 래핑하지 않아도된다.

u.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT,false);