草庐IT

java - CXF Restful 服务复杂对象解码不起作用

coder 2024-04-05 原文

我是 restful 服务的新手,并且有一个相对良好的开端,直到我决定玩一些复杂的对象。我遇到的问题是关于解码一个到达服务器的对象(在服务器端从 XML 创建对象)。

下面是我的服务示例(代表性)实现。

这是我的“复杂对象”数据类型。

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;
    }
}

这是我的服务API

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) 时,我得到了一个序列化的“ComplexType”就好了。当我序列化一个复杂类型并将其作为 FormParam 传递给 addMember(ComplexType member) 时,我总是得到 Parameter Class 数据。ComplexType 没有带有单个 String 参数的构造函数,static valueOf(String) 或fromString(String) 方法

我尝试通过编写以下类来提供我的自定义提供程序:

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;
    }
}

对于其余配置,这是我的 web.xml:

<?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>

为了完整起见,这里是我用来构建应用程序的 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>

任何帮助(解决方案、指示或任何类型的方向)将不胜感激。

哦,我用的是cxf 2.4.1和Spring 3.0.5.RELEASE。这是我部署的应用程序的精确副本。

谢谢。

最佳答案

http://cxf.547215.n5.nabble.com/MessageBodyReader-not-picked-up-td564496.html 所述,原来我需要一个ParameterHandler。由于我的应用程序中有大量对象,我不想为每个对象创建单独的 ParameterHandler<>,因此我做了一个小改动:

使用 JAXB inheritance, unmarshal to subclass of marshaled class 中描述的技术,我创建了一个基类型“BaseType”,它继承了所有 API 数据对象(TypeA、TypeB、...)。

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;
        }
    }
}

关于java - CXF Restful 服务复杂对象解码不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7196245/

有关java - CXF Restful 服务复杂对象解码不起作用的更多相关文章

  1. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  2. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  3. ruby-on-rails - 按天对 Mongoid 对象进行分组 - 2

    在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev

  4. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  5. ruby-on-rails - 如何验证非模型(甚至非对象)字段 - 2

    我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss

  6. Ruby 写入和读取对象到文件 - 2

    好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信

  7. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  8. ruby-on-rails - 未在 Ruby 中初始化的对象 - 2

    我在Rails工作并有以下类(class):classPlayer当我运行时bundleexecrailsconsole然后尝试:a=Player.new("me",5.0,"UCLA")我回来了:=>#我不知道为什么Player对象不会在这里初始化。关于可能导致此问题的操作/解释的任何建议?谢谢,马里奥格 最佳答案 havenoideawhythePlayerobjectwouldn'tbeinitializedhere它没有初始化很简单,因为你还没有初始化它!您已经覆盖了ActiveRecord::Base初始化方法,但您没有调

  9. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  10. ruby-on-rails - 启动 Rails 服务器时 ImageMagick 的警告 - 2

    最近,当我启动我的Rails服务器时,我收到了一长串警告。虽然它不影响我的应用程序,但我想知道如何解决这些警告。我的估计是imagemagick以某种方式被调用了两次?当我在警告前后检查我的git日志时。我想知道如何解决这个问题。-bcrypt-ruby(3.1.2)-better_errors(1.0.1)+bcrypt(3.1.7)+bcrypt-ruby(3.1.5)-bcrypt(>=3.1.3)+better_errors(1.1.0)bcrypt和imagemagick有关系吗?/Users/rbchris/.rbenv/versions/2.0.0-p247/lib/ru

随机推荐