Почему @XmlJavaTypeAdapter в корневом объекте не работает с Marshaller.marshal в JDK 8?JAVA

Программисты JAVA общаются здесь
Anonymous
Почему @XmlJavaTypeAdapter в корневом объекте не работает с Marshaller.marshal в JDK 8?

Сообщение Anonymous »

В продолжение предыдущего вопроса (Как правильно использовать XmlAdapter?).
После решения моего решения с помощью 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);
}

}
}

Вернуться в «JAVA»