eclipse-ee4j / jaxb-ri

Jaxb RI
https://eclipse-ee4j.github.io/jaxb-ri/
BSD 3-Clause "New" or "Revised" License
202 stars 110 forks source link

ConcurrentModificationException in TypeInfoSetImpl#getXmlNs #1726

Open schabe77 opened 1 year ago

schabe77 commented 1 year ago

Hi,

I use the BingAds-API that uses CXF that uses jaxb-runtime-4.0.3 and just faced a ConcurrentModificationException.

Unfortunately I don't know what Bing and CXF do in detail, but maybe this stack trace helps:

java.util.ConcurrentModificationException: null
    at java.base/java.util.HashMap.computeIfAbsent(HashMap.java:1221)
    at org.glassfish.jaxb.runtime.v2.model.impl.TypeInfoSetImpl.getXmlNs(TypeInfoSetImpl.java:298)
    at org.glassfish.jaxb.runtime.v2.schemagen.XmlSchemaGenerator$Namespace.writeTo(XmlSchemaGenerator.java:565)
    at org.glassfish.jaxb.runtime.v2.schemagen.XmlSchemaGenerator.write(XmlSchemaGenerator.java:415)
    at org.glassfish.jaxb.runtime.v2.runtime.JAXBContextImpl.generateSchema(JAXBContextImpl.java:770)
    at org.apache.cxf.common.jaxb.JAXBUtils.generateJaxbSchemas(JAXBUtils.java:810)
    at org.apache.cxf.jaxb.JAXBDataBinding.generateJaxbSchemas(JAXBDataBinding.java:474)
    at org.apache.cxf.jaxb.JAXBDataBinding.initialize(JAXBDataBinding.java:391)
    at org.apache.cxf.service.factory.AbstractServiceFactoryBean.initializeDataBindings(AbstractServiceFactoryBean.java:87)
    at org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean.buildServiceFromClass(ReflectionServiceFactoryBean.java:469)
    at org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean.buildServiceFromClass(JaxWsServiceFactoryBean.java:693)
    at org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean.initializeServiceModel(ReflectionServiceFactoryBean.java:529)
    at org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean.create(ReflectionServiceFactoryBean.java:262)
    at org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean.create(JaxWsServiceFactoryBean.java:199)
    at org.apache.cxf.jaxws.ServiceImpl.createPort(ServiceImpl.java:466)
    at org.apache.cxf.jaxws.ServiceImpl.getPort(ServiceImpl.java:342)
    at org.apache.cxf.jaxws.ServiceImpl.getPort(ServiceImpl.java:337)
    at jakarta.xml.ws.Service.getPort(Service.java:210)
    at com.microsoft.bingads.internal.ServiceFactoryImpl.createProxyFromService(ServiceFactoryImpl.java:179)

The environment is

Debian openjdk version "17.0.2" 2022-01-18 OpenJDK Runtime Environment (build 17.0.2+8-86) OpenJDK 64-Bit Server VM (build 17.0.2+8-86, mixed mode, sharing)

schabe77 commented 1 year ago

I think it's a multi-threading issue. I don't know if this class is meant to be accessed by multiple threads simultaneously.

I think what is happing here

        if(xmlNsCache==null) {
            xmlNsCache = new HashMap<>();
            ...
            Map<String, String> m = xmlNsCache.computeIfAbsent(uri, k -> new HashMap<>());

is that

Options could be to

jimma commented 2 months ago

We met this issue too in CXF. It looks like creating a ConcurrentHashMap for xmlNsCache is good to go

tomjenkinson commented 3 hours ago

I might have misunderstood what @schabe77 is considering as an option here but if getXmlNs can be called concurrently then I don't think that just making xmlNsCache a ConcurrentHashMap would be enough because multiple threads executing in that method at the same time could see xmlNsCache==null at the same time and thus multiple xmlNsCache = new ConcurrentHashMap<>(); could execute in parallel at the same time, with the latest thread overwriting the variable xmlNsCache /cc @jimma regarding pull request https://github.com/eclipse-ee4j/jaxb-ri/pull/1806.