我遇到了一个问题,我需要在反序列化过程中使用Gson
和InstanceCreator
设置我的对象被引用的引用。
为了描述问题,以下是类结构的简单表示。
public class Workshift {
private final transient Context context;
private final Visit visit;
public Workshift(Context context) {
this.context = context;
this.visit = new Visit(this);
}
}
public class Visit {
private final transient Workshift workshift;
public Visit(Workshift ws) {
this.workshift = ws;
}
}
通过这种结构,我可以通过向Context
提供Workshift
来设置InstanceCreator
中的GsonBuilder
,例如:
Gson gson = new GsonBuilder()
.registerTypeAdapter(Workshift.class, new InstanceCreator<Workshift>() {
@Override
public Workshift createInstance(Type type) {
return new Workshift(context);
}
})
.create();
我知道,我可以向InstanceCreator
添加额外的GsonBuilder
,但我不确定如何提供正在解析的Workshift
对象的引用(即时)到Visit
对象?
任何帮助将不胜感激!
答案 0 :(得分:1)
你绝对应该使用GraphAdapterBuilder。
正如你在@Braj回答的评论中所说,
由于某种原因workshift 设置为瞬态,因此在序列化访问对象时它不会序列化此对象。如果没有标记 作为瞬态,然后序列化陷入堆栈溢出 例外 - 通过创建一个不可阻挡的循环
这有一个简单的解决方案。
<强> Workshift.java 强>
public class Workshift {
private final transient Context context;
private final Visit visit;
//for testing
private String workshift_description;
public Workshift(Context context,String id) {
this.workshift_description=id;
this.context = context;
this.visit = new Visit(this);
}
public String getId() {
return workshift_description;
}
public void setId(String id) {
this.workshift_description = id;
}
public String toString() {
return "[Workshift element => { WD: "+this.workshift_description+", VD : "+this.visit.getVisit_description()+"}";
}
}
<强> Visit.java 强>
public class Visit {
private final /* transient */ Workshift workshift;
public Visit(Workshift ws) {
this.workshift = ws;
}
public String getVisit_description() {
return "visit containing "+ workshift.getId();
}
}
诀窍在于:
GsonBuilder gsonBuilder = new GsonBuilder();
new GraphAdapterBuilder()
.addType(Visit.class)
.addType(Workshift.class)
.registerOn(gsonBuilder);
全部放在一起,
public static void main(String[] args) {
Workshift[] workshifts = new Workshift[10];
for (int i = 0; i < workshifts.length; i++) {
//Replace Context(i) for the real one
workshifts[i] = new Workshift(new Context(i), "Workshift#"
+ i);
}
System.out.println("Original Workshifts array:");
for (int i = 0; i < workshifts.length; i++) {
System.out.println(workshifts[i]);
}
System.out.println("===================================");
GsonBuilder gsonBuilder = new GsonBuilder();
new GraphAdapterBuilder()
.addType(Visit.class)
.addType(Workshift.class)
.registerOn(gsonBuilder);
Gson gson = gsonBuilder.setPrettyPrinting().create();
String serialized = gson.toJson(workshifts);
// System.out.println(serialized);
Workshift[] w_array = gson.fromJson(serialized, Workshift[].class);
// System.out.println(gson.toJson(w_array));
System.out.println("Des-serialized Workshifts array:");
for (int i = 0; i < w_array.length; i++) {
System.out.println(w_array[i]);
}
System.out.println("===================================");
<强>输出:强>
Original Workshifts array:
[Workshift element => { WD: Workshift#0, VD : visit containing Workshift#0}
[Workshift element => { WD: Workshift#1, VD : visit containing Workshift#1}
[Workshift element => { WD: Workshift#2, VD : visit containing Workshift#2}
[Workshift element => { WD: Workshift#3, VD : visit containing Workshift#3}
[Workshift element => { WD: Workshift#4, VD : visit containing Workshift#4}
[Workshift element => { WD: Workshift#5, VD : visit containing Workshift#5}
[Workshift element => { WD: Workshift#6, VD : visit containing Workshift#6}
[Workshift element => { WD: Workshift#7, VD : visit containing Workshift#7}
[Workshift element => { WD: Workshift#8, VD : visit containing Workshift#8}
[Workshift element => { WD: Workshift#9, VD : visit containing Workshift#9}
===================================
Des-serialized Workshifts array:
[Workshift element => { WD: Workshift#0, VD : visit containing Workshift#0}
[Workshift element => { WD: Workshift#1, VD : visit containing Workshift#1}
[Workshift element => { WD: Workshift#2, VD : visit containing Workshift#2}
[Workshift element => { WD: Workshift#3, VD : visit containing Workshift#3}
[Workshift element => { WD: Workshift#4, VD : visit containing Workshift#4}
[Workshift element => { WD: Workshift#5, VD : visit containing Workshift#5}
[Workshift element => { WD: Workshift#6, VD : visit containing Workshift#6}
[Workshift element => { WD: Workshift#7, VD : visit containing Workshift#7}
[Workshift element => { WD: Workshift#8, VD : visit containing Workshift#8}
[Workshift element => { WD: Workshift#9, VD : visit containing Workshift#9}
===================================
没有StackOverflow错误。
如果您取消对该行的评论
// System.out.println(serialized);
输出如下:
[
{
"0x1": {
"visit": "0x2",
"workshift_description": "Workshift#0"
},
"0x2": {
"workshift": "0x1"
}
},
{
"0x1": {
"visit": "0x2",
"workshift_description": "Workshift#1"
},
"0x2": {
"workshift": "0x1"
}
},
{
"0x1": {
"visit": "0x2",
"workshift_description": "Workshift#2"
},
"0x2": {
"workshift": "0x1"
}
},
{
"0x1": {
"visit": "0x2",
"workshift_description": "Workshift#3"
},
"0x2": {
"workshift": "0x1"
}
},
{
"0x1": {
"visit": "0x2",
"workshift_description": "Workshift#4"
},
"0x2": {
"workshift": "0x1"
}
},
{
"0x1": {
"visit": "0x2",
"workshift_description": "Workshift#5"
},
"0x2": {
"workshift": "0x1"
}
},
{
"0x1": {
"visit": "0x2",
"workshift_description": "Workshift#6"
},
"0x2": {
"workshift": "0x1"
}
},
{
"0x1": {
"visit": "0x2",
"workshift_description": "Workshift#7"
},
"0x2": {
"workshift": "0x1"
}
},
{
"0x1": {
"visit": "0x2",
"workshift_description": "Workshift#8"
},
"0x2": {
"workshift": "0x1"
}
},
{
"0x1": {
"visit": "0x2",
"workshift_description": "Workshift#9"
},
"0x2": {
"workshift": "0x1"
}
}
这是因为Gson正在替换您的引用,以避免该堆栈溢出异常。这就像模拟指针
希望它有所帮助。
注意:请记住复制文件GraphAdapterBuilder.java并更改行
private final ConstructorConstructor constructorConstructor = new ConstructorConstructor();
带
private final ConstructorConstructor constructorConstructor = new ConstructorConstructor(instanceCreators);
否则将无法编译。也许它现在已经修好了。
答案 1 :(得分:0)
<强>问题:强>
目前,访问中的workshift字段在反序列化时结果为null。
<强>解决方案:强>
workshift字段是Visit类中的临时成员,并且不会序列化瞬态成员,这就是反序列化时获取空值的原因。
要解决此问题,您必须在反序列化后获取workshift对象后通过调用其setter方法手动设置访问类中的workshift引用。
反序列化时,你引用了对象的workshift和visit。 只需要通过工作转移的参考就可以解决它。
<强> Visit.java:强>
public class Visit {
private final transient Workshift workshift;
public Visit() {
}
public Workshift getWorkshift() {
return workshift;
}
public void setWorkshift(Workshift workshift) {
this.workshift = workshift;
}
}
使用JsonDeserializer将workshift的引用设置为访问类。
示例代码:
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Type;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
public class GSON {
/**
* @param args
* @throws IOException
* @throws ClassNotFoundException
*/
public static void main(String[] args) throws Exception {
// serialize
Gson gson = new Gson();
String json = gson.toJson(new Workshift());
System.out.println("Workshift JSON:" + json);
// deserialize
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(Workshift.class, new WorkshiftDeserializer());
Workshift workshift = builder.create().fromJson(json, Workshift.class);
System.out.println("Reference of Workshift from Visit:"
+ workshift.getVisit().getWorkshift());
}
}
class Workshift implements Serializable {
private Visit visit;
public Workshift() {
this.visit = new Visit(this);
}
public Visit getVisit() {
return visit;
}
public void setVisit(Visit visit) {
this.visit = visit;
}
}
class Visit implements Serializable {
private transient Workshift workshift;
public Visit() {
}
public Visit(Workshift ws) {
this.workshift = ws;
}
public Workshift getWorkshift() {
return workshift;
}
public void setWorkshift(Workshift workshift) {
this.workshift = workshift;
}
}
class WorkshiftDeserializer implements JsonDeserializer<Workshift> {
public Workshift deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
Gson gson = new Gson();
Workshift workshift = gson.fromJson(json, Workshift.class);
workshift.getVisit().setWorkshift(workshift);
return workshift;
}
}