XmlBeans.Factory 解析方法的 ClassCastException 不一致

Inconsistent ClassCastException for XmlBeans.Factory parse method

我知道这是一个 非常 的远景,但我已经花了大约两周的时间试图弄清楚,所以任何指向正确方向的想法都可能是无价之宝。

所以,我有一个使用 XmlBeans 的非常古老的应用程序。我的任务是从 Tomcat 7.0.67 迁移到 Tomcat 8.5.11,引入 Spring 会话和 Spring 安全性而不是基于领域的身份验证。在迁移之前,在本地(MacOS、Oracle JDK 8)和 Heroku(Ubuntu、OpenJDK 8)上,一切都运行良好,但在迁移之后,一切都在我的本地环境中运行,但在 Heroku 上,有时,当应用程序尝试将字符串解析为适当的 XmlBean 时,会发生此 ClassCastException:

java.lang.ClassCastException: foo.bar.2.impl.PreferencesDocumentImpl cannot be cast to foo.bar.1.PreferencesDocument
    at foo.bar.1.PreferencesDocument$Factory.parse(Unknown Source)

我有两个由 XmlBeans classes 自动生成的,它们是从两个 xsd-schemas 生成的,没有任何命名空间集。 类同名,但位于不同的包中(出现异常的解析方法位于Factory内部class,其他方法省略):

/*
 * An XML document type.
 * Localname: Preferences
 * Namespace: 
 * Java type: foo.bar.1.PreferencesDocument
 *
 * Automatically generated - do not modify.
 */
package foo.bar.1;

public interface PreferencesDocument extends org.apache.xmlbeans.XmlObject {
    public static final org.apache.xmlbeans.SchemaType type = (org.apache.xmlbeans.SchemaType)
        org.apache.xmlbeans.XmlBeans.typeSystemForClassLoader(PreferencesDocument.class.getClassLoader(), "schemaorg_apache_xmlbeans.system.s2D5798E4F4AFDA8394735C8512CDCBC7").resolveHandle("preferencesa8bfdoctype");

    public static final class Factory {
        public static foo.bar.1.PreferencesDocument parse(java.lang.String xmlAsString) throws org.apache.xmlbeans.XmlException {
          return (foo.bar.PreferencesDocument) org.apache.xmlbeans.XmlBeans.getContextTypeLoader().parse( xmlAsString, type, null ); 
        }   
    }
}

/*
 * An XML document type.
 * Localname: Preferences
 * Namespace: 
 * Java type: foo.bar.1.PreferencesDocument
 *
 * Automatically generated - do not modify.
 */
package foo.bar.1.impl;

public class PreferencesDocumentImpl extends org.apache.xmlbeans.impl.values.XmlComplexContentImpl implements foo.bar.1.PreferencesDocument {
    public PreferencesDocumentImpl(org.apache.xmlbeans.SchemaType sType) {
        super(sType);
    }

    private static final javax.xml.namespace.QName PREFERENCES[=12=] = new javax.xml.namespace.QName("", "Preferences");
}

/*
 * An XML document type.
 * Localname: Preferences
 * Namespace: 
 * Java type: foo.bar.2.PreferencesDocument
 *
 * Automatically generated - do not modify.
 */
package foo.bar.2;  

public interface PreferencesDocument extends org.apache.xmlbeans.XmlObject {
    public static final org.apache.xmlbeans.SchemaType type = (org.apache.xmlbeans.SchemaType)
        org.apache.xmlbeans.XmlBeans.typeSystemForClassLoader(PreferencesDocument.class.getClassLoader(), "schemaorg_apache_xmlbeans.system.sC8953008EC716AA258D3951B84AB1CB7").resolveHandle("preferencesa8bfdoctype");

    public static final class Factory {
        public static foo.bar.2.PreferencesDocument parse(java.lang.String xmlAsString) throws org.apache.xmlbeans.XmlException {
          return (foo.bar.2.PreferencesDocument) org.apache.xmlbeans.XmlBeans.getContextTypeLoader().parse( xmlAsString, type, null ); }

    }
}

/*
 * An XML document type.
 * Localname: Preferences
 * Namespace: 
 * Java type: foo.bar.2.PreferencesDocument
 *
 * Automatically generated - do not modify.
 */
package foo.bar.2.impl;

public class PreferencesDocumentImpl extends org.apache.xmlbeans.impl.values.XmlComplexContentImpl implements foo.bar.2.PreferencesDocument {

    public PreferencesDocumentImpl(org.apache.xmlbeans.SchemaType sType) {
        super(sType);
    }

    private static final javax.xml.namespace.QName PREFERENCES[=12=] = 
        new javax.xml.namespace.QName("", "Preferences");
    }
}

有时,当部署到 Heroku 的应用程序重新启动时,问题消失了,但在再次重新启动后,它又回来了。

根据this,根本原因是命名空间的缺失导致了冲突。但由于我们的要求,我无法添加或更改 xsd 的名称空间。那么你有什么想法为什么它在本地使用 Tomcat 7,在本地使用 Tomcat 8,在 Heroku 上使用 Tomcat 7,但在 Heroku 上使用 Tomcat 8?

提前致谢。

我怀疑问题的不可预测性(即有时在重启后会发生或不会发生)是由于 JVM classloader 的不确定性造成的。如果您有相同 class 的两个不同版本,它们将以不确定的顺序加载。

在这种情况下,听起来您有两个不同的 class 同名(我说得对吗?)。尽管它们是自动生成的,但只有一个会获胜。

我想你必须想办法给 classes 不同的名字(或包)。

它适用于 Tomcat 7 因为 this

之前 Tomcat 8 a Tomcat 的类加载器正在按字母顺序加载资源。我们的应用程序只能因此而运行。

它在 Tomcat 8 + MacOS 上本地工作,因为 Tomcat 8 的类加载器按照 OS 提供的顺序加载资源,如果 OSX,好像是订的。