当前位置: 首页 > 面试题库 >

为什么在解组期间不使用ObjectFactory?

班展
2023-03-14
问题内容

我定义了以下内容ObjectFactory

@XmlRegistry
public class ObjectFactory {

    public Dogs createDogs() {
        return new Dogs();
    }

    @XmlElementDecl(name = "dog")
    public Dog createDog(DogType value) {
        return new Dog(value);
    }

    @XmlElementDecl(name = "fido", substitutionHeadName = "dog", substitutionHeadNamespace = "")
    public Dog createFido(DogType value) {
        return new Dog("fido", value);
    }

    @XmlElementDecl(name = "barks", substitutionHeadName = "dog", substitutionHeadNamespace = "")
    public Dog createBarks(DogType value) {
        return new Dog("barks", value);
    }
}

Dogs类是微不足道的,DogDogType见下文或点击这里。)

我正在解组以下XML:

<listOfDogs>
    <dogs>
        <dog>
            <name>henry</name>
            <sound>bark</sound>
        </dog>
        <fido>
            <sound>woof</sound>
        </fido>
        <barks>
            <sound>miau</sound>
        </barks>
    </dogs>
</listOfDogs>

我真诚地希望JAXB 在解组期间会调用my
createFido(...)createBarks(...)method。但这不会发生。该Dog构造是通过反射直接调用的,相应的create...不被使用的方法。

我的问题是:

为什么ObjectFactory在解组期间不被调用?

不是吗 还是ist只是持有@XmlRegistry/ @XmlElementDecl声明的假人?

我也检查了这个问题:

JAXB解组期间,ObjectFactory的作用是什么?

解决方案是使用@XmlType.factoryClassfactoryMethod。这在这里不起作用,因为我不想将我的静态链接DogType到某个实例化例程。我希望在运行时根据元素名称决定它。我的目标是根据元素名称实例化相同的类,但以不同的方式实例化。

现在添加一些代码以使其完整。

根元素类:

@XmlRootElement(name = "listOfDogs")
public class Dogs {

    private List<JAXBElement<DogType>> dogs = new LinkedList<JAXBElement<DogType>>();

    @XmlElementWrapper(name = "dogs")
    @XmlElementRef(name = "dog")
    public List<JAXBElement<DogType>> getDogs() {
        return this.dogs;
    }

    @Override
    public String toString() {
        return "Dogs [dogs=" + dogs + "]";
    }
}

Dog,是包装器元素类DogType

public class Dog extends JAXBElement<DogType> {

    public static final QName NAME = new QName("dog");

    private static final long serialVersionUID = 1L;

    public Dog(DogType value) {
        super(NAME, DogType.class, value);
    }

    public Dog(String dogName, DogType value) {
        super(NAME, DogType.class, value);
    }

    @Override
    public QName getName() {
        final DogType value = getValue();
        if (value != null && value.getName() != null) {
            return new QName(value.getName());
        } else {
            return super.getName();
        }
    }
}

DogType

public class DogType {

    private String name;
    private String sound;

    public String getName() {
        return name;
    }

    public void setName(String dogName) {
        this.name = dogName;
    }

    public String getSound() {
        return sound;
    }

    public void setSound(String sound) {
        this.sound = sound;
    }
}

测试:

public class DogTest {

    @Test
    public void unmarshallsDogs() throws JAXBException {
        final JAXBContext context = JAXBContext
                .newInstance(ObjectFactory.class);
        final Dogs dogs = (Dogs) context.createUnmarshaller().unmarshal(
                getClass().getResource("dogs.xml"));
        Assert.assertEquals(3, dogs.getDogs().size());
        // Does not work
//      Assert.assertEquals("henry", dogs.getDogs().get(0).getValue()
//              .getName());
        Assert.assertEquals("bark", dogs.getDogs().get(0).getValue().getSound());
        // Does not work
//      Assert.assertEquals("fido", dogs.getDogs().get(1).getValue()
//              .getName());
        Assert.assertEquals("woof", dogs.getDogs().get(1).getValue().getSound());
        // Does not work
//      Assert.assertEquals("barks", dogs.getDogs().get(2).getValue()
//              .getName());
        Assert.assertEquals("miau", dogs.getDogs().get(2).getValue().getSound());
    }
}

该代码也可以在GitHub的此处和此处获得。


问题答案:

简短的答案是因为@XmlType注释中未生成工厂方法来告诉JAXB这样做:

@XmlRootElement(name = "listOfDogs")
@XmlType(factoryClass=ObjectFactory.class, factoryMethod="createDogs") // not generated
public class Dogs {

不是吗 还是ist只是一个假人来保存@ XmlRegistry / @ XmlElementDecl声明?

在我看来,应该使用它实例化类。

ObjectFactory回到JAXB 1.0。在JAXB
1.0中,规范定义了所生成的接口的外观,并且实现可以以他们想要提供的暗示支持那些所生成的接口。那时,您需要使用ObjectFactory该类以独立于供应商的方式创建模型。

JAXB 2.0切换到POJO模型,您可以在其中自由使用默认构造函数。如果JAXB
1.0从未存在过ObjectFactory,那将是一个类,这很难说。由于ObjectFactory该类以前存在,因此保留该类的原因有两个:

  1. 从JAXB 1.0过渡的人与生成的模型进行交互时,它使过渡的人更容易。
  2. 它提供了一个位置,用于通过指定一个类的多个根元素@XmlElementDecl。该@XmlRegistry注解实际上只是一个标记注解,用于指示包含@XmlElementDecl注解的类,而不将其限制为一个名为的类ObjectFactory

您的用例

您的用例也许可以通过实现XmlAdapter,尽管对我来说尚不清楚您试图在其中使用什么逻辑ObjectFactory

XmlAdapter(DogAdapter)

您的自定义逻辑将继续XmlAdapter

import javax.xml.bind.*;
import javax.xml.bind.annotation.adapters.*;

public class DogAdapter extends XmlAdapter<JAXBElement<DogType>, JAXBElement<DogType>> {

    @Override
    public JAXBElement<DogType> unmarshal(JAXBElement<DogType> v) throws Exception {
        return new Dog(v.getName().getLocalPart(), v.getValue());
    }

    @Override
    public JAXBElement<DogType> marshal(JAXBElement<DogType> v) throws Exception {
        return v;
    }

}

小狗

XmlAdapter从引用的@XmlJavaTypeAdapter注释。

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

@XmlRootElement(name = "listOfDogs")
public class Dogs {

    private List<JAXBElement<DogType>> dogs = new LinkedList<JAXBElement<DogType>>();

    @XmlElementWrapper(name = "dogs")
    @XmlElementRef(name = "dog")
    @XmlJavaTypeAdapter(DogAdapter.class)
    public List<JAXBElement<DogType>> getDogs() {
        return this.dogs;
    }

    @Override
    public String toString() {
        return "Dogs [dogs=" + dogs + "]";
    }

}

对象工厂

ObjectFactory现在是一个仅包含@XmlElementDecl注释的哑类:

import javax.xml.bind.*;
import javax.xml.bind.annotation.*;
import javax.xml.namespace.QName;

@XmlRegistry
public class ObjectFactory {

    public Dogs createDogs() {
        return new Dogs();
    }

    @XmlElementDecl(name = "dog")
    public JAXBElement<DogType> createDog(DogType value) {
        return new Dog(value);
    }

    @XmlElementDecl(name = "fido", substitutionHeadName = "dog", substitutionHeadNamespace = "")
    public JAXBElement<DogType> createFido(DogType value) {
        return new JAXBElement<DogType>(new QName("fido"), DogType.class, value);
    }

    @XmlElementDecl(name = "barks", substitutionHeadName = "dog", substitutionHeadNamespace = "")
    public JAXBElement<DogType> createBarks(DogType value) {
        return new JAXBElement<DogType>(new QName("barks"), DogType.class, value);
    }

}

更新

但是,我的问题更多地是关于规范。根据规范,是否应该执行ObjectFactory的create *方法?

在JAXB 2中,从头创建的模型与从XML
Schema生成的模型没有区别。因此,您需要查看规范中有关类的内容。根据下面的参考,它归结为无参数构造函数或指定的工厂方法。

从节 8.7.1.2映射 所述的JAXB
2.2(JSR-222)规范:

一个类必须具有公共或受保护的无参数构造函数,或者由{factoryClass(),factoryMethod()}标识的工厂方法,除非使用@XmlJavaTypeAdapter对其进行了改编。



 类似资料:
  • 问题内容: 我正在使用JAXB 2.2.2解析简单的XML-REST流。这是一段代码: ObjectFactory类: 回应类别: “ com.example.entities”必须包含ObjectFactory类或jaxb.in​​dex。我想使用ObjectFactory类来确定一些pojo初始化,但是这些类从未使用:Response类始终直接由class.newInstance()实例化。这

  • 我在路由Laravel时使用以下中间件: 当我尝试在URL中调用此路径时: 我得到一个错误: 对不起,找不到您要找的页面。 常规采集。RouteCollection处的php第161行-

  • 我是React新手,我正在使用最新版本的React学习React组件生命周期。我对下面部分代码的“super”调用被标记为不推荐使用的警告。我很难理解这一点,因为很多文档仍然使用“super”,而且我不确定后续版本是什么,即使是从反馈中链接的完整文章中。有什么想法吗?谢谢 警告如下:

  • 我喜欢通过摆弄代码来学习,最近我复制并粘贴了一个随机数生成器代码。然后我删除了所有代码行,这些代码行对于生成一个随机数来说是不必要的。最后一根稻草是我删除了srand中的“时间”。 (无符号) 时间(0)); 这里的“时间(0)”是什么意思? 它使用程序打开的时间来生成随机数的种子吗?这就是为什么删除它(时间)会使它不起作用吗?因为它没有种子? 而且 这是整个代码,我注意到它使用“rand”结果进

  • 问题内容: 我阅读了有关在开发过程中使用Django提供静态媒体的指南。 我注意到了,并没有在此使用。为什么?有什么不同? 我尝试使用和进行操作,但结果很奇怪。 问题答案: 在生产情况下,您希望从前端Web服务器(Apache,Nginx等)提供媒体,以避免在Django / Python进程上造成额外负担。通常使用MEDIA_URL和MEDIA_ROOT。 运行内置的开发服务器,您需要在url.

  • 我有字符串格式的日期,我想解析成使用日期。 我将其解析为: 但奇怪的是,如果我通过"03-08-201309hjhkjhk"或"03-88-2013"或43-88-201378",它不会抛出错误,它会解析它。 现在,我必须编写正则表达式模式来检查日期的输入是否正确。但为什么会这样呢?? 代码: