오랫동안 죄송합니다. 미리 감사드립니다! JAXB를 사용하여 중첩 세트 비 정렬 화
내가이 XML 비 직렬화해야 내 JAXB 내부
<RootTag>
<Container type="type1">
<value name="name1"/>
<value name="name2"/>
</Container>
<Container type="type2">
<value name="name3"/>
<value name="name4"/>
</Container>
</RootTag>
요약
을 나는 내부 세트가 싸여 값 세트의 세트가 (코드는 아래와 같습니다) 컨테이너 클래스로 그래서 저는 값의 컨테이너 집합을 가지고 있는데, 여기서 값은 일반적인 클래스입니다. 문제점 : 선택한 제네릭 클래스가 하드 코드되지 않으면 값이 해석되지 않습니다. 는 XML에
자세한
주 :
<Container>
태그<value>
태그 설정이 포함되어 있습니다.<value>
태그는 무엇이든 포함 할 수 있습니다. (우리는 하나 "name"속성이있는 ElementName을 클래스를 가지고 위의 예에서)이 JAXB에서 컨테이너 클래스는설정 <T>를 사용합니다.만 정확히 두
는<Container>
태그있을 가정된다 (그 속성이 두 항목의 열거이지만,이 예제에서 그것을 간단하게하기 위해 단지 문자열입니다). 추가 질문 (선택 사항) : 태그 양을 정확히 2 개로 제한 할 수있는 방법이 있습니까? 이 모든 포장
, 우리는 Set<Container<ElementName>>
이있는 루트 클래스가 있습니다. 문제는 가장 깊은 ElementName
(<value>
태그를 나타냄) 클래스가 JAXB에 의해 해결되지 않는다는 것입니다 (너무 많은 수준의 간접 참조?). 그러나 JAXB는 모든 정보를 내부 형식 인 ElementNSImpl
으로 읽습니다. 태그의 값 (즉, name1
, name2
, name3
및 name4
)이있는 곳에서 afterUnmarshall
메서드 내에 중단 점을 배치하여 계산했습니다. 비 정렬 화는 오류없이 완료,하지만 난 어떤 <value>
태그에 액세스하려고 할 때이 얻을 :
java.lang.ClassCastException: com.sun.org.apache.xerces.internal.dom.ElementNSImpl cannot be cast to ElementName
, 내가
@XmlElement(name = "value")
내가 만약 사용하여 <value>
의 태그 이름을 지정 다음과 같이 유형을 하드 코드하면됩니다.
@XmlElement(name = "value", type = ElementName.class)
그러면 JAXB가 태그를 올바르게 해석합니다. 그러나 제가 말했듯이, 수업은 일반적인 수업으로되어있어서 정말 저를위한 해결책은 아닙니다.
JAXB 클래스
루트
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/*
* <RootTag>
* *
* </RootTag>
*/
@XmlRootElement(name = "RootTag")
public class Root {
/* <Container type = "type1">
* <value name = "name1"/>
* <value name = "name2"/>
* </Container>
* <Container type = "type2">
* <value name = "name3"/>
* <value name = "name4"/>
* </Container>
*/
@XmlElement(name = "Container")
private Set<Container<ElementName>> containers;
// for each of the two Container types
// we create a set of its corresponding values' names
// and then we null the containers field
@XmlTransient
private Map<String, Set<String>> valuesNames = new HashMap<>(2);
//Basically that is @PostConstruct, but works with JAXB
void afterUnmarshal(Unmarshaller u, Object parent) {
containers.forEach(container -> valuesNames.put(container.getType(),
container.getValues().stream()
.map(ElementName::getName)
.collect(Collectors.toSet())));
containers = null;
}
/** return unique value names from both container types */
public Set<String> getAllValuesNames() {
return valuesNames.values().stream()
.flatMap(Set::stream)
.collect(Collectors.toSet());
}
}
컨테이너
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.*;
import java.util.Set;
/*
* <* type = "type1">
* <value *>*
* <value *>*
* </*>
*/
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Container<T> {
@XmlAttribute
private String type;
@XmlElement(name = "value")
private Set<T> values;
public String getType() {
return type;
}
public Set<T> getValues() {
return values;
}
}
ElementName을
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
/*
* <* name = "name2"/>
*/
@XmlAccessorType(XmlAccessType.FIELD)
public class ElementName {
@XmlAttribute
private String name;
public String getName() {
return name;
}
}
홈페이지
public static void main(String[] args) throws JAXBException {
final String xmlSerialized = "<RootTag>\n" +
" \n" +
" <Container type=\"type1\">\n" +
" <value name=\"name1\"/>\n" +
" <value name=\"name2\"/>\n" +
" </Container>\n" +
" \n" +
" <Container type=\"type2\">\n" +
" <value name=\"name3\"/>\n" +
" <value name=\"name4\"/>\n" +
" </Container>\n" +
" \n" +
"</RootTag>";
System.out.println("XML:\n" +
"=======================================\n" +
xmlSerialized +
"\n=======================================");
//works just the same with only Root.class
JAXBContext context = JAXBContext.newInstance(Root.class, Container.class, ElementName.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
Root xmlDeserialized = (Root) unmarshaller.unmarshal(new StringReader(xmlSerialized));
System.out.println("Values' names: " + xmlDeserialized.getAllMetricNames());
}
경우 모든 작동합니다 (I가 컨테이너 클래스 내부의 주석에 ElementName.class를 하드 경우) 다음과 같은 출력을 제공합니다
을XML:
=======================================
<RootTag>
<Body>
<Container type="type1">
<value name="name1"/>
<value name="name2"/>
</Container>
<Container type="type2">
<value name="name3"/>
<value name="name4"/>
</Container>
</Body>
</RootTag>
=======================================
Values' names: [name4, name3, name2, name1]
내가 시도한 것
Unmarshalling generic list with JAXB.
주요 아이디어는 대신 내부적으로 그 목록을 사용하는
Wrapper<T>
을 사용하고 게터 통해 제공List<T>
의 사용이다. 내 컨테이너은 이미 속성을 가지고있는 것을 제외하고는 이미 래퍼입니다.하기 전에 :
@XmlElement(name = "value") private Set<T> values;
후 :
이@XmlAnyElement(lax = true) private Set<T> values;
가 실행 다시 (
JAXBContext.newInstance(Root.class, Container.class, ElementName.class)
가) : 아무것도 변경, 값은 여전히의없는 그러나 설정의 주석에서 차이가있다ElementNSImpl
을 입력하십시오. 또한 태그의 이름을 허용하는 것이 싫어서 '가치'여야합니다. 자신의 경우Intermittent ClassCastException from ElementNSImpl to own type during unmarshalling
JAXBContext
를 만든 것이 었습니다. 나에게 해당되지 않는다. 자신의 경우 JAXB Unmarshalling XML Class Cast Exception
문제는 다음 코드를 컴파일하고 JVM이 알고하지 않도록 다음 는 제네릭의 유형을 삭제하고 자바는 컴파일시에 일반적인 유형을 결정한다 자바 유형 말소했다 그 일반 유형은 무엇입니까? 나는 그것이 나의 경우라고 생각하지만, 그것을 확인하거나 고치는 방법에 대해서는 모른다.