Java GSON:在反序列化时删除不必要的父对象
我正在尝试使用GSON反序列化JSON数组。我的所有嵌套对象都嵌入到“嵌入”对象中 我也可能遇到这样的情况:Java GSON:在反序列化时删除不必要的父对象,java,gson,json-deserialization,Java,Gson,Json Deserialization,我正在尝试使用GSON反序列化JSON数组。我的所有嵌套对象都嵌入到“嵌入”对象中 我也可能遇到这样的情况: { "Book": { "name": "Book 1", "published": 1999, "links": { "url": "www.book1.com" }, "embedded": { "Publisher": {
{
"Book": {
"name": "Book 1",
"published": 1999,
"links": {
"url": "www.book1.com"
},
"embedded": {
"Publisher": {
"name": "Publishing Company",
"links": {
"url": "www.publishingcompany.com"
}
}
}
}
}
public class Book {
String name;
int published;
String url;
Author author;
Publisher publisher;
}
这是一个非常简单的例子。我的一些对象可能嵌套2或3层深,并且都在“嵌入”对象中。此外,每个对象在“链接”对象中都有一个嵌套的“url”。我有大约20个不同的模型对象,每个对象都有几个字段,每个对象都有“嵌入式”对象。我开始为每个模型编写自定义反序列化程序,但这似乎忽略了使用gson的全部意义,而且我可能并不总是知道嵌入的对象是什么
我找到了这个,但它是用于序列化对象的。我已经试着弄明白这一点有一段时间了,但没有发现任何有效的方法
我的图书模型如下所示:
{
"Book": {
"name": "Book 1",
"published": 1999,
"links": {
"url": "www.book1.com"
},
"embedded": {
"Publisher": {
"name": "Publishing Company",
"links": {
"url": "www.publishingcompany.com"
}
}
}
}
}
public class Book {
String name;
int published;
String url;
Author author;
Publisher publisher;
}
作者类别:
public class Author {
String name;
String url;
}
@Flatten("links::url")
private String url;
发布者类别:
public class Publisher {
String name;
String url;
}
这是我目前为止的图书反序列化程序:
public class BookDeserializer implements JsonDeserializer<Book> {
@Override
public Book deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
final JsonObject jsonObject = json.getAsJsonObject();
Book book = new Book();
book.setName(jsonObject.get("name").getAsString());
book.setPublished(jsonObject.get("published").getAsInt());
String url = jsonObject.getAsJsonObject("links").get("url").getAsString();
book.setUrl(url);
// 1) How to get rid of this and skip to the "real" nested object?
final JsonObject embeddedObject = jsonObject.getAsJsonObject("embedded");
// 2) See what the "embedded" object actually is.
String embeddedModel;
Set<Map.Entry<String, JsonElement>> entrySet = embeddedObject.entrySet();
for (Map.Entry<String, JsonElement> entry : entrySet) {
// Author or Publisher
embeddedModel = entry.getKey();
}
// We have the model's key, now add code here to deserialize whatever the object is
return book;
}
}
公共类BookDeserializer实现JsonDeserializer{
@凌驾
PublicBook反序列化(JsonElement json,类型typeOfT,JsonDeserializationContext)引发JsonParseException{
final JsonObject JsonObject=json.getAsJsonObject();
书=新书();
setName(jsonObject.get(“name”).getAsString());
book.setPublished(jsonObject.get(“published”).getAsInt());
字符串url=jsonObject.getAsJsonObject(“链接”).get(“url”).getAsString();
setUrl(url);
//1)如何摆脱这种情况并跳到“真实”嵌套对象?
final JsonObject embeddedObject=JsonObject.getAsJsonObject(“嵌入式”);
//2)查看“嵌入”对象实际上是什么。
字符串嵌入模型;
Set entrySet=embeddedObject.entrySet();
for(Map.Entry:entrySet){
//作者或出版商
embeddedModel=entry.getKey();
}
//我们有了模型的密钥,现在在这里添加代码来反序列化对象
还书;
}
}
我仍然需要解析json并为Book设置每个字段。然后,我必须添加代码来确定并使用嵌套对象的正确反序列化器。看起来我仍然需要为每个对象使用自定义反序列化器来获取“url”。我对gson还比较陌生,所以可能有一些东西我忽略了,但我似乎也可以手动解析所有的json,甚至不用gson。也许有一种方法可以让json变得平坦
有没有关于如何解析它并仍然使用gson的便利性的想法,或者这是可能的?也许Jackson可以更好地处理这个问题?创建一个名为embedded的类,并将其添加为Book中的字段:
public class Book {
String name;
int published;
Embedded embedded;
}
然后创建一个嵌入式类:
public class Embedded {
Author Author;
Publisher Publisher;
}
只需根据JSON对类进行建模,我的第一个想法是解析JSON并对其进行破解,但它看起来GSON
JsonObject
s是不可变的
因此,我将编写一个简单的流解析器,查找“嵌入式”:{
和“链接”:{
并删除它们。也运行一个简单的括号计数器来删除匹配的右括号。如果时间允许,我可能会将一个放在一起
顺便说一句,您的示例JSON缺少一个逗号-请粘贴它以进行检查
添加:-流解析器失控了-尽管它会是一个更整洁的选项。如果你能找到一个JSON流解析器,就像SAX对XML所做的那样,你也许可以用这种方式做得更好
第二种机制假设您可以将整个JSON放在内存中的一个字符串中。这并不理想,但对于大多数设置来说可能是一种可接受的解决方案。然后使用简单的正则表达式加上括号计数器删除所需的部分
/**
* Finds the first matching close brace - assuming an open brace has just been removed from the `start` position.
*/
private int closeBrace(StringBuilder s, int start) {
int count = 1;
boolean inQuotes = false;
for (int i = start; i < s.length(); i++) {
char ch = s.charAt(i);
// Special case escapes.
if (ch != '\\') {
switch (ch) {
case '"':
inQuotes = !inQuotes;
break;
case '{':
if (!inQuotes) {
count += 1;
}
break;
case '}':
if (!inQuotes) {
count -= 1;
if (count == 0) {
return i;
}
}
break;
}
} else {
// Escape character - skip the next character.
if (i < s.length()) {
i += 1;
}
}
}
// Failed to find
return s.length();
}
/**
* Removes the JSON specified.
*/
private String hack(String json, String remove) {
// Transfer to an sb for slicing and dicing.
StringBuilder s = new StringBuilder(json);
// Build my pattern
Pattern p = Pattern.compile("\"" + remove + "\"\\s*:\\s*\\{");
// Make my Matchjer.
Matcher m = p.matcher(s);
// Is it there?
while (m.find()) {
int start = m.start();
int end = m.end();
// Kill the match.
s.delete(start, end);
// Walk forward to find the close brace.
end = closeBrace(s, start);
// And remove it.
if (end < s.length()) {
s.delete(end, end + 1);
}
// Rebuild the matcher.
m = p.matcher(s);
}
return s.toString();
}
private void test(String json) {
JsonParser parser = new JsonParser();
JsonElement e = parser.parse(json);
System.out.println(e);
}
public void test() {
String json = "{'Book': {'name': 'Book \\'1\\'','published': 1999,'links': {'url': 'www.book1.com'},'embedded': {'Publisher': {'name': 'Publishing Company','links': {'url': 'www.publishingcompany.com'}}}}}".replace("'", "\"");
test(json);
json = hack(json, "embedded");
test(json);
json = hack(json, "links");
test(json);
}
这看起来有点像你要找的东西。我想你在找这样的东西: 这个工具可以帮助你省略一些嵌入的类,你将拥有更少的类和更干净的代码。 在你的书本课上,使用以下方法:
@Flatten("embedded::Author")
private Author author;
这样可以折叠一层。
使用相同的方法可以将链接移动到作者。
在“作者”类中:
public class Author {
String name;
String url;
}
@Flatten("links::url")
private String url;
如果你想走得更深,你可以用同样的方法将两个级别移得更高。例如:
@Flatten("embedded::Author::name")
private String authorName;
在这里,您将在Book类中拥有作者的姓名
希望有帮助。gson默认情况下不能反序列化和序列化此内容吗?为什么需要编写自己的?这是我最初认为的方式,但希望有一个更“优雅”的解决方案。创建链接和嵌入类似乎是浪费(还会有更多类似的),每个都有我甚至可能不使用的对象。我想这比为每个对象创建自定义反序列化器更容易。我们在公司中使用来在这些类之间映射。实际上,我们制作了一个平面响应对象,我们想要发送,并使用dozer来映射它们。这有助于自动将bean映射到彼此感谢您的帮助,我已经更正了JSON。这听起来是个好主意,一些示例代码会很棒!Gson确实支持流式处理,这就是您所指的吗?@Mark-见Added-这不是一个非常漂亮的解决方案,但它应该适用于中小型JSON对象。感谢您提供代码示例。不过,我将继续创建额外的类,以便java模型与json匹配。看起来gson可能没有提供内置的方法来打开选定的嵌套对象。请不要只是发布一些工具或库作为答案。至少在答案本身中进行演示。@Dwhitz感谢您的评论:)我编辑了答案。今天太忙了:/