gpt4 book ai didi

json - gson flat json 到嵌套对象需要序列化器/反序列化器吗?

转载 作者:行者123 更新时间:2023-12-04 12:58:15 30 4
gpt4 key购买 nike

我有一些 JSON 进来(我没有任何控制或能力来更改 JSON 中的结构和/或命名......在这个问题中记住这一点很重要)具有类似于以下的“平面”结构:

{
"name": "...",
"email": "...",
"box_background_color": "...",
"box_border_color": "...",
"box_text_color": "...",
...
}

现在,我可以创建一个简单的对象来保持一切平坦,如下所示:
public class Settings {

@SerializedName("name")
private String _name;

@SerializedName("email")
private String _emailAddress;

@SerializedName("box_background_color")
private String _boxBackgroundColor;

@SerializedName("box_border_color")
private String _boxBorderColor;

@SerializedName("box_text_color")
private String _boxTextColor;

...
}

但是,我想要与 box 相关的所有内容设置在它自己的类中( BoxSettings )。这更像是我想要的:
public class Settings {

@SerializedName("name")
private String _name;

@SerializedName("email")
private String _emailAddress;

private BoxSettings _boxSettings

...
}

public class BoxSettings {

@SerializedName("box_background_color")
private String _boxBackgroundColor;

@SerializedName("box_border_color")
private String _boxBorderColor;

@SerializedName("box_text_color")
private String _boxTextColor;

...
}

我知道如果 JSON 的结构是嵌套的框设置,那么很容易完成我想要的,但是,我没有能力更改 JSON 的结构,所以请不要建议(如果可以的话,我会这样做)。

我的问题是: 创建整个 TypeAdapter 是完成我想要的唯一方法还是我仍然可以通过注释完成大部分工作?如果这不是唯一的方法,我还能如何在不更改 JSON 的情况下完成此操作?

以下是我所说的“创建整个 TypeAdapter”的示例:
public class SettingsTypeAdapter implements JsonDeserializer<Settings>, JsonSerializer<Settings> {

@Override
public JsonElement serialize(Settings src, Type typeOfSrc, JsonSerializationContext context) {
// Add _name
// Add _emailAddress
// Add BoxSettings._boxBackgroundColor
// Add BoxSettings._boxBorderColor
// Add BoxSettings._boxTextColor
return jsonElement;
}

@Override
public Settings deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
// Read _name
// Read _emailAddress
// Read BoxSettings._boxBackgroundColor
// Read BoxSettings._boxBorderColor
// Read BoxSettings._boxTextColor
return settings;
}
}

最佳答案

TypeAdapter 不是唯一的方法,但在这种情况下将是最好的方法,因为您可以将适配器与 Gson 实例(或您正在使用的任何库)相关联,并将所有映射代码放在那里。

另一种方法是使用JAVA反射。我以前在我的项目中使用过以下代码的一个版本,但从未使用 JSON,也从未使用嵌套对象(主要是当没有其他选择时,或者如果我想将 SQL 结果集映射到 Java 对象而不调用 resultSet.get...很多时间)。

这将在这种情况下起作用。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.json.JSONObject;

public class Main {

public static void main(String[] args) {

try {
String json = "{\"name\": \"test name\", \"email\": \"email@email.com\", \"box_background_color\": \"red\", \"box_border_color\": \"orange\", \"box_text_color\": \"white\", \"test3_var2\":3}";

JSONObject jsonObject = new JSONObject(json);

System.out.println(jsonObject);
System.out.println();

/*
* need to parse JSON into a map of String, Object
*/

Map<String, Object> mapAll = new HashMap<String, Object>();
Iterator<String> iter = jsonObject.keys();

while (iter.hasNext()) {
String key = (String) iter.next();
Object value = jsonObject.get(key);

mapAll.put(key, value);

System.out.println(key + "::::" + value);
}

System.out.println();

/*
* use the mapper to generate the objects
*/

MyMapper<TestClass1> myMapper = new MyMapper<TestClass1>();
TestClass1 result = myMapper.mapToObject(mapAll, TestClass1.class);

System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
}
}
}

class MyMapper<T> {

@SuppressWarnings("unchecked")
public T mapToObject(Map<String, Object> flatStructure, Class<T> objectClass) {
T result = null;
Field[] fields = null;

try {
// new base object
result = objectClass.newInstance();

// get all of its fields
fields = objectClass.getDeclaredFields();

for (Field field : fields) {
// normal variable
if (field.isAnnotationPresent(MyColumn.class)) {
String variableKey = field.getAnnotation(MyColumn.class).variableKey();

setJavaFieldValue(result, field.getName(), flatStructure.get(variableKey));
}
// variable that is an object and itself has to be mapped
else if (field.isAnnotationPresent(MyInnerColumn.class)) {
String startsWith = field.getAnnotation(MyInnerColumn.class).startsWith();

// reduce the map to only have attributes that are related to this field
Map<String, Object> reducedMap = reduceMap(startsWith, flatStructure);

// make sure that there are attributes for the inner object
if (reducedMap != null) {
// map the inner object
MyMapper<T> myMapper = new MyMapper<T>();
T t2 = myMapper.mapToObject(reducedMap, (Class<T>) field.getType());

// set the mapped object to the base objecct
setJavaFieldValue(result, field.getName(), t2);
}
} else {
// no annotation on the field so ignored
}
}
} catch (Exception e) {
e.printStackTrace();
}

return result;
}

private Map<String, Object> reduceMap(String startsWith, Map<String, Object> mapToReduce) {
Map<String, Object> result = new HashMap<String, Object>();

for (Map.Entry<String, Object> entry : mapToReduce.entrySet()) {
if (entry.getKey().toLowerCase().startsWith(startsWith.toLowerCase())) {
result.put(entry.getKey(), entry.getValue());
}
}

return result.size() == 0 ? null : result;
}

private void setJavaFieldValue(Object object, String fieldName, Object fieldValue) {
try {
Field field = object.getClass().getDeclaredField(fieldName);

boolean fieldAccess = field.isAccessible();

// make the field accessible
field.setAccessible(true);
field.set(object, fieldValue);

// put it back to the way it was
field.setAccessible(fieldAccess);
} catch (Exception e) {
e.printStackTrace();
}
}
}

/*
* Annotation for a regular variable / field
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface MyColumn {

// the variable's JSON key
String variableKey() default "";
}

/*
* Annotation for an inner / nested variable / field
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface MyInnerColumn {

/*
* JSON keys that start with this string will be
* associated with this nested field
*/
String startsWith() default "";
}

class TestClass1 {
@MyColumn(variableKey = "name")
private String _name;

@MyColumn(variableKey = "email")
private String _emailAddress;

@MyInnerColumn(startsWith = "box_")
private TestClass2 innerClass;

@MyInnerColumn(startsWith = "test3_")
private TestClass3 innerClass2;

@Override
public String toString() {
return "TestClass1 [_name=" + _name + ", _emailAddress=" + _emailAddress + ", innerClass=" + innerClass + ", innerClass2=" + innerClass2 + "]";
}
}

class TestClass2 {
@MyColumn(variableKey = "box_background_color")
private String _boxBackgroundColor;

@MyColumn(variableKey = "box_border_color")
private String _boxBorderColor;

@MyColumn(variableKey = "box_text_color")
private String _boxTextColor;

@Override
public String toString() {
return "TestClass2 [_boxBackgroundColor=" + _boxBackgroundColor + ", _boxBorderColor=" + _boxBorderColor
+ ", _boxTextColor=" + _boxTextColor + "]";
}
}

class TestClass3 {
@MyColumn(variableKey = "test3_var1")
private String _test3Var1;

@MyColumn(variableKey = "test3_var2")
private int _test3Var2;

@Override
public String toString() {
return "TestClass3 [_test3Var1=" + _test3Var1 + ", _test3Var2=" + _test3Var2 + "]";
}
}

输出
{"box_background_color":"red","box_text_color":"white","test3_var2":3,"name":"test name","email":"email@email.com","box_border_color":"orange"}

box_background_color::::red
box_text_color::::white
test3_var2::::3
name::::test name
email::::email@email.com
box_border_color::::orange

TestClass1 [_name=test name, _emailAddress=email@email.com, innerClass=TestClass2 [_boxBackgroundColor=red, _boxBorderColor=orange, _boxTextColor=white], innerClass2=TestClass3 [_test3Var1=null, _test3Var2=3]]

关于json - gson flat json 到嵌套对象需要序列化器/反序列化器吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26289130/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com