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)

Reply via email to