使用"类型" MOXy JAXB异常作为子类判别者处理的字段

时间:2014-12-04 13:24:04

标签: java json jaxb moxy

我正在编写一个简单的地理编码应用程序,使用Jersey REST客户端api,它使用OpenStreetMap / Mapquest Nominatim REST服务。调用返回类似于此的JSON响应:

[ {
  "place_id":"249137377",
  "licence":"Data \u00a9 OpenStreetMap contributors, ODbL 1.0. http:\/\/www.openstreetmap.org\/copyright",
  "boundingbox":["32.834854904644","32.834954904644","-79.243545952863","-79.243445952863"],
  "lat":"32.8349049046436",
  "lon":"-79.2434959528633",
  "display_name":"9000, Maple Avenue, Bedford, Trimble County, Kentucky, 40006, United States of America",
  "class":"place",
  "type":"house",
  "importance":0.521
} ]

如您所见,它包含一个名为type的字段。在解组此JSON响应时,会引发以下异常:

Caused by: Exception [EclipseLink-43] (Eclipse Persistence Services - 2.5.1.v20130918-f2b9fc5):     org.eclipse.persistence.exceptions.DescriptorException
Exception Description: Missing class for indicator field value [house] of type [class java.lang.String].
Descriptor: XMLDescriptor(com.edc.c2c.geospatial.nominatim.v1.model.impl.NominatimResponse --> [])
    at org.eclipse.persistence.exceptions.DescriptorException.missingClassForIndicatorFieldValue(DescriptorException.java:940)
    at org.eclipse.persistence.internal.oxm.QNameInheritancePolicy.classFromRow(QNameInheritancePolicy.java:266)
    at org.eclipse.persistence.internal.oxm.TreeObjectBuilder.classFromRow(TreeObjectBuilder.java:182)
    at org.eclipse.persistence.internal.oxm.TreeObjectBuilder.classFromRow(TreeObjectBuilder.java:1)
    at org.eclipse.persistence.internal.oxm.record.UnmarshalRecordImpl.initializeRecord(UnmarshalRecordImpl.java:502)
    at org.eclipse.persistence.internal.oxm.record.UnmarshalRecordImpl.startElement(UnmarshalRecordImpl.java:740)
    at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parseRoot(JSONReader.java:177)
    at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parseRoot(JSONReader.java:195)
    at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parse(JSONReader.java:125)
    at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:972)
    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:703)
    at org.eclipse.persistence.oxm.XMLUnmarshaller.unmarshal(XMLUnmarshaller.java:655)
    at org.eclipse.persistence.jaxb.JAXBUnmarshaller.unmarshal(JAXBUnmarshaller.java:301)
    at org.eclipse.persistence.jaxb.rs.MOXyJsonProvider.readFrom(MOXyJsonProvider.java:597)
    at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.aroundReadFrom(ReaderInterceptorExecutor.java:188)
    at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:134)
    at org.glassfish.jersey.message.internal.MessageBodyFactory.readFrom(MessageBodyFactory.java:988)
    at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:833)
    at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:768)
    at org.glassfish.jersey.client.InboundJaxrsResponse.readEntity(InboundJaxrsResponse.java:96)
    at org.glassfish.jersey.client.JerseyInvocation.translate(JerseyInvocation.java:761)
    ... 31 more

我推测错误正在发生,因为type被视为一种类鉴别器,house被解释为子类而不是简单的字符串。

这是用于调用服务的代码:

public Coordinate lookup( StreetAddress a_StreetAddress )
{
    LatLongCoordinate result = null ;

    Client client = ClientBuilder.newClient() ;
    client.register( MoxyXmlFeature.class ) ;

    WebTarget target = client.target( this.getEndPointUrl() ) ;
    NominatimResponse response =
        target
            .queryParam( "q", a_StreetAddress.format() ) // Buildup GET request
            .queryParam( "format", "json" )
            .queryParam( "addressdetails", "0" )
            .queryParam( "limit", "1" )
            .request( MediaType.APPLICATION_JSON_TYPE )  // Only accept JSON back in response
            .buildGet()
            .invoke( NominatimResponse.class )
            ;

    if ( ( response != null ) && ( response.getLatitude() != null ) && ( response.getLongitude() != null ) ) {
        result = new LatLongCoordinate( response.getLatitude(), response.getLongitude() ) ;
    }

    return result ;
}

这是我创建的NominatimResponse类,用于将响应解组为:

public class NominatimResponse extends AbstractGeospatialModelObject
{
    private static final long serialVersionUID = -7514888439468843335L ;

    @XmlElement( name = "place_id" ) 
    private String m_PlaceId = null ;
    @XmlElement( name = "license" ) 
    private String m_License = null ;
    @XmlElement( name = "osm_type" ) 
    private String m_OsmType = null ;
    @XmlElement( name = "osm_id" ) 
    private String m_OsmId = null ;
    @XmlElement( name = "bounding_box")
    private Double[] m_BoundingBox = null ;
    @XmlElement( name = "lat" ) 
    private Double m_Latitude = null ;
    @XmlElement( name = "lon" ) 
    private Double m_Longitude = null ;
    @XmlElement( name = "display_name" ) 
    private String m_DisplayName = null ;
    @XmlElement( name = "class" ) 
    private String m_Classifier = null ;
    @XmlElement( name = "type" )
    private String m_Type = null ;
    @XmlElement( name = "importance" ) 
    private Double m_Importance = null ;


    /**
     * @return the placeId
     */
    public String getPlaceId()
    {
    return this.m_PlaceId ;
    }
    /**
     * @param a_placeId the placeId to set
     */
    public void setPlaceId( String a_placeId )
    {
    this.m_PlaceId = a_placeId ;
    }
    /**
     * @return the license
     */
    public String getLicense()
    {
    return this.m_License ;
    }
    /**
     * @param a_license the license to set
     */
    public void setLicense( String a_license )
    {
    this.m_License = a_license ;
    }
    /**
     * @return the osmType
     */
    public String getOsmType()
    {
    return this.m_OsmType ;
    }
    /**
     * @param a_osmType the osmType to set
     */
    public void setOsmType( String a_osmType )
    {
    this.m_OsmType = a_osmType ;
    }
    /**
     * @return the osmId
     */
    public String getOsmId()
    {
    return this.m_OsmId ;
    }
    /**
     * @param a_osmId the osmId to set
     */
    public void setOsmId( String a_osmId )
    {
    this.m_OsmId = a_osmId ;
    }
    /**
     * @return the boundingBox
     */
    public Double[] getBoundingBox()
    {
    return this.m_BoundingBox ;
    }
    /**
     * @param a_boundingBox the boundingBox to set
     */
    public void setBoundingBox( Double[] a_boundingBox )
    {
    this.m_BoundingBox = a_boundingBox ;
    }
    /**
     * @return the latitude
     */
    public Double getLatitude()
    {
    return this.m_Latitude ;
    }
    /**
     * @param a_latitude the latitude to set
     */
    public void setLatitude( Double a_latitude )
    {
    this.m_Latitude = a_latitude ;
    }
    /**
     * @return the longitude
     */
    public Double getLongitude()
    {
    return this.m_Longitude ;
    }
    /**
     * @param a_longitude the longitude to set
     */
    public void setLongitude( Double a_longitude )
    {
    this.m_Longitude = a_longitude ;
    }
    /**
     * @return the displayName
     */
    public String getDisplayName()
    {
    return this.m_DisplayName ;
    }
    /**
     * @param a_displayName the displayName to set
     */
    public void setDisplayName( String a_displayName )
    {
    this.m_DisplayName = a_displayName ;
    }
    /**
     * @return the classifier
     */
    public String getClassifier()
    {
    return this.m_Classifier ;
    }
    /**
     * @param a_classifier the classifier to set
     */
    public void setClassifier( String a_classifier )
    {
    this.m_Classifier = a_classifier ;
    }
    /**
     * @return the type
     */
    public String getType()
    {
    return this.m_Type ;
    }
    /**
     * @param a_type the type to set
     */
    public void setType( String a_type )
    {
    this.m_Type = a_type ;
    }
    /**
     * @return the importance
     */
    public Double getImportance()
    {
    return this.m_Importance ;
    }
    /**
     * @param a_importance the importance to set
     */
    public void setImportance( Double a_importance )
    {
    this.m_Importance = a_importance ;
    }

}

有没有办法阻止MOXy以type的方式对待它?似乎它需要与@XmlDiscriminatorNode等相反。

提前感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

我遇到了同样的问题。我从Moxy换到杰克逊,杰克逊似乎正好处理这个案子。

只需更改构建脚本中的 jersey-media 依赖关系

即可
// remove this
compile 'org.glassfish.jersey.media:jersey-media-moxy:2.13'

// add this
compile 'org.glassfish.jersey.media:jersey-media-json-jackson:2.13'