После решения моего решения с помощью fastxml мне стало любопытно, почему jaxb не работает. По этой причине я подделал исходный код. Вот мои выводы: могут быть некоторые ошибки.
Прежде всего, я нашел место, где возникла ошибка, проследив маршал. Метод, вызвавший ошибку: com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.serializeRoot. Причина ошибки в том, что tagName имеет значение null и нет аннотации XmlRootElement.
Я пытался найти время присвоения значения tagName и обнаружил, что оно было присвоено при вызове JAXBContext.newInstance.
По своей сути он использует отражение для вызова com.sun.xml.internal.bind.v2.ContextFactory.createContext, а затем создает экземпляр JAXBContextImpl, вызывая JAXBContextImpl.JAXBContextBuilder.build. В конструкторе JAXBContextImpl вызывается getTypeInfoSet. Внутри этого метода объект типа RuntimeModelBuilder с именем builder вызывает getTypeInfo. Через несколько уровней вызовов он в конечном итоге вызывает com.sun.xml.internal.bind.v2.model.impl.ModelBuilder.getClassInfo, где выполняются внутренние проверки. Поскольку это первое создание и обычный Java Bean, далее будет вызываться createClassInfo.
В конструкторе com.sun.xml.internal.bind.v2.model.impl.ClassInfoImpl он анализирует имя элемента с помощью метода parseElementName. Если этот класс не имеет аннотации XmlRootElement.class, он будет возвращать значение null напрямую, elementName будет использоваться для принятия значения null.
Когда вызов getTypeInfoSet заканчивается и входит в цикл for, подготовленный для обычного Java-компонента (то есть третий цикл for), он получит или создаст экземпляр com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl, вызвав метод getOrCreate. Когда я ввожу этот метод и далее вхожу в конструктор com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl, он присваивает значение tagName, вызывая ci.isElement(ci имеет тип RuntimeClassInfo), чтобы проверить его истинность. Когда оно ложно, tagName имеет значение null.
А в методе isElement проверяется, имеет ли elementName значение null.
Я использую версию jdk8u472-b08.
Вопрос
- Кажется, во время процесса отладки что я не нашел никакой обработки адаптера, возможно, потому, что не заметил этого из-за отсутствия навыков. Можете ли вы сказать мне, есть ли часть, которая управляет адаптером?
- Если кто-то успешно использовал JAXB, не могли бы вы поделиться исходным кодом?
- Если в процессе отладки, который я описал выше, есть какие-либо упущения или ошибки, пожалуйста, не стесняйтесь указать на них.
package com.ff;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "root")
public class MiddleRoot {
private Head head;
private Body body;
public MiddleRoot() {
}
public MiddleRoot(Head head, Body body) {
this.head = head;
this.body = body;
}
public Head getHead() {
return head;
}
public void setHead(Head head) {
this.head = head;
}
public Body getBody() {
return body;
}
public void setBody(Body body) {
this.body = body;
}
public String toString() {
return "MiddleRoot{head = " + head + ", body = " + body + "}";
}
public static class Head{
private String a;
private String b;
private String c;
public Head() {
}
public Head(String a, String b, String c) {
this.a = a;
this.b = b;
this.c = c;
}
public String getA() {
return a;
}
public void setA(String a) {
this.a = a;
}
public String getB() {
return b;
}
public void setB(String b) {
this.b = b;
}
public String getC() {
return c;
}
public void setC(String c) {
this.c = c;
}
public String toString() {
return "Head{a = " + a + ", b = " + b + ", c = " + c + "}";
}
}
public static class Body{
private String d;
private String e;
public Body() {
}
public Body(String d, String e) {
this.d = d;
this.e = e;
}
public String getD() {
return d;
}
public void setD(String d) {
this.d = d;
}
public String getE() {
return e;
}
public void setE(String e) {
this.e = e;
}
public String toString() {
return "Body{d = " + d + ", e = " + e + "}";
}
}
}
package com.ff;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlJavaTypeAdapter(RootAdapter.class)
public class Root {
private String a;
private String b;
private String c;
private String d;
private String e;
public Root() {
}
public Root(String a, String b, String c, String d, String e) {
this.a = a;
this.b = b;
this.c = c;
this.d = d;
this.e = e;
}
public String getA() {
return a;
}
public void setA(String a) {
this.a = a;
}
public String getB() {
return b;
}
public void setB(String b) {
this.b = b;
}
public String getC() {
return c;
}
public void setC(String c) {
this.c = c;
}
public String getD() {
return d;
}
public void setD(String d) {
this.d = d;
}
public String getE() {
return e;
}
public void setE(String e) {
this.e = e;
}
public String toString() {
return "Root{a = " + a + ", b = " + b + ", c = " + c + ", d = " + d + ", e = " + e + "}";
}
}
package com.ff;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class RootAdapter extends XmlAdapter {
@Override
public Root unmarshal(MiddleRoot v) throws Exception {
MiddleRoot.Head head = v.getHead();
MiddleRoot.Body body = v.getBody();
Root r = new Root();
if(head!=null){
r.setA(head.getA());
r.setB(head.getB());
r.setC(head.getC());
}
if(body!=null){
r.setD(body.getD());
r.setE(body.getE());
}
return r;
}
@Override
public MiddleRoot marshal(Root v) throws Exception {
MiddleRoot.Head head = new MiddleRoot.Head(v.getA(), v.getB(), v.getC());
MiddleRoot.Body body = new MiddleRoot.Body(v.getD(), v.getE());
return new MiddleRoot(head,body);
}
}
package com.ff;
import com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) throws Exception {
Root root = new Root("a", "b", "c", "d", "e");
JAXBContext context = JAXBContext.newInstance(Root.class,MiddleRoot.class);
context = (JAXBContextImpl)context;
Field classes = context.getClass().getDeclaredField("classes");
classes.setAccessible(true);
Class[] classes1 = (Class[]) classes.get(context);
for (Class aClass : classes1) {
System.out.println("class Name:"+aClass.getName());
Annotation[] annotations = aClass.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println("type:"+annotation.annotationType().getSimpleName());
System.out.println("name:"+annotation.annotationType().getName());
Method[] declaredMethods = annotation.annotationType().getDeclaredMethods();
for (Method method : declaredMethods) {
Object value = method.invoke(annotation);
System.out.println(" "+method.getName()+" = "+value);
}
System.out.println();
}
}
try {
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_ENCODING,"UTF-8");
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root,System.out);
} catch (JAXBException e) {
System.out.println(e);
}
}
}