xml 和 json 之间根元素的序列化差异

Serialization difference of root element between xml and json

我正在尝试为我们拥有的一组 class 确定什么是正确的 JSON 序列化输出。我们对 XML 使用 .Net XmlSerializer,对 JSON 使用 JSON.Net。对于一组 classes,例如:

public class User
{
    public AccountType[] Account {get; set;};
}

public class AccountType
{
    public AccountDetailType[] Detail {get; set;}
}

public class AccountDetailType
{
    //properties here
}

XML 序列化程序产生如下内容:

<User>
    <Account>
        <Detail>
        </Detail>
    </Account>
</User>

与根级别 'User' 节点,并且 Json.Net JsonConvert.SerializeObject(object); 产生:

   {
      "account": 
      [
        {
          "detail": 
          [
            {
              
            }
          ],
          
        }
      ], 
    }

请注意,父 'User' 类型是 JSON 输出中的 'missing'。

我们正在与客户端交换此 class 层次结构的 xsd 架构,但是当他们生成 Java classes 并将对象序列化为 JSON(不知道用的是哪个库),他们的JSON长这样:

    {
    "User": // is this correct?
    {
      "account":
      [
        {
          "detail":
          [
            {
            }
          ],
        }
      ],
    }
}

他们坚持认为,我们提供的xsd,他们只能在JSON中生成一个JSON,其顶级/根元素名称为'User'。我认为这只是他们的序列化设置的问题。我现在没有 xsd 样本。

谁能解释一下:

  1. 哪个 JSON 输出,有或没有顶级元素,是正确的还是都有效? XML总是写根级节点,是JSON中的'optional'吗?
  2. 这里有什么可能的解决方案?我们希望他们在没有顶级用户节点的情况下生成 JSON(他们使用 Java)。他们坚持他们的库总是在 JSON 输出中生成顶级 'User' 节点,并且对此无能为力!

我同意@AlbertoSinigaglia 的观点。

两种 JSON 结构(有和没有 "User": 值)都是可能的,并且在技术上可以被认为是“正确的”(即有效的 JSON)。

区别取决于用于序列化的对象:

  • 单个Userclass;或
  • 一个 Map 包含相同的 User class.

假设我们有以下两个 class 用于测试(这些从您的示例中略微简化):

User.java:

import java.util.List;

public class User {
    
    private final List<Account> accounts;
    
    public User(List<Account> accounts) {
        this.accounts = accounts;
    }

    public List<Account> getAccounts() {
        return accounts;
    }
    
}

Account.java:

public class Account {

    private final String accountID;
    
    public Account(String accountID) {
        this.accountID = accountID;
    }

    public String getAccountID() {
        return accountID;
    }
    
}

然后我们可以assemble一个User测试对象如下:

Account account1 = new Account("ABC123");
Account account2 = new Account("XYZ789");
List<Account> accounts = new ArrayList<>();
accounts.add(account1);
accounts.add(account2);
User user = new User(accounts);

如何序列化为JSON?

在这里我将使用 Jackson - 但就这个问题而言,使用哪个库并不重要。

这是我的 Jackson 对象映射器:

ObjectMapper mapper = new ObjectMapper();

我可以按如下方式序列化我的 user 对象:

System.out.println(mapper.writeValueAsString(user));

这会生成以下 JSON:

{
    "accounts": [{
        "accountID": "ABC123"
    }, {
        "accountID": "XYZ789"
    }]
}

如您所见,这里没有提到“用户”对象。

但我可以选择将我的 user 对象放在 Map:

Map<String, User> userContainer = new HashMap<>();
userContainer.put("User", user);

现在如果我序列化这张新地图:

System.out.println(mapper.writeValueAsString(userContainer));

这给出了以下 JSON:

{
    "User": {
        "accounts": [{
            "accountID": "ABC123"
        }, {
            "accountID": "XYZ789"
        }]
    }
}

还有你问的 "User": { ... } 对象。

因此,从技术上讲,这两种方法都是有效的 - 序列化方法只有微小的变化。

我的个人偏好是后者JSON——仅仅因为它明确地告诉我们包含对象是一个“用户”对象。第一条 JSON.

中缺少该信息

我真的不明白为什么“他们只能在 JSON 中生成具有顶级/根元素名称 'User' 的 JSON。" - 但是因为我们不知道他们是怎么做到的,所以很难支持或反对他们的声明。而且我们不知道为什么你需要它们来 而不是 生成外部结构,因此也很难争论或反对它。

因此,对于问题 1:是的,它们都是有效的 JSON 表示,尽管其中一个可能被认为是不完整的。

对于问题 2,我会说:如果它们包含那个外部对象,那么当您使用它们的 JSON 时,您可以使用 Map。如果那是你正在做的。然后你可以丢弃地图并只使用地图中的对象(值)。

如果他们将此 JSON 传递给第 3 方,那么我认为这不是技术问题,而是团队间 discussion/communications 问题。

没有“正确”的连载。 XML、JSON、Java数据模型不同,它们之间没有标准的映射关系。每个实施映射(在三个中的任意两个之间)的每个人都必须就如何处理差异做出决定,而这些决定涉及权衡。获得你想要的精确映射的唯一方法是自己实现它。更好的是,始终使用单一表示。我猜 XRX 架构(XML 在客户端,XML 在服务器,休息以桥接两者)现在不太流行,但它确实削减了典型的 40% 的代码仅关注将数据从一种表示形式转换为另一种表示形式的应用程序。