ClassCastException intermittente da ElementNSImpl al tipo proprio durante unmarshalling
-
22-08-2019 - |
Domanda
Stiamo vivendo uno estremamente difficile da rintracciare problema per cui stiamo assistendo ClassCastExceptions a volte quando si cerca di iterare su una lista di oggetti deserializzati. Il bit importante è a volte , dopo un riavvio del particolare codice funziona bene. Questo sembra indicare la direzione di concorrenza / temporizzazione / condizione di competizione. Posso confermare che né il JAXBContext, né le marshaller e unmarshallers vengono utilizzati contemporaneamente. Siamo andati per quanto serializzazione accesso ad essi attraverso il blocco.
Tuttavia, poiché si corre su una piattaforma OSGi in cui i singoli fasci sono sempre inizializzati in modo asincrono attraverso DM primavera può essere che 2 diversi fasci stanno creando il loro JAXBContext allo stesso tempo.
In ogni caso Gradirei qualsiasi puntatori verso una spiegazione per quello che potrebbe causare questi intermittenti ClassCastExceptions. L'intermittenza è importante dal momento che indicano che il codice stesso è normalmente lavorando bene, ma che qualche fattore esterno sembra influenzare il comportamento.
Ecco un esempio specifico di eccezione (nota ho rimosso la compagnia cose specifiche):
Caused by: java.lang.ClassCastException: com.sun.org.apache.xerces.internal.dom.ElementNSImpl cannot be cast to com.foobar.TunnelType
at com.foobar.NetMonitorImpl.getVpnStatus(NetMonitorImpl.java:180)
Tale metodo in linea 180 è una per () costruire un ciclo su un insieme di oggetti TunnelType all'interno di un oggetto deserializzati (detto deserializzazione funziona bene BTW).
Dato che l'unmarshalling oggetto reale è andato bene, è anche fisicamente possibile per JAXB di lasciare oggetti ElementNSImpl all'interno delle collezioni annidate?
ambiente runtime:
- JAXB 2.1
- OSGi
- Primavera DM
- Il JAXBContext viene inizializzato con il ClassLoader del fascio contenente le classi siano radunate / deserializzati
Soluzione 3
Fuori della disperazione ci siamo rivolti alla sincronizzazione sull'oggetto JAXBContext.class
, vedendo questo come l'unica residua possibilità per qualche condizione di competizione e almeno noi non sono stati in grado di riprodurre di nuovo la questione. Ecco il codice critica:
synchronized (JAXBContext.class) {
context = JAXBContext.newInstance(packageList, classLoader);
}
Altri suggerimenti
ottengo questa eccezione solo quando mi dimentico di dire JAXBContext su ALL per-essere-radunate tipi si potrebbe avere a che fare con.
JAXBContext.newInstance(MyClass1.class,MyClass2.class, [...]);
Nessuno dei due approcci suggerito qui ha fatto per me. Tuttavia, questo ha risolto il mio problema
@XmlAnyElement(lax = true)
public List<Foo> foos;
La clausola sincronizzato sopra ha risolto il problema anche per me, ma sembra che il contesto non dovrebbe essere una variabile locale. Invece dovrebbe essere una variabile di istanza, o statica. Non ero in grado di refactoring il mio codice come mi piacerebbe che, così invece ho spostato il contesto in un inizializzatore statico, che non è perfetto, ma sembra funzionare:
private static Unmarshaller um;
static{
try {
final JAXBContext ctx = JAXBContext.newInstance(ObjectFactory.class.getPackage().getName());
um = ctx.createUnmarshaller();
} catch (final JAXBException e) {
e.printStackTrace();
}
}