草庐IT

java - JAXB for lists 为 JSON 或 XML 自然返回

coder 2024-03-13 原文

我将 MOXy 与 Jersey 一起使用来实现 RESTful API,并希望自然地为 JSON 和 XML 返回列表,我的意思是 XML 包含用于整个集合以及集合项的元素标记,而JSON 仅包含集合的标签。

例如,我想返回一个包含设施和位置嵌套列表的“组织”资源。作为 XML:

<organisation>
  <id>1</id>
  <name>XYZ</name>
  <facilities>
    <facility>
      <id>1</id>
      <text>Telephone</text>
    </facility>
    <facility>
      <id>3</id>
      <text>Whiteboard</text>
    </facility>
  </facilities>
  <locations>
    <location>
      <id>1</id>
      <kind>REGION</kind>
      <name>London</name>
    </location>
    <location>
      <id>2</id>
      <kind>REGION</kind>
      <name>Manchester</name>
    </location>
  </locations>
</organisation>

作为 JSON:

{
  "id": 1,
  "name": "XYZ",
  "facilities": [
    {
      "id": 1,
      "text": "Telephone"
    },
    {
      "id": 3,
      "text": "Whiteboard"
    }
  ],
  "locations": [
    {
      "id": 1,
      "kind": "REGION",
      "name": "London"
    },
    {
      "id": 2,
      "kind": "REGION",
      "name": "Manchester"
    }
  ]
}

不幸的是,我似乎无法获得允许我为 XML 和 JSON 返回类似输出的代码库。如果我使用一个类来包装嵌套列表,那么 XML 看起来是正确的,但 JSON 不正确(请参阅下面的“ExternalFacilities”)。如果我将嵌套列表定义为 ArrayList 子类,则 JSON 显示正确但 XML 不正确(请参阅下面的“ExternalLocations”)。

显示“设施”列表正确但“位置”不正确的 XML 示例

看到没有 XML 元素包装“位置”列表(因为有“设施”),而且每个位置都有一个复数元素名称。

<organisation>
  <id>1</id>
  <name>XYZ</name>
  <facilities>
    <facility>
      <id>1</id>
      <text>Telephone</text>
    </facility>
    <facility>
        <id>3</id>
        <text>Whiteboard</text>
    </facility>
  </facilities>
  <locations>
    <id>1</id>
    <kind>REGION</kind>
    <name>London</name>
  </locations>
  <locations>
    <id>2</id>
    <kind>REGION</kind>
    <name>Manchester</name>
  </locations>
</organisation>

显示“位置”列表正确但“设施”列表不正确的 JSON 示例

看到“设施”列表是一个包含 JSON 数组的 JSON 对象,而我只想要 JSON 数组(具有复数元素名称)。

{
  "id": 1,
  "name": "XYZ",
  "facilities": {
    "facility": [
        {
            "id": 1,
            "text": "Telephone"
        },
        {
            "id": 3,
            "text": "Whiteboard"
        }
    ]
  },
  "locations": [
    {
      "id": 1,
      "kind": "REGION",
      "name": "London"
    },
    {
      "id": 2,
      "kind": "REGION",
      "name": "Manchester"
    }
  ]
}

上面的示例是使用相同的代码生成的,只是更改了 Accept HTTP header 以使 Jersey 返回 JSON 而不是 XML。以下是类(class)的摘录:

ExternalOrganisation.java

@XmlRootElement(name="organisation")
@XmlAccessorType(XmlAccessType.FIELD)
public class ExternalOrganisation {

   private String             name;
   private ExternalFacilities facilities;
   private ExternalLocations  locations;

   ...

}

ExternalFacilities.java

@XmlRootElement(name="facilities")
public class ExternalFacilities {
  @XmlElementRef
  private List<ExternalFacility> list;
  ...
}

ExternalLocations.java

@XmlRootElement(name="locations")
public class ExternalLocations extends ArrayList<ExternalLocation> {
  ...
}

ExternalFacility.java

@XmlRootElement(name="facility")
@XmlType(propOrder={"id", "uri", "kind", "text"})
public class ExternalFacility extends ExternalBase {
    // id inherited
    private String text;
    ....
}

ExternalLocation.java

@XmlRootElement(name="location")
@XmlType(propOrder={"id", "kind", "name"})
public class ExternalLocation extends ExternalBase {
    // id inherited
    @XmlElement private LocationKind kind;
    @XmlElement private String       name;
    ...
}

初看起来类似于this question但我并不想在我的列表中混合对象的类型。

最佳答案

您可以执行以下操作以获得所需的 XML 和 JSON 表示形式:

第 1 步 - 利用 @XMLElementWrapper

代替:

@XmlRootElement(name="organisation")
@XmlAccessorType(XmlAccessType.FIELD)
public class ExternalOrganisation {

   private String             name;
   private ExternalFacilities facilities;
   private ExternalLocations  locations;

   ...

}

您可以使用 @XmlElementWrapper 执行以下操作(参见:http://blog.bdoughan.com/2010/09/jaxb-collection-properties.html):

@XmlRootElement(name="organisation")
@XmlAccessorType(XmlAccessType.FIELD)
public class ExternalOrganisation {

   private String             name;

   @XmlElementWrapper
   @XmlElementRef
   private List<ExternalFacility> facilities;

   @XmlElementWrapper
   @XmlElementRef
   private List<ExternalLocation>  locations;

   ...

}

第 2 步 - 利用 MOXy 的包装器作为数组名称属性

通过将包装器指定为数组名称属性,MOXy 将使用来自 @XmlElementWrapper 的值作为 JSON 数组名称。

import java.util.*;
import javax.ws.rs.core.Application;
import org.eclipse.persistence.jaxb.rs.MOXyJsonProvider;

public class YourApplication  extends Application {

    @Override
    public Set<Class<?>> getClasses() {
        HashSet<Class<?>> set = new HashSet<Class<?>>(1);
        set.add(YourService.class);
        return set;
    }

    @Override
    public Set<Object> getSingletons() {
        MOXyJsonProvider moxyJsonProvider = new MOXyJsonProvider();
        moxyJsonProvider.setWrapperAsArrayName(true);

        HashSet<Object> set = new HashSet<Object>(1);
        set.add(moxyJsonProvider);
        return set;
    }

} 

了解更多信息

关于java - JAXB for lists 为 JSON 或 XML 自然返回,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20890731/

有关java - JAXB for lists 为 JSON 或 XML 自然返回的更多相关文章

  1. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  2. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

  3. ruby-on-rails - Rails HTML 请求渲染 JSON - 2

    在我的Controller中,我通过以下方式在我的index方法中支持HTML和JSON:respond_todo|format|format.htmlformat.json{renderjson:@user}end在浏览器中拉起它时,它会自然地以HTML呈现。但是,当我对/user资源进行内容类型为application/json的curl调用时(因为它是索引方法),我仍然将HTML作为响应。如何获取JSON作为响应?我还需要说明什么? 最佳答案 您应该将.json附加到请求的url,提供的格式在routes.rb的路径中定义。这

  4. 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/

  5. ruby - 检查字符串是否包含散列中的任何键并返回它包含的键的值 - 2

    我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案

  6. ruby - Ruby 中的隐式返回值是怎么回事? - 2

    所以我开始关注ruby​​,很多东西看起来不错,但我对隐式return语句很反感。我理解默认情况下让所有内容返回self或nil但不是语句的最后一个值。对我来说,它看起来非常脆弱(尤其是)如果你正在使用一个不打算返回某些东西的方法(尤其是一个改变状态/破坏性方法的函数!),其他人可能最终依赖于一个返回对方法的目的并不重要,并且有很大的改变机会。隐式返回有什么意义?有没有办法让事情变得更简单?总是有返回以防止隐含返回被认为是好的做法吗?我是不是太担心这个了?附言当人们想要从方法中返回特定的东西时,他们是否经常使用隐式返回,这不是让你组中的其他人更容易破坏彼此的代码吗?当然,记录一切并给出

  7. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  8. ruby-on-rails - 如何使用 Rack 接收 JSON 对象 - 2

    我有一个非常简单的RubyRack服务器,例如:app=Proc.newdo|env|req=Rack::Request.new(env).paramspreq.inspect[200,{'Content-Type'=>'text/plain'},['Somebody']]endRack::Handler::Thin.run(app,:Port=>4001,:threaded=>true)每当我使用JSON对象向服务器发送POSTHTTP请求时:{"session":{"accountId":String,"callId":String,"from":Object,"headers":

  9. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

  10. ruby-on-rails - ruby 日期方程不返回预期的真值 - 2

    为什么以下不同?Time.now.end_of_day==Time.now.end_of_day-0.days#falseTime.now.end_of_day.to_s==Time.now.end_of_day-0.days.to_s#true 最佳答案 因为纳秒数不同:ruby-1.9.2-p180:014>(Time.now.end_of_day-0.days).nsec=>999999000ruby-1.9.2-p180:015>Time.now.end_of_day.nsec=>999999998

随机推荐