给出以下JSON源
{
"database": "accounts","groups": {
"databaseDictionary": {
"folder": "C:\\Development\\Work\\Ac\\Data\\DataDictionary"
},"sqlCreateDatabase": {
"name": "Sleaford","user": "JBarrow","useWindowsAuthentication": "true"
},"defaultData": {
"folder": "C:\\Development\\Work\\Ac\\Data\\Configuration"
}
}
}
我希望下面的类结构可以成功地填充对象。
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.reader;
import java.util.ArrayList;
import java.util.HashMap;
public class JsonnestedHashMapConcise {
private Configuration data;
private class Configuration {
private String database;
private HashMap<String,Group> groups;
private class Group {
private HashMap<String,String> settings;
}
}
public JsonnestedHashMapConcise (String fn) {
try (Reader jsonFile = new BufferedReader(new FileReader(new File(fn)))) {
Gson jsonParser = new Gson();
this.data = jsonParser.fromJson(jsonFile,Configuration.class);
}
catch (JsonSyntaxException | IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
JsonnestedHashMapConcise myConfiguration;
myConfiguration = new JsonnestedHashMapConcise("C:\\StackOverflow\\Concise.json");
System.out.println("Completed reading database configuration for " + myConfiguration);
}
}
但是,在填充Configuration.groups HashMap时,嵌套的groups.settings HashMap为null。
我已经搜索了JsonDeserializer
,registerTypeAdapter
和TypeToken
之类的技术,并找到了可能的解决方案,但我无法理解它们如何适合解决我的问题。
作为背景知识,我有一个起点(下面列出了源和示例JSON),提供了一种解决方法,但需要更详细的JSON语法。在写支持方法时,我发现如果将Configuration.groups字段设置为HashMap
,则会导致更有效的查询。我还读到Gson支持内部类,并且此起点似乎支持该声明。
详细结构的JSON源
{
"database": "accounts","groups": [
{
"name": "databaseDictionary","settings": {
"folder": "C:\\Development\\Work\\Ac\\Data\\DataDictionary"
}
},{
"name": "sqlCreateDatabase","settings": {
"name": "Sleaford","useWindowsAuthentication": "true"
}
},{
"name": "defaultData","settings": {
"folder": "C:\\Development\\Work\\Ac\\Data\\Configuration"
}
}
]
}
使用以下类结构
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.reader;
import java.util.ArrayList;
import java.util.HashMap;
public class JsonnestedHashMapVerbose {
private Configuration data;
private class Configuration {
private String database;
private ArrayList<Group> groups;
private class Group {
private String name;
private HashMap<String,String> settings;
}
}
public JsonnestedHashMapVerbose (String fn) {
try (Reader jsonFile = new BufferedReader(new FileReader(new File(fn)))) {
Gson jsonParser = new Gson();
this.data = jsonParser.fromJson(jsonFile,Configuration.class);
}
catch (JsonSyntaxException | IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
JsonnestedHashMapVerbose myConfiguration;
myConfiguration = new JsonnestedHashMapVerbose("C:\\StackOverflow\\Concise.json");
System.out.println("Completed reading database configuration for " + myConfiguration);
}
}
两种设计之间的唯一区别是,起始结构具有在JSON中定义的显式“设置”元素,解析器可能需要该元素才能反序列化结构的那部分。
我是不是将Gson解串器推得太远了,还是可以添加一些其他代码来帮助Gson完成任务?
对建议的重复问题的反馈
在建议的相关问题中详细介绍的解决方案,使用由提供的解析器,创建了一个非常详细的类结构,我在下面对此进行了详细介绍(为清楚起见进行了编辑)。
此自动解析器方法不能识别出所有相关元素(databaseDictionary,sqlCreateDatabase和defaultData)都可以存储在HashMap
结构中,如果解析器可以检测到该元素,我会印象深刻。相反,我们最终为每个元素都提供了一个类。
public class DatabaseDictionary {
public String folder;
}
public class DefaultData {
public String folder;
}
public class Example {
public String database;
public Groups groups;
}
public class Groups {
public DatabaseDictionary databaseDictionary;
public SqlCreateDatabase sqlCreateDatabase;
public DefaultData defaultData;
}
public class SqlCreateDatabase {
public String name;
public String user;
public String useWindowsAuthentication;
}
此问题开头详细介绍的JSON源是groups元素内存在的元素数量的子集,这些元素将被扩展(并在以后进行搜索)。
使用详细使用的类结构将要求我创建一个新类来支持每个元素(并且我希望在源中有10或100的这些元素)。使用这种结构还意味着很难在groups元素中定位指定的group元素以提取其属性。
我可以使用JsonToken
的原始方法来解析JSON源,以填充Java类
private class Configuration {
private String database;
private HashMap<String,String> settings;
}
}
但是,鉴于GSON解析器显然可以检测和填充HashMap
元素(如第二个示例所示),我希望以相同的方式检测到两层HashMap
以避免重复使用JsonToken
,因为我还有其他类似的JSON结构,这些结构将从使用HashMap
中受益。
我不知道GSON解析器是否检测到所提供的Java类中的类类型,或者是否检测到同一级别有多个元素名称以便填充单个HashMap
,因为我没有了解GSON的内部运作方式。
我希望有一种支持的GSON抽象方法,可以用来教育解析器填充分层HashMap
类。
万一有兴趣的人
如果其他人想对相似的结构进行建模,我发现使用JsonReader
类会导致可读性很强的解决方案,即使toJson
方法只是极简主义也很好要编写的代码。我在下面提供了我的资料,尽管我仍然是一个新手,但我确信可能会有更优雅的方法来编写其中的一些方法。
import com.google.gson.JsonSyntaxException;
import com.google.gson.stream.JsonReader;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.reader;
import java.util.HashMap;
public class DatabaseConfiguration {
private String database;
private HashMap<String,Group> groups;
private class Group {
private HashMap<String,String> settings;
}
private Group ReadGroup(JsonReader jsonReader) throws IOException {
Group result = null;
// Iterate over the the list of group attributes
jsonReader.beginObject();
while (jsonReader.hasnext()) {
String name = jsonReader.nextName();
if (result == null) {
result = new Group();
result.settings = new HashMap<>();
}
result.settings.put(name,jsonReader.nextString());
}
jsonReader.endObject();
return result;
}
private HashMap<String,Group> ReadGroups (JsonReader jsonReader) throws IOException {
HashMap<String,Group> result = null;
// Iterate over the the list of groups
jsonReader.beginObject();
while (jsonReader.hasnext()) {
String name = jsonReader.nextName();
Group myGroup;
myGroup = ReadGroup(jsonReader);
if (result == null) {
result = new HashMap<>();
}
result.put(name,myGroup);
}
jsonReader.endObject();
return result;
}
public DatabaseConfiguration (String fn) {
try (Reader jsonFile = new BufferedReader(new FileReader(new File(fn)));
JsonReader jsonReader = new JsonReader(jsonFile)) {
// Root node (database + groups)
jsonReader.beginObject();
while (jsonReader.hasnext()) {
String name = jsonReader.nextName();
switch (name) {
case "database":
this.database = jsonReader.nextString();
break;
case "groups":
this.groups = ReadGroups(jsonReader);
break;
default:
throw new JsonSyntaxException("Unexpected name " + name + "in outer element of " + fn);
}
}
jsonReader.endObject();
}
catch (JsonSyntaxException | IOException e) {
System.out.println(e);
}
}
public static void main(String[] args) {
DatabaseConfiguration myConfiguration;
myConfiguration = new DatabaseConfiguration("C:\\StackOverflow\\Concise.json");
System.out.println("Completed reading database configuration for " + myConfiguration);
}
}
除了我第一次在这里发布
我原来的问题最初被标记为重复,因此被自动关闭。然后,我按照建议编辑了我的问题,以详细说明为什么重复问题中建议的解决方案与我的问题无关。然后,我希望这个问题可以重新打开(因为它已被编辑),但这从未发生。我不想剪切并粘贴重新编辑的问题,因为我认为这会滥用堆栈溢出的原理,因此,我对成功撤回错误标记的问题的正确方法感到困惑作为副本。
自从我在上面发表评论以来,我现在偶然发现,我可以要求“重复”标记的创建者通过在评论中“ ping”它们来审查他们的决定,所以我现在将尝试一下!
如果在叙述为什么原始问题不是表格上的重复项之后有一个明显的选择,那将是很好的选择,但是由于我是新用户,因此我只有5个评论才能在一般论坛上发表任何反馈学分!