Hello Avner,
I did this once because of the same idea. In the end I decided to remove this
because this caused too much trouble due
to the nature of the implementation of the JAXBContext. Anyways, this is the
way I did that:
First of all, you need a good way to initialize the JAXBContext. I was using
Freemaker for this.
/src/main/freemarker/jaxb-packages.fmt:
<@file package="package.of.jaxb.generated.classes" name="jaxb.packages">
<@forAllPackages var="package">
<#assign printpackage=false>
<#list package.classes as class>
<@ifHasAnnotation declaration=class
annotation="javax.xml.bind.annotation.XmlRegistry">
<#assign printpackage=true>
</@ifHasAnnotation>
</#list>
<#if printpackage>
${package.qualifiedName}
</#if>
</@forAllPackages>
</@file>
Run this code using the apt-maven-plugin after the maven-jaxb2-plugin:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>apt-maven-plugin</artifactId>
<configuration>
<factory>net.sf.jelly.apt.freemarker.FreemarkerProcessorFactory</factory>
<fork>false</fork>
<options>
<value>template=${basedir}/src/main/freemarker/jaxb-packages.fmt</value>
</options>
<outputDirectory>${project.build.outputDirectory}</outputDirectory>
<sourceOutputDirectory>${project.build.outputDirectory}</sourceOutputDirectory>
<additionalSourceRoots>
<additionalSourceRoot>target/generated-sources/java</additionalSourceRoot>
</additionalSourceRoots>
</configuration>
<executions>
<execution>
<goals>
<goal>process</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>net.sf.apt-jelly</groupId>
<artifactId>apt-jelly-core</artifactId>
<version>2.14</version>
</dependency>
<dependency>
<groupId>net.sf.apt-jelly</groupId>
<artifactId>apt-jelly-freemarker</artifactId>
<version>2.14</version>
</dependency>
</dependencies>
</plugin>
This will generate a file which contains all the packages of the generated JAXB
classes. One package per line. You will
need these packages to initialize the JAXBContext for all your classes at once.
Now, I have added a JAXBContextProvider. (Note: there are OVal annotations in
this code)
/**
* @author Marko Voss ([email protected])
*/
@Guarded
@Provider
public class JAXBContextProvider {
private static final Logger LOG =
LoggerFactory.getLogger(JAXBContextProvider.class);
private JAXBContext jaxbContext;
private String packageFile;
protected JAXBContextProvider() {}
@NotNull
public final JAXBContext getJAXBContext() throws JAXBException {
if (this.jaxbContext == null) {
this.jaxbContext = initJAXBContext();
if (this.jaxbContext == null) {
this.jaxbContext = JAXBContext.newInstance();
LOG.warn("Returning default JAXBContext instance.");
}
}
return this.jaxbContext;
}
public final void setPackageFile(@NotNull @NotBlank final String
packageFile) {
this.packageFile = packageFile;
}
private JAXBContext initJAXBContext() throws JAXBException {
if (this.packageFile == null) return null;
final InputStream stream =
getClass().getClassLoader().getResourceAsStream(this.packageFile);
try {
if (stream != null) {
final BufferedReader reader = new BufferedReader(new
InputStreamReader(stream));
final StringBuilder packages = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
packages.append(line);
packages.append(':');
}
packages.deleteCharAt(packages.length() - 1);
return JAXBContext.newInstance(packages.toString());
} else {
LOG.warn("Unable to find JAXB package list: " +
this.packageFile);
}
} catch (IOException e) {
LOG.error("Error reading JAXB package list: " +
this.packageFile, e);
}
return null;
}
}
Now, register the JAXBContextProvider to the JAXBElementProvider:
public class MyJAXBElementProvider extends JAXBElementProvider<Object> {
private JAXBContextProvider jaxbContextProvider;
// register
public void setJaxbContextProvider(final JAXBContextProvider
jaxbContextProvider) {
this.jaxbContextProvider = jaxbContextProvider;
}
public JAXBContext getJAXBContext(Class<?> type, Type genericType)
throws JAXBException {
if (this.jaxbContextProvider != null) {
return this.jaxbContextProvider.getJAXBContext();
} else {
return super.getJAXBContext(type, genericType);
}
}
}
I configured this using Spring.
The JAXBContext will now be available for all the generated JAXB classes. BUT
this works only for unmarshalling! (iirc)
On marshalling I got the problem, that the JAXBContext was not able to
recognize some namespaces or something. I cannot
really remember the problem. In the end I have decided to remove this, because
it is just not possible to have one
context for everything. I think the problem was like this:
The XML allows any content and you put some XML inside this any content. You
have JAXB objects for both XML structures,
the outside one and the "any-content one". Iirc, the JAXBContext was not able
to map the inner XML to an object because
of it could not find the JAXB object mapping for it, even through it was
registered. Due to lack of time I did not
investigate this any further.
best
Am 02.10.2012 14:16, schrieb Avner Levy:
> Hi,
> I have multiple services which can return results out of thousands of classes.
> Since each CXF service contains a private otherwise-identical JAXB context,
> it causes a huge memory waste.
> Is there a way to create the JAXB context myself and share it between the
> services?
> Thanks in advance,
> Avner
-------------------------------------------------------
Fachinformationszentrum Karlsruhe, Gesellschaft für wissenschaftlich-technische
Information mbH.
Sitz der Gesellschaft: Eggenstein-Leopoldshafen, Amtsgericht Mannheim HRB
101892.
Geschäftsführerin: Sabine Brünger-Weilandt.
Vorsitzender des Aufsichtsrats: MinDirig Dr. Thomas Greiner.