Jersey从cglib bean为JSON和XML生成不同的输出

时间:2013-09-12 17:59:28

标签: xml json rest jersey cglib

我想使用动态生成的bean作为Jersey REST WS的输出。我不知道在编译时会要求哪些属性。我可以返回一个包含字段列表的bean,但我想尝试返回一个动态创建属性的bean,因为输出会更好一些。

我试图使用cglib构建一个bean实例并将其返回到Jersey框架以编组为JSON / XML。我遇到了下面的问题,如果有人可以提出建议我会很感激。我不知道我是否可以使用泛型魔法或创建自定义处理程序来解决。

使用的库:Tomcat 6.0.18,Java 1.6.0_17,Jersey v1.8,cglib v2.2

SearchWS

@Path("/search")
public class SearchWS
{
private static final Logger log = Logger.getLogger(SearchWS.class.getName());

@POST
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public GenericObject getXML(@Context final HttpServletRequest request, @FormParam("query") final String query)
        throws Exception
{
    log.debug("Entering");
    final IDAO dao = new DAOImpl();
    return dao.search(query).getResults().get(0);
}

}

GenericObject bean类

@XmlRootElement(name = "object")
@XmlAccessorType(XmlAccessType.PROPERTY)
public class GenericObject
{

}

DAO从查询中创建键/值对的映射并构建GenericObject子类实例

public GenericObject buildGenericBean(final Map<String, String> propertyValues) throws Exception
{
    log.debug("Entering");

    BeanGenerator bg = new BeanGenerator();
    bg.setSuperclass(GenericObject.class);

    bg.setNamingPolicy(new net.sf.cglib.core.NamingPolicy()
    {
        @Override
        public String getClassName(final String prefix, final String source, final Object key, final Predicate names)
        {
            return prefix + "Impl";
        }
    });

    Set<String> keys = propertyValues.keySet();
    for (String nextKey : keys)
    {
        bg.addProperty(nextKey, String.class);
    }
    GenericObject bean = (GenericObject) bg.create();

    for (String nextKey : keys)
    {
        setProperty(bean, nextKey, propertyValues.get(nextKey));
    }

    log.debug("Leaving");
    return bean;
}

当客户端请求JSON内容(&#34; application / json&#34;)时,它会根据作为表单参数提交的SQL查询按预期生成一些不错的输出:

{
    "country": "DZ",
    "title": "foo",
    "theme": "foo",
    "subject": "foo",
    "owner_name": "foo",
    "creation_date": "16/05/2013 06:20:10 PM",
    "publication_needed": "1",
    "language_code": "en",
    "modify_date": "21/05/2013 05:08:15 PM",
    "classification": "0"
}

将请求的内容类型设置为XML(&#34; application / xml&#34;)会导致以下错误。我曾希望泽西岛能确保产量相等,例如以文本内容作为属性值的属性命名的元素。我不是XML编组专家,所以可能会遗漏一些东西。如何在XML中获得等效输出?

Caused by: com.sun.jersey.api.MessageException: A message body writer for Java class xxx.model.GenericObjectImpl, and Java type class xxx.model.GenericObjectImpl, and MIME media type application/xml was not found

1 个答案:

答案 0 :(得分:0)

cglib创建一个子类以创建代理。这意味着Jersey将接收GenericObject的子类而不是直接实例。但注释XMLRootElement未声明为@Inherited,因此即使是GenericObject,此注释也不会出现在此代理子类中。

由于Jersey没有在实际类型上找到这个注释,它告诉你它不知道如何处理它。遗憾的是,使用cglib解决这个问题并不容易。您可能希望直接尝试其他检测库,例如javassist或ASM。

如果你想直接解决泽西岛的问题。但是,您可以创建自己的编组程序,以检查该类是否为GenericObject的子类,以便创建默认的XML输出。 (看看泽西岛MessageBodyWriter寻求帮助。)