Andreas Rusjaev created CXF-8836:
------------------------------------
Summary: Jaxb Integration with EclipseLink has Error
Key: CXF-8836
URL: https://issues.apache.org/jira/browse/CXF-8836
Project: CXF
Issue Type: Bug
Components: Core
Affects Versions: 4.0.0
Reporter: Andreas Rusjaev
Dear CXF developers,
I am using version 4.0.0 of CXF cxf-spring-boot-starter-jaxws.
My CXF jaxws services are wrapped in Spring Boot 3.0. I also use
akarta.xml.bind-api 4.0.0 and org.eclipse.persistence.moxy 4.0.1.
I generate Java models with cxf-codegen-plugin with the following configuration:
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>${cxf.version}</version>
<dependencies>
<dependency>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-basics-annotate</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.cxf.xjc-utils</groupId>
<artifactId>cxf-xjc-runtime</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf.xjcplugins</groupId>
<artifactId>cxf-xjc-ts</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.4.0-b180830.0359</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<sourceRoot>${project.build.directory}/generated-sources/cxf</sourceRoot>
<defaultOptions>
<noAddressBinding>true</noAddressBinding>
<faultSerialVersionUID>3105839350746982386</faultSerialVersionUID>
<extraargs>
<extraarg>-xjc-Xannotate</extraarg>
</extraargs>
</defaultOptions>
<wsdlOptions>
<wsdlOption>
<wsdl>${basedir}/src/main/resources/wsdl/myservice.wsdl</wsdl>
<wsdlLocation>classpath:wsdl/myservice.wsdl</wsdlLocation>
<serviceName>myservice</serviceName>
<bindingFiles>
<bindingFile>${basedir}/src/main/resources/wsdl/bindings.xjb</bindingFile>
</bindingFiles>
</wsdlOption>
</wsdlOptions>
</configuration>
<goals>
<goal>wsdl2java</goal>
</goals>
</execution>
</executions>
</plugin>
Binding file has the following configuration:
<?xml version="1.0"?>
<jaxb:bindings version="3.0"
xmlns:jaxb="https://jakarta.ee/xml/ns/jaxb"
jaxb:extensionBindingPrefixes="annox xjc"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:annox="http://annox.dev.java.net"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc">
<jaxb:bindings>
<jaxb:bindings>
<jaxb:globalBindings typesafeEnumMaxMembers="3000"
generateElementProperty="false"
mapSimpleTypeDef="false"
fixedAttributeAsConstantProperty="true"
choiceContentProperty="true"
typesafeEnumBase="xs:boolean">
</jaxb:globalBindings>
</jaxb:bindings>
</jaxb:bindings>
<jaxb:bindings schemaLocation="*">
<jaxb:bindings node="//xs:complexType" multiple="true" required="false">
<annox:annotateClass>@lombok.experimental.SuperBuilder</annox:annotateClass>
<annox:annotateClass>@jakarta.xml.bind.annotation.XmlRootElement</annox:annotateClass>
<annox:annotateClass>@lombok.NoArgsConstructor</annox:annotateClass>
</jaxb:bindings>
<jaxb:bindings node="//xs:element" multiple="true" required="false">
<annox:annotate target="field">
@org.eclipse.persistence.oxm.annotations.XmlNullPolicy(nullRepresentationForXml=
XmlMarshalNullRepresentation.ABSENT_NODE,
xsiNilRepresentsNull=false)
</annox:annotate>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
Model class generation works fine, nullable properties are marked with
annotation:
"@XmlNullPolicy(nullRepresentationForXml =
XmlMarshalNullRepresentation.ABSENT_NODE, xsiNilRepresentsNull = false)".
To start Moxy Runtime use the following settings in main method of Application:
System.setProperty("jakarta.xml.bind.JAXBContextFactory",
"org.eclipse.persistence.jaxb.JAXBContextFactory");
I use this initialisation because I still need to use Spring Web Service Client
from Spring WS in parallel.
But on startup I get errors:
Caused by: java.lang.reflect.InvocationTargetException: null
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native
Method) ~[na:na]
at
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
~[na:na]
at
java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
at org.apache.cxf.common.jaxb.JAXBUtils$3.run(JAXBUtils.java:1189)
~[cxf-core-4.0.0.jar:4.0.0]
at org.apache.cxf.common.jaxb.JAXBUtils$3.run(JAXBUtils.java:1183)
~[cxf-core-4.0.0.jar:4.0.0]
at
java.base/java.security.AccessController.doPrivileged(AccessController.java:569)
~[na:na]
at org.apache.cxf.common.jaxb.JAXBUtils.createContext(JAXBUtils.java:1183)
~[cxf-core-4.0.0.jar:4.0.0]
... 64 common frames omitted
Caused by: jakarta.xml.bind.JAXBException: Property
"eclipselink.default-target-namespace" is not supported.
at
org.glassfish.jaxb.runtime.v2.ContextFactory.createContext(ContextFactory.java:126)
~[jaxb-runtime-4.0.1.jar:4.0.1 - a95cb76]
I have examined your code and found that you are using hard coded call to
"Class<?> factoryClass =
ClassLoaderUtils.loadClass("org.glassfish.jaxb.runtime.v2.ContextFactory" in
cxf-core org.apache.cxf.common.jaxb.JAXBUtils
I have experimented a bit and if you can make a few changes in two classes
everything will work. The classes need to be changed:
1. org.apache.cxf.common.jaxb.JAXBContextCache Method
getCachedContextAndSchemas in lines 197 to 194
old code
if (defaultNs != null) {
if (HAS_MOXY) {
map.put("eclipselink.default-target-namespace", defaultNs);
}
map.put("org.glassfish.jaxb.defaultNamespaceRemap", defaultNs);
}
new code
if (defaultNs != null) {
if (HAS_MOXY) {
map.put("eclipselink.default-target-namespace", defaultNs);
} else {
map.put("org.glassfish.jaxb.defaultNamespaceRemap", defaultNs);
}
}
2. org.apache.cxf.common.jaxb.JAXBUtils
2.1 Method getPostfix in lines 1105 to 1117
old code:
private static String getPostfix(Class<?> cls) {
String className = cls.getName();
//TODO: review and remove "com.sun" package name check
if (className.contains("org.glassfish.jaxb") ||
className.contains("com.sun.xml.bind")
|| className.startsWith("com.ibm.xml")) {
return "";
} else if (className.contains("com.sun.xml.internal")
|| className.contains("eclipse")) {
//eclipse moxy accepts sun package CharacterEscapeHandler
return ".internal";
}
return null;
}
new code:
private static String getPostfix(Class<?> cls) {
String className = cls.getName();
//TODO: review and remove "com.sun" package name check
if (className.contains("org.glassfish.jaxb") ||
className.contains("com.sun.xml.bind")
|| className.startsWith("com.ibm.xml") ||
className.contains("eclipse")) {
//eclipse moxy 4.0 accepts glassfish package
CharacterEscapeHandler see const SUN_CHARACTER_ESCAPE_HANDLER
// Const in MOXY 4.0.1
// SUN_CHARACTER_ESCAPE_HANDLER=
"org.glassfish.jaxb.characterEscapeHandler";
// SUN_JSE_CHARACTER_ESCAPE_HANDLER =
"com.sun.xml.internal.bind.characterEscapeHandler";
// SUN_CHARACTER_ESCAPE_HANDLER_MARSHALLER =
"org.glassfish.jaxb.marshaller.CharacterEscapeHandler";
// SUN_JSE_CHARACTER_ESCAPE_HANDLER_MARSHALLER =
"com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler"
// part of setProperty(String key, Object value) from Class
org.eclipse.persistence.jaxb. JAXBMarshaller
// else if (SUN_CHARACTER_ESCAPE_HANDLER.equals(key)
|| SUN_JSE_CHARACTER_ESCAPE_HANDLER.equals(key) ||
//
SUN_CHARACTER_ESCAPE_HANDLER_MARSHALLER.equals(key) ||
//
SUN_JSE_CHARACTER_ESCAPE_HANDLER_MARSHALLER.equals(key)) {
// if (value == null) {
// xmlMarshaller.setCharacterEscapeHandler(null);
// } else {
// xmlMarshaller.setCharacterEscapeHandler(new
CharacterEscapeHandlerWrapper(value));
// }
return "";
} else if (className.contains("com.sun.xml.internal")
) {
return ".internal";
}
return null;
}
2.2 Method createContext in lines 1179 to 1202
old code:
public static JAXBContext createContext(final Set<Class<?>> classes,
final Map<String, Object> map)
throws JAXBException {
JAXBContext ctx = null;
try {
ctx = AccessController.doPrivileged(new
PrivilegedExceptionAction<JAXBContext>() {
public JAXBContext run() throws Exception {
//This is a workaround for CXF-8675
Class<?> factoryClass =
ClassLoaderUtils.loadClass("org.glassfish.jaxb.runtime.v2.ContextFactory",
JAXBContextCache.class);
Method m = factoryClass.getMethod("createContext",
Class[].class, Map.class);
Object context = m.invoke(null, classes.toArray(new
Class<?>[0]), map);
return (JAXBContext) context;
}
});
} catch (PrivilegedActionException e2) {
if (e2.getException() instanceof JAXBException) {
JAXBException ex = (JAXBException) e2.getException();
throw ex;
} else {
throw new RuntimeException(e2.getException());
}
}
return ctx;
}
new code:
public static JAXBContext createContext(final Set<Class<?>> classes,
final Map<String, Object> map)
throws JAXBException {
JAXBContext ctx = null;
try {
ctx = AccessController.doPrivileged(new
PrivilegedExceptionAction<JAXBContext>() {
public JAXBContext run() throws Exception {
String factoryClassName =
classNameFromSystemProperties("org.glassfish.jaxb.runtime.v2.ContextFactory");
//This is a workaround for CXF-8675
Class<?> factoryClass =
ClassLoaderUtils.loadClass(factoryClassName,
JAXBContextCache.class);
Method m = factoryClass.getMethod("createContext",
Class[].class, Map.class);
Object context = m.invoke(null, classes.toArray(new
Class<?>[0]), map);
return (JAXBContext) context;
}
});
} catch (PrivilegedActionException e2) {
if (e2.getException() instanceof JAXBException) {
JAXBException ex = (JAXBException) e2.getException();
throw ex;
} else {
throw new RuntimeException(e2.getException());
}
}
return ctx;
}
private static String classNameFromSystemProperties(String
defaultValue) throws JAXBException {
String factoryClassName =
getSystemProperty(JAXBContext.JAXB_CONTEXT_FACTORY, defaultValue);
if (factoryClassName != null) {
return factoryClassName;
}
return null;
}
private static String getSystemProperty(String property, String
defaultValue) {
String value = System.getProperty(property);
if (value != null) {
return value;
} else {
return defaultValue;
}
}
If you have other possibilities to configure org.eclipse.persistence.moxy. Can
you please describe.
Thanks in advance
Anderas Rusjaev
--
This message was sent by Atlassian Jira
(v8.20.10#820010)