Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ClassCastException: cannot be cast to com.sun.xml.bind.v2.runtime.reflect.Accessor #1449

Closed
merusso opened this issue May 15, 2020 · 12 comments · Fixed by #1527
Closed

ClassCastException: cannot be cast to com.sun.xml.bind.v2.runtime.reflect.Accessor #1449

merusso opened this issue May 15, 2020 · 12 comments · Fixed by #1527

Comments

@merusso
Copy link

merusso commented May 15, 2020

Version: 2.3.3

In a Java 8 app, after upgrading the jaxb-runtime from 2.3.2 to 2.3.3, an exception is thrown when using JAX-B as part of a SOAP service call.

I believe this relates to #1284, which changed from using jakarta.activation-api to jakarta.activation.

Exception snippet:

java.lang.ClassCastException: com.tsys.xmlmessaging.cc.DateTime$JaxbAccessorF_value cannot be cast to com.sun.xml.bind.v2.runtime.reflect.Accessor
	at com.sun.xml.bind.v2.runtime.reflect.opt.OptimizedAccessorFactory.instanciate(OptimizedAccessorFactory.java:183) ~[jaxb-runtime-2.3.3.jar:2.3.3]
	at com.sun.xml.bind.v2.runtime.reflect.opt.OptimizedAccessorFactory.get(OptimizedAccessorFactory.java:172) ~[jaxb-runtime-2.3.3.jar:2.3.3]
	at com.sun.xml.bind.v2.runtime.reflect.Accessor$FieldReflection.optimize(Accessor.java:255) ~[jaxb-runtime-2.3.3.jar:2.3.3]
	at com.sun.xml.bind.v2.runtime.reflect.TransducedAccessor$CompositeTransducedAccessorImpl.<init>(TransducedAccessor.java:207) ~[jaxb-runtime-2.3.3.jar:2.3.3]
	at com.sun.xml.bind.v2.runtime.reflect.TransducedAccessor.get(TransducedAccessor.java:147) ~[jaxb-runtime-2.3.3.jar:2.3.3]
	at com.sun.xml.bind.v2.model.impl.RuntimeClassInfoImpl.calcTransducer(RuntimeClassInfoImpl.java:215) ~[jaxb-runtime-2.3.3.jar:2.3.3]
	at com.sun.xml.bind.v2.model.impl.RuntimeClassInfoImpl.getTransducer(RuntimeClassInfoImpl.java:189) ~[jaxb-runtime-2.3.3.jar:2.3.3]
	at com.sun.xml.bind.v2.model.impl.RuntimeClassInfoImpl.link(RuntimeClassInfoImpl.java:166) ~[jaxb-runtime-2.3.3.jar:2.3.3]
	at com.sun.xml.bind.v2.model.impl.ModelBuilder.link(ModelBuilder.java:424) ~[jaxb-runtime-2.3.3.jar:2.3.3]
	at com.sun.xml.bind.v2.model.impl.RuntimeModelBuilder.link(RuntimeModelBuilder.java:103) ~[jaxb-runtime-2.3.3.jar:2.3.3]
	at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:448) ~[jaxb-runtime-2.3.3.jar:2.3.3]
	at com.sun.xml.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:282) ~[jaxb-runtime-2.3.3.jar:2.3.3]
	at com.sun.xml.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:109) ~[jaxb-runtime-2.3.3.jar:2.3.3]
	at com.sun.xml.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1142) ~[jaxb-runtime-2.3.3.jar:2.3.3]
	at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:141) ~[jaxb-runtime-2.3.3.jar:2.3.3]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_252]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_252]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_252]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_252]
	at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:247) ~[na:1.8.0_252]
	at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:234) ~[na:1.8.0_252]
	at javax.xml.bind.ContextFinder.find(ContextFinder.java:441) ~[na:1.8.0_252]
	at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:641) ~[na:1.8.0_252]
	at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:584) ~[na:1.8.0_252]
...
@lukasj
Copy link
Member

lukasj commented May 15, 2020

Any way one can reproduce the problem? This has nothing to do with activation.jar.

@lukasj
Copy link
Member

lukasj commented May 15, 2020

it's more likely related to #1352 ; what happens when you start JVM with -Dcom.sun.xml.bind.v2.runtime.reflect.opt.OptimizedAccessorFactory.noOptimization=true/false?

@merusso
Copy link
Author

merusso commented May 15, 2020

Thanks for the insight! When setting that Java property to true, the problem goes away. When setting to false, the problem reoccurs.

@lukasj
Copy link
Member

lukasj commented May 15, 2020

@danielkec this is related to your changes. Any idea what's wrong?

@danielkec
Copy link
Contributor

@merusso Would it be possible to share how is declared field value in class com.tsys.xmlmessaging.cc.DateTime? I am unable to reproduce the issue. Thx in advance

@merusso
Copy link
Author

merusso commented May 21, 2020

Sure. It might be helpful to know that this is generated Java source from a SOAP WSDL.

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlSchemaType;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.XmlValue;
import javax.xml.datatype.XMLGregorianCalendar;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "dateTime", propOrder = {
    "value"
})
public class DateTime {

    @XmlValue
    @XmlSchemaType(name = "dateTime")
    protected XMLGregorianCalendar value;

    public XMLGregorianCalendar getValue() {
        return value;
    }

    public void setValue(XMLGregorianCalendar value) {
        this.value = value;
    }

}

@merusso
Copy link
Author

merusso commented May 28, 2020

@danielkec, is this enough info for you to reproduce successfully? Please let me know if you need anything else.

@merusso
Copy link
Author

merusso commented Jun 1, 2020

This regression in a patch version is not ideal. Would it be reasonable to change this feature flag's default state to false (opt-in) for 2.3.x to avoid this regression?

@jimma
Copy link
Contributor

jimma commented Mar 25, 2021

@lukasj @danielkec I totally agree with @merusso that make this flag to false by default to backward compatible with jaxb 2.3.2. Is there any performance improvement number by #1352 ?

@jimma
Copy link
Contributor

jimma commented Mar 25, 2021

@lukasj @danielkec @merusso I already sent two PRs to set this flag to true by default : #1525, #1524. Please review and guide me what I need to do before the merge.

@danielkec
Copy link
Contributor

I was able to replicate on jdk 1.8.0_221 with org.glassfish.jaxb:jaxb-runtime:2.3.3

class AccessorCast1449Test {

    static final String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" +
            "<testEntity>\n" +
            "    <dateTime>2021-03-25T09:34:49.877</dateTime>\n" +
            "</testEntity>";

    @Test
    void accessorCast() throws JAXBException {
        System.setProperty("com.sun.xml.bind.v2.runtime.reflect.opt.OptimizedAccessorFactory.noOptimization","false");
        ClassLoader parent = Thread.currentThread().getContextClassLoader();
        // Using jdk's internal JAXB to unmarshall
        Thread.currentThread().setContextClassLoader(CustomJaxbClassLoader.internalJaxbLoader(parent));
        JAXBContext contextInternal = com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl
                .newInstance(TestEntity.class, TestEntity.DateTime.class);
        TestEntity unmarshaled = (TestEntity) contextInternal.createUnmarshaller()
                .unmarshal(new StringReader(xml));
        System.out.println(unmarshaled);
        // And org.glassfish.jaxb:jaxb-runtime:2.3.3 for marshalling same entity
        Thread.currentThread().setContextClassLoader(CustomJaxbClassLoader.riJaxbLoader(parent));
        JAXBContext contextGlassfish = com.sun.xml.bind.v2.runtime.JAXBContextImpl
                .newInstance(TestEntity.class, TestEntity.DateTime.class);
        Marshaller mar = contextGlassfish.createMarshaller();
        StringWriter writer = new StringWriter();
        mar.marshal(unmarshaled, writer);
        System.out.println(writer);
    }


    @XmlRootElement
    @XmlAccessorType(XmlAccessType.FIELD)
    public static class TestEntity {
        private DateTime dateTime;

        public TestEntity() {
        }

        public DateTime getDateTime() {
            return dateTime;
        }

        public void setDateTime(final DateTime dateTime) {
            this.dateTime = dateTime;
        }

        @Override
        public String toString() {
            return String.valueOf(dateTime.value);
        }

        @XmlAccessorType(XmlAccessType.FIELD)
        @XmlType(name = "dateTime", propOrder = {
                "value"
        })
        public static class DateTime {

            @XmlValue
            @XmlSchemaType(name = "dateTime")
            protected XMLGregorianCalendar value;

            public XMLGregorianCalendar getValue() {
                return value;
            }

            public void setValue(XMLGregorianCalendar value) {
                this.value = value;
            }
        }
    }

    public static class CustomJaxbClassLoader extends ClassLoader {
        static {
            URL.setURLStreamHandlerFactory(protocol -> {
                if("customjaxb".equals(protocol)){
                    return new URLStreamHandler() {
                        @Override
                        protected URLConnection openConnection(final URL u) throws IOException {
                            return new URLConnection(u) {
                                @Override
                                public InputStream getInputStream() throws IOException {
                                    System.out.println("Custom JAXB context factory "+u.getHost());
                                    return new ByteArrayInputStream(u.getHost().getBytes());
                                }
    
                                @Override
                                public void connect() throws IOException {
                                    //noop
                                }
                            };
                        }
                    };
                }
                return null;
            });
        }
    
        private final String contextFactory;
    
        private CustomJaxbClassLoader(final ClassLoader parent, String contextFactory) {
            super(parent);
            this.contextFactory = contextFactory;
        }
    
        public static ClassLoader internalJaxbLoader(final ClassLoader parent) {
            return new CustomJaxbClassLoader(parent, "com.sun.xml.internal.bind.v2.ContextFactory");
        }
    
        public static ClassLoader riJaxbLoader(final ClassLoader parent) {
            return new CustomJaxbClassLoader(parent, "com.sun.xml.bind.v2.ContextFactory");
        }
    
        @Override
        public URL getResource(final String name) {
            if (name.equals("META-INF/services/javax.xml.bind.JAXBContext")) {
                try {
                    return new URL("customjaxb://" + contextFactory);
                } catch (MalformedURLException e) {
                    throw new RuntimeException(e);
                }
            }
            return super.getResource(name);
        }
    }
}

@danielkec
Copy link
Contributor

@lukasj root cause seems to be mixing up different JAXBContexts, can ask @merusso for confirmation?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants