JAXB学习四 (理解JAXBContext)

在jaxb应用中,JAXBContext类可以说是使用JAXB API的入口点,就像是一道门,只有通过它才能进入到jaxb的世界里。

 

JAXBContext类提供的功能主要有:

  • marshall
  • unmarshall
  • validate

在jaxb中,通常如果声明JAXBContext对象:

JAXBContext jaxbContext = JAXBContext.newInstance("com.liulutu.student.model");

不过如果稍稍研究一下 JAXBContext 类,就会发现,其实它是一个抽象类, 但是从源码里却不能很清楚的看到到底是哪个实现类被具体的用到。

 

那么在 JAXBContext.newInstance("com.liulutu.student.model") 的背后肯定有一些猫腻。下面就简单介绍一下这背后所隐藏的秘密。

 

一、代码追踪

 首先看一下JAXBContext.newInstance("com.liulutu.student.model") 它的调用关系图:

可以看到,它一直调到了javax.xml.bind.ContextFinder类的find()方法:

ContextFinder.find(
                        /* The default property name according to the JAXB spec */
                        JAXB_CONTEXT_FACTORY,

                        /* the context path supplied by the client app */
                        contextPath,

                        /* class loader to be used */
                        classLoader,
                        properties );

 

其中这里的 contextPath 就是传入的包名,如上的 com.liulutu.student.model ; JAXB_CONTEXT_FACTORY 是一个预定义的值 javax.xml.bind.context.factory 。

 

KEY: 在ContextFinder的find方法里,它首先会去找一个东西:jaxb.properties 。它会试图在你传入的包中去查找有没有一个名为 jaxb.properties 的properties文件;如果有,则会继续深入,看看有没有key值为传入的 factoryId ,在这里也就是值为 JAXB_CONTEXT_FACTORY 的key值,如果有,则把它对应的 value 认为是需要的 JAXBContext的factory的实现,会自动调它的 createContext 文件。

 

OTHER: 否则就会去查找 系统属性;再查找类路径上的META-INF/services/目录;最后再不行就反正一个默认的实现 /jaxb/src/com/sun/xml/internal/bind/v2/ContextFactory.java 。不过这些事情我不再关心了。

 

回过头看KEY部分。由此我们可以想到,如果要指定自定义的JAXBContext的实现,只需要在包下提供一个jaxb.properties文件;文件里有一条key为 javax.xml.bind.context.factory , 值指定一个包含有 createContext()方法 并且该方法的返回值是一个JAXBContext 对象的类。

 

二、实践

可以简单实践一下,例如我在包 com.liulutu.student.model 下新建一个文件 jaxb.properties,内容如下:

 

javax.xml.bind.context.factory=com.liulutu.student.model.CustomJAXBContextFactory

 然后,在CustomJAXBContextFactory类里什么也不实现:

package com.liulutu.student.model;

import javax.xml.bind.JAXBContext;

public class CustomJAXBContextFactory{

}

 

然后再测试一下marshall或unmarshall的代码,例如:

		JAXBContext jaxbContext = JAXBContext.newInstance("com.liulutu.student.model");

		ObjectFactory factory = new ObjectFactory();
		Students students = factory.createStudents();
		addNewStudentTo(factory, students, "a", SexType.MALE);
		addNewStudentTo(factory, students, "b", SexType.FEMALE);
		Marshaller marshaller = jaxbContext.createMarshaller();
		marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
		marshaller.setSchema(SchemaFactory.newInstance(
				XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(
				new File("students.xsd")));
		marshaller.marshal(students, new File("a.xml"));

 

然后检查一下运行结果:

 

Exception in thread "main" javax.xml.bind.JAXBException: Provider com.liulutu.student.model.CustomJAXBContextFactory could not be instantiated: java.lang.NoSuchMethodException: com.liulutu.student.model.CustomJAXBContextFactory.createContext(java.lang.String, java.lang.ClassLoader)	
 - with linked exception:
[java.lang.NoSuchMethodException: com.liulutu.student.model.CustomJAXBContextFactory.createContext(java.lang.String, java.lang.ClassLoader)]
	at javax.xml.bind.ContextFinder.newInstance(Unknown Source)
	at javax.xml.bind.ContextFinder.find(Unknown Source)
	at javax.xml.bind.JAXBContext.newInstance(Unknown Source)
	at javax.xml.bind.JAXBContext.newInstance(Unknown Source)
	at javax.xml.bind.JAXBContext.newInstance(Unknown Source)
	at com.liulutu.student.test.TestMarshaller.main(TestMarshaller.java:22)
Caused by: java.lang.NoSuchMethodException: com.liulutu.student.model.CustomJAXBContextFactory.createContext(java.lang.String, java.lang.ClassLoader)
	at java.lang.Class.getMethod(Unknown Source)
	... 6 more

 

 

你可能感兴趣的:(context)