2011-08-25 19 views
6

मैं आराम से सेवाओं में नया हूं, और अपेक्षाकृत अच्छी शुरुआत हुई, जब तक कि मैंने कुछ जटिल वस्तुओं के साथ खेलने का फैसला नहीं किया। जिस समस्या को मैं मार रहा हूं वह सर्वर पर आने वाली ऑब्जेक्ट को अनमर्शलिंग करने के बारे में है (सर्वर पक्ष पर एक्सएमएल से ऑब्जेक्ट बनाना)।सीएक्सएफ आराम से सेवा जटिल वस्तु unmarshalling काम नहीं करता

नीचे मेरा नमूना (प्रतिनिधि) सेवा का कार्यान्वयन है।

यहां मेरा "जटिल ऑब्जेक्ट" डेटा प्रकार है।

package data; 
import javax.xml.bind.annotation.XmlRootElement; 

@XmlRootElement 
public class ComplexType { 
    private long id; 
    private String name; 
    private Boolean isRegistered; 


    public ComplexType() { 
     super(); 
    } 
    public ComplexType(long id, String name, Boolean isRegistered) { 
     super(); 
     this.id = id; 
     this.name = name; 
     this.isRegistered = isRegistered; 
    } 
    public long getId() { 
     return id; 
    } 
    public void setId(long id) { 
     this.id = id; 
    } 
    public String getName() { 
     return name; 
    } 
    public void setName(String name) { 
     this.name = name; 
    } 
    public Boolean getIsRegistered() { 
     return isRegistered; 
    } 
    public void setIsRegistered(Boolean isRegistered) { 
     this.isRegistered = isRegistered; 
    } 
} 

यह मेरी सेवा एपीआई

package api; 

import javax.ws.rs.FormParam; 
import javax.ws.rs.GET; 
import javax.ws.rs.POST; 
import javax.ws.rs.Path; 
import javax.ws.rs.PathParam; 

import data.ComplexType; 


public interface Service { 
    @GET 
    @Path("/nummembers") 
    int getNumElements(); 

    @GET 
    @Path("/member/{id}") 
    ComplexType getMember(@PathParam("id") long id); 

    @POST 
    @Path("/member") 
    boolean addMember(@FormParam("member") ComplexType member); 
} 

है और इस सेवा के कार्यान्वयन है:

package impl; 

import java.util.HashMap; 
import java.util.Map; 

import data.ComplexType; 
import api.Service; 

public class ServiceImpl implements Service { 
    Map<Long, ComplexType> data; 

    public ServiceImpl() { 
     System.out.println("TestApp Starting"); 
     data = new HashMap<Long, ComplexType>(); 
    } 

    @Override 
    public int getNumElements() { 
     return data.size(); 
    } 

    @Override 
    public ComplexType getMember(long id) { 
     if (data.containsKey(id)) { 
      return data.get(id); 
     } 
     ComplexType ct = 
      new ComplexType(id, "NAME" + new Long(id).toString(), (id % 2 == 1)); 
     data.put(id, ct); 
     return ct; 
    } 

    @Override 
    public boolean addMember(ComplexType member) { 
     int preSize = data.size(); 
     data.put(member.getId(), member); 
     return preSize < data.size(); // True if added 
    } 
} 

तो, जब मैं फोन getNumElements() वहाँ कोई समस्या नहीं है। जब मैं getMember(long id) पर कॉल करता हूं तो मुझे एक सीरियलाइज्ड "कॉम्प्लेक्स टाइप" ठीक लगता है। मैं एक जटिल प्रकार क्रमानुसार और addMember(ComplexType member) को FormParam के रूप में इसे पारित करते हैं, तो मैं हमेशा मिलता Parameter Class data.ComplexType has no constructor with single String parameter, static valueOf(String) or fromString(String) methods

मैं अपने कस्टम प्रदाता प्रदान करने की कोशिश, निम्नलिखित वर्ग लिख कर:

package impl; 

import javax.ws.rs.ext.ContextResolver; 
import javax.xml.bind.JAXBContext; 
import javax.xml.bind.JAXBException; 

import data.ComplexType; 

public class JaxbXmlContextResolver implements ContextResolver<Object> { 
    private static final Class<?>[] classes = new Class[] {ComplexType.class}; 
    private static final JAXBContext context = initContext(); 

    public static JAXBContext initContext() { 
     JAXBContext context = null; 
     try { 
      context = JAXBContext.newInstance(classes); 
     } catch (JAXBException e) { 
      throw new RuntimeException(e); 
     } 
     return context; 
    } 

    @Override 
    public Object getContext(Class<?> arg0) { 
     return context; 
    } 
} 

और विन्यास के बाकी के लिए

<?xml version="1.0"?> 
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" 
"http://java.sun.com/dtd/web-app_2_3.dtd"> 

<web-app> 
    <display-name>TestApp</display-name> 

    <context-param> 
    <param-name>contextConfigLocation</param-name> 
    <param-value>classpath:cxf.xml</param-value> 
    </context-param> 

    <context-param> 
    <param-name>log4jConfigLocation</param-name> 
    <param-value>classpath:log4j.properties</param-value> 
    </context-param> 

    <listener> 
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 
    </listener> 

    <servlet> 
    <servlet-name>CXFServlet</servlet-name> 
    <display-name>CXF Servlet</display-name> 
    <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> 
    <load-on-startup>1</load-on-startup> 
    </servlet> 

    <servlet-mapping> 
    <servlet-name>CXFServlet</servlet-name> 
    <url-pattern>/services/*</url-pattern> 
    </servlet-mapping> 
</web-app> 

और cxf.xml यह करने के लिए संदर्भित करता है::

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xmlns:util="http://www.springframework.org/schema/util" 
     xmlns:jaxrs="http://cxf.apache.org/jaxrs" 
     xmlns:jaxws="http://cxf.apache.org/jaxws" 
     xmlns:cxf="http://cxf.apache.org/core" 
     xsi:schemaLocation="http://www.springframework.org/schema/beans 
          http://www.springframework.org/schema/beans/spring-beans.xsd 
          http://www.springframework.org/schema/util 
          http://www.springframework.org/schema/util/spring-util-2.0.xsd 
          http://cxf.apache.org/jaxrs 
          http://cxf.apache.org/schemas/jaxrs.xsd"> 

    <import resource="classpath:META-INF/cxf/cxf.xml" /> 
    <import resource="classpath:META-INF/cxf/cxf-servlet.xml" /> 

    <bean id="myservice" class="impl.ServiceImpl" /> 
    <bean id="jaxbXmlProvider" class="impl.JaxbXmlContextResolver" /> 

    <jaxrs:server id="connectionService" address="/" > 
    <jaxrs:serviceBeans> 
     <ref bean="myservice" /> 
    </jaxrs:serviceBeans> 
    <jaxrs:extensionMappings> 
     <entry key="xml" value="application/xml" /> 
    </jaxrs:extensionMappings> 
    <jaxrs:providers> 
     <ref bean="jaxbXmlProvider" /> 
    </jaxrs:providers> 
    </jaxrs:server> 
</beans> 
, यहाँ मेरी web.xml है

और पूर्णता के लिए, यहां pom.xml है जिसे मैं ऐप बनाने के लिए उपयोग कर रहा हूं।

<project xmlns="http://maven.apache.org/POM/4.0.0" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 

    <properties> 
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 
    </properties> 
    <modelVersion>4.0.0</modelVersion> 
    <groupId>TESTAPP</groupId> 
    <artifactId>testApp</artifactId> 
    <packaging>war</packaging> 
    <version>1.0</version> 
    <name>Test Application</name> 
    <url>http://www.mycompany.com</url> 

    <dependencies> 
    <dependency> 
     <groupId>log4j</groupId> 
     <artifactId>log4j</artifactId> 
     <version>1.2.16</version> 
    </dependency> 

    <dependency> 
     <groupId>org.springframework</groupId> 
     <artifactId>spring-orm</artifactId> 
     <version>3.0.5.RELEASE</version> 
    </dependency> 

    <dependency> 
     <groupId>org.apache.cxf</groupId> 
     <artifactId>cxf-rt-frontend-jaxrs</artifactId> 
     <version>2.4.1</version> 
     <exclusions> 
     <exclusion> 
      <groupId>wsdl4j</groupId> 
      <artifactId>wsdl4j</artifactId> 
     </exclusion> 
     </exclusions> 
    </dependency> 
    <dependency> 
     <groupId>com.thoughtworks.xstream</groupId> 
     <artifactId>xstream</artifactId> 
     <version>1.3.1</version> 
    </dependency> 
    <dependency> 
     <groupId>net.sf.kxml</groupId> 
     <artifactId>kxml2</artifactId> 
     <version>2.2.2</version> 
    </dependency> 
    <dependency> 
     <groupId>javax.xml.bind</groupId> 
     <artifactId>jaxb-api</artifactId> 
     <version>2.2.1</version> 
    </dependency> 

    </dependencies> 

    <build> 
    <plugins> 
     <plugin> 
     <artifactId>maven-compiler-plugin</artifactId> 
     <version>2.3.2</version> 
     <configuration> 
      <source>1.6</source> 
      <target>1.6</target> 
     </configuration> 
     </plugin> 
    </plugins> 
    </build> 
</project> 

कोई भी मदद (समाधान, पॉइंटर्स, या किसी भी प्रकार की दिशा) की सराहना की जाएगी।

ओह, मैं सीएक्सएफ 2.4.1 और स्प्रिंग 3.0.5.RELEASE का उपयोग कर रहा हूं। यह मेरे तैनात आवेदन की सटीक प्रति है।

धन्यवाद।

+0

के अनुसार: http://cxf.547215.n5.nabble.com/MessageBodyReader-not-picked-up-td564496.html @FormParam चिह्नित पैराम संदेश पाठकों द्वारा संभाला नहीं जाता है, और एक विशिष्ट पैरामीटर हैंडलर की आवश्यकता होती है। तो, मैंने एक कस्टम हैंडलर लिखा, और यह ठीक काम किया। यह मुझे परेशान करता है कि मुझे प्रत्येक ओबीजे के लिए एक हैंडलर लिखना है जिसे मैं एक रूप में प्राप्त करने की उम्मीद करता हूं। यदि कोई समाधान है, तो मैं इसकी सराहना करता हूं। इसके अलावा, मेरी चिंताओं में से एक यह है कि, मैं अपनी सेवा में एक्सएमएल और जेसन दोनों का समर्थन करना चाहता हूं। मुझे यकीन नहीं है कि मैं एक ही ओबीजे के लिए दो हैंडलर कैसे लिख सकता हूं, या क्या मुझे दोनों प्रारूपों को संभालने के लिए अपना हैंडलर लिखना चाहिए। –

उत्तर

0

किसी भी तर्क के साथ एक डिफ़ॉल्ट कन्स्ट्रक्टर लागू करें और प्रत्येक तीन गुणों में से प्रत्येक के लिए तर्क के साथ। इससे जेएक्सबी खुश होना चाहिए।

+0

धन्यवाद। लेकिन यह काम नहीं किया। मैं वास्तव में दोनों रचनाकार था, लेकिन उन्हें मेरे सरलीकृत नमूने में जोड़ने के लिए भूल गए। –

1

जैसा कि यह http://cxf.547215.n5.nabble.com/MessageBodyReader-not-picked-up-td564496.html पर बताया गया था, यह पता चला कि मुझे पैरामीटर हैंडलर की आवश्यकता है। चूंकि मेरे पास मेरे एप्लिकेशन में ऑब्जेक्ट्स का एक बड़ा सेट था, इसलिए मैं अलग-अलग पैरामीटर हैंडलर <> प्रत्येक के लिए नहीं बनाना चाहता था, इसलिए मैंने एक छोटा बदलाव किया:

JAXB inheritance, unmarshal to subclass of marshaled class पर वर्णित तकनीक का उपयोग करके, मैंने बेस टाइप "बेस टाइप "जो सभी एपीआई डेटा ऑब्जेक्ट्स (टाइपए, टाइपबी, ...) विरासत में मिला था।

public class XmlParamHandler implements ParameterHandler<BaseType> { 
    private static final Logger log = LoggerFactory.getLogger(XmlParamHandler.class); 
    private static final JAXBContext jaxbContext = initContext(); 


    private static JAXBContext initContext() throws JAXBException { 
     Class<?>[] classes = new Class[] { 
      com.mycompany.BaseType.class, 
      com.mycompany.TypeA.class, 
      com.mycompany.TypeB.class, 
      com.mycompany.TypeC.class, 
      com.mycompany.TypeD.class, 
      com.mycompany.TypeE.class, 
      com.mycompany.TypeF.class, 
     }; 
     JAXBContext context = JAXBContext.newInstance(classes); 
     return context; 
    } 

    public static <T> T valueOf(String str) throws JAXBException { 
     if (str == null) { 
      return null; 
     } 
     Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); 
     StringReader sr = new StringReader(str); 
     @SuppressWarnings("unchecked") 
     T request = (T) unmarshaller.unmarshal(sr); 
     return request; 
    } 

    @Override 
    public BaseType fromString(String s) { 
     BaseType ct = null; 
     try { 
      return valueOf(s); 
     } catch (JAXBException e) { 
      return null; 
     } 
    } 
} 
0

यह एक जटिल "एक्सएमएल-मार्शेलबल" ऑब्जेक्ट को @ फॉर्मपाराम के रूप में पारित करने के लिए थोड़ा अजीब है। @ फॉर्मपाराम का उद्देश्य ज्यादातर सरल या आदिम प्रकारों जैसे स्ट्रिंग्स, इंटीग्रर्स इत्यादि के लिए किया जाता है।

जेएक्स-आरएस की अच्छी चीजों में से एक यह है कि यह स्वचालित रूप से आपके लिए ऑब्जेक्ट्स मार्शल/अनमशेल करेगा, क्या आप इसे बताते हैं कि कौन से मीडिया प्रकार का उपभोग करना है ।अनुरोध शरीर बजाय एक प्रपत्र पैरामीटर और सेट के रूप में एक सदस्य की एक्सएमएल प्रतिनिधित्व

@POST 
@Path("/member") 
@Consumes({ MediaType.APPLICATION_XML }) 
boolean addMember(ComplexType member); 

और पोस्ट: तो आप के रूप में (@Consumes जोड़ने और सदस्य पर कोई टिप्पणी) अपने अंतिम बिंदु को परिभाषित करने के लिए कर सकते हैं application/xml पर आपके अनुरोध का शीर्षलेख। सीएक्सएफ स्वचालित रूप से कॉम्प्लेक्स टाइप के उदाहरण के लिए अनुरोध निकाय को पढ़ और पार्स करेगा और इसे आपकी विधि में पास कर देगा।

आप इसके लिए कर्ल का उपयोग कर सकते हैं। धारावाहिक वस्तु (member.xml) के साथ एक XML फ़ाइल बनाएँ और चलाएँ:

curl -k --request POST --header "Content-Type: application/xml" --data @member.xml https://localhost:8080/path/to/service 
संबंधित मुद्दे