2015-05-25 3 views
0

Кажется, в MOXy есть ошибка. Часть кода ниже отлично работает, когда поля в классе Request объявлены как metaInfo, а затем содержимое, но тест терпит неудачу при unmarshalling с исключением при объявлении полей в обратном порядке (сначала содержимое и metaInfo second).MOXy порядок полей в целевом объекте Java имеет значение при unmarshalling

The exception thrown is: 
Going with type: APPLICATION_XML 
Original request = {content=Payload = {[one, two, three]}, metaInfo=requestMetaInfo = {confirmation=false}} 
Marshaled as application/xml: <?xml version="1.0" encoding="UTF-8"?><request><collection><collection xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">one</collection><collection xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">two</collection><collection xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">three</collection></collection><metaInfo><confirmation>false</confirmation></metaInfo></request> 
Local Exception Stack: 
Exception [EclipseLink-32] (Eclipse Persistence Services - 2.6.0.v20150309-bf26070): org.eclipse.persistence.exceptions.DescriptorException 
Exception Description: Trying to set value [[one, two, three]] for instance variable [collection] of type [java.util.Collection] in the object. The specified object is not an instance of the class or interface declaring the underlying field, or an unwrapping conversion has failed. 
Internal Exception: java.lang.IllegalArgumentException: Can not set java.util.Collection field test2.TestCase2$Payload.collection to test2.TestCase2$RequestMetaInfo 
Mapping: org.eclipse.persistence.oxm.mappings.XMLCompositeCollectionMapping[collection] 
Descriptor: XMLDescriptor(test2.TestCase2$Payload --> [DatabaseTable(collection)]) 
    at org.eclipse.persistence.exceptions.DescriptorException.illegalArgumentWhileSettingValueThruInstanceVariableAccessor(DescriptorException.java:703) 
    at org.eclipse.persistence.internal.descriptors.InstanceVariableAttributeAccessor.setAttributeValueInObject(InstanceVariableAttributeAccessor.java:188) 
    at org.eclipse.persistence.mappings.DatabaseMapping.setAttributeValueInObject(DatabaseMapping.java:1652) 
    at org.eclipse.persistence.oxm.mappings.XMLCompositeCollectionMapping.setAttributeValueInObject(XMLCompositeCollectionMapping.java:741) 
    at org.eclipse.persistence.internal.oxm.XMLCompositeCollectionMappingNodeValue.setContainerInstance(XMLCompositeCollectionMappingNodeValue.java:265) 
    at org.eclipse.persistence.internal.oxm.record.UnmarshalRecordImpl.endDocument(UnmarshalRecordImpl.java:628) 
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endDocument(AbstractSAXParser.java:745) 
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:515) 
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:848) 
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:777) 
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141) 
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1213) 
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:648) 
    at org.eclipse.persistence.internal.oxm.record.XMLReader.parse(XMLReader.java:243) 
    at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:978) 
    at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:425) 
    at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:635) 
    at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:706) 
    at org.eclipse.persistence.internal.oxm.XMLUnmarshaller.unmarshal(XMLUnmarshaller.java:643) 
    at org.eclipse.persistence.jaxb.JAXBUnmarshaller.unmarshal(JAXBUnmarshaller.java:339) 
    at test2.TestCase2.main(TestCase2.java:67) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:606) 
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134) 
Caused by: java.lang.IllegalArgumentException: Can not set java.util.Collection field test2.TestCase2$Payload.collection to test2.TestCase2$RequestMetaInfo 
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:164) 
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:168) 
    at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:55) 
    at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:75) 
    at java.lang.reflect.Field.set(Field.java:741) 
    at org.eclipse.persistence.internal.descriptors.InstanceVariableAttributeAccessor.setAttributeValueInObject(InstanceVariableAttributeAccessor.java:141) 
    ... 24 more 

Это тест, чтобы воспроизвести проблему.

package test2; 

import org.eclipse.persistence.jaxb.JAXBContext; 
import org.eclipse.persistence.jaxb.JAXBContextFactory; 
import org.eclipse.persistence.jaxb.MarshallerProperties; 
import org.eclipse.persistence.jaxb.UnmarshallerProperties; 
import org.eclipse.persistence.oxm.MediaType; 

import javax.xml.bind.Marshaller; 
import javax.xml.bind.Unmarshaller; 
import javax.xml.bind.annotation.*; 
import javax.xml.transform.stream.StreamResult; 
import javax.xml.transform.stream.StreamSource; 
import java.io.StringReader; 
import java.io.StringWriter; 
import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.Collection; 
import java.util.Collections; 

/** 
* Test that fails if Request.content field declared before than Request.metaInfo, but works well if 
* Request.metaInfo goes first in declaration 
* 
* MOXy 2.6.0 
*/ 
public class TestCase2 { 
    @XmlRootElement(name = "request") 
    @XmlAccessorType(XmlAccessType.FIELD) 
    public static class Request<T> { 
     @XmlAnyElement(lax = true) 
     private T content; // NB!: Causes test failure if declared before metaInfo, if declaration order is changed, things work 

     @XmlElement 
     private RequestMetaInfo metaInfo; 

     public Request() { 
     } 

     public Request(T content, RequestMetaInfo metaInfo) { 
      this.content = content; 
      this.metaInfo = metaInfo; 
     } 

     @Override 
     public String toString() { 
      return "request = {" + "content=" + content + ", metaInfo=" + metaInfo +'}'; 
     } 

    } 
    @XmlRootElement 
    @XmlAccessorType(XmlAccessType.FIELD) 
    public static class RequestMetaInfo { 
     @XmlElement 
     private Boolean confirmation = false; 
     @Override 
     public String toString() { 
      return "requestMetaInfo = {" + "confirmation=" + confirmation +'}'; 
     } 
    } 

    @XmlRootElement(name = "collection") 
    @XmlAccessorType(XmlAccessType.FIELD) 
    public static class Payload<T> { 
     @XmlElement 
     private Collection collection = new ArrayList(); 

     public Payload(){} 
     public Payload(Collection<T> collection){ 
      this.collection.addAll(collection); 
     } 

     public Collection<T> getCollection() { 
      return collection; 
     } 

     @Override 
     public String toString() { 
      return "Payload = {" + getCollection()+"}"; 
     } 
    } 

    // Element name holding value of primitive types 
    public static final String VALUE_ELEMENT = "value"; 
    // Attribute prefix in JSON 
    public static final String ATTRIBUTE_PREFIX = "@"; 
    public static void main(String... args) { 
     try { 
      for (MediaType type : new MediaType[]{MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) { 
       System.out.println("Going with type: " + type); 
       JAXBContext context = (JAXBContext) JAXBContextFactory.createContext(
        new Class[]{ 
         Request.class, 
         RequestMetaInfo.class, 
         Payload.class 
        }, 
        Collections.emptyMap()); 

       Marshaller marshaller = context.createMarshaller(); 
       marshaller.setProperty(MarshallerProperties.MEDIA_TYPE, type); 
       marshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, false); 
       marshaller.setProperty(MarshallerProperties.JSON_ATTRIBUTE_PREFIX, ATTRIBUTE_PREFIX); 
       marshaller.setProperty(MarshallerProperties.JSON_VALUE_WRAPPER, VALUE_ELEMENT); 
       marshaller.setProperty(UnmarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, true); 

       Request original = new Request(
        new Payload(Arrays.asList("one","two","three")), 
        new RequestMetaInfo() 
       ); 
       System.out.println("Original " + original.toString()); 

       StreamResult result = new StreamResult(new StringWriter()); 
       marshaller.marshal(original, result); 
       String generated = result.getWriter().toString(); 
       System.out.println("Marshaled as " + type.getMediaType() + ": " + generated); 

       Unmarshaller unmarshaller = context.createUnmarshaller(); 
       unmarshaller.setProperty(UnmarshallerProperties.MEDIA_TYPE, type); 
       unmarshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, false); 
       unmarshaller.setProperty(UnmarshallerProperties.JSON_ATTRIBUTE_PREFIX, ATTRIBUTE_PREFIX); 
       unmarshaller.setProperty(UnmarshallerProperties.JSON_VALUE_WRAPPER, VALUE_ELEMENT); 
       unmarshaller.setProperty(UnmarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, true); 


       Request unmarshalled = unmarshaller.unmarshal(new StreamSource(new StringReader(generated)), Request.class).getValue(); 
       System.out.println("Unmarshaled " + unmarshalled.toString()); 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 

Пожалуйста, любые идеи, что может быть неправильным?

ответ

3

После некоторой отладки я узнал, что ошибка может быть, вероятно, в org.eclipse.persistence.internal.oxm.record.UnmarshalRecordImpl.endDocument().

Коллекция, заполненная контейнеромValues, не получила нулевого значения после того, как Payload.collection был неармирован. Затем, когда moxy unmarshalls элемент metaInfo пытается обработать его как бы Payload.collection, присваивая коллекции Request.metaInfo, что вызывает исключение.

Я сделал уродливое обходное решение (так как я не могу исправить его) и просто изменил порядок объявления полей в объекте Request, но я считаю, что он будет зафиксирован один день в MOXy.

UPDATE: Я подал ошибку в Bugzilla Moxy: https://bugs.eclipse.org/bugs/show_bug.cgi?id=468337

0

У меня была такая же проблема. Мое решение:

@XmlMixed 
@XmlAnyElement(lax = true) 
private String content; 

Наслаждайтесь;)