英文:
How do I read this Generics correctly from JSON?
问题
以下是您提供的内容的翻译部分:
我对我的第一个泛型容器还算有信心,但在客户端的类型转换方面卡住了。在涉足学习 <T>
相关内容之前,以下是之前有效的代码:
CommonNounContainer typeContainer = new Json().fromJson(CommonNounContainer.class, result);
我在考虑为每个类创建一个不同的容器,但这似乎不是很好的设计。以下是我更新后、不起作用的尝试,用于读取我的新泛型容器:
JSONContainer<CommonNoun> typeContainer = new Json().fromJson(JSONContainer.class, result);
我的集成开发环境不认可这种措辞,指出:
类型安全性:类型为 JSONContainer 的表达式需要进行未经检查的转换,以符合 JSONContainer
执行时,我的错误日志如下:
result = {"myObject":{"cid":{"oid":129},"name":"technology","form":1},"children":[]}
com.badlogic.gdx.utils.SerializationException: Field not found: cid (java.lang.Object)
Serialization trace:
{}.myObject.cid
myObject (semanticWeb.rep.concept.JSONContainer)
at com.badlogic.gdx.utils.Json.readFields(Json.java:854)
at com.badlogic.gdx.utils.Json.readValue(Json.java:1011)
...
我相信在等号右边的 CommonNoun 类型之后,肯定有一些方法,但我还没有找到方法。我该如何做?关于泛型、类型转换、JSON 和去除类信息的问题,有很多适用的帖子。我尝试过其中一个不涉及上述类型转换的问题,它在构造容器期间将 T 类作为私有变量添加到容器中:
https://stackoverflow.com/questions/3437897/how-do-i-get-a-class-instance-of-generic-type-t
但我在尝试正确引用该类时遇到了类似的语法问题,只是在过程的不同位置。我也怀疑在告诉 JSON 如何对文件中的信息进行分类之前,是否可以从 JSON 文件中读取这个类变量。
fromJson(Class<T>, String)
方法的 Javadoc:
类型参数:
<T>
参数:
type 如果类型未知,则可以为 null。
json
返回:
可以为 null。
我可能已经有了一个由 deduper 提交的可行答案,但如您所请求,这里是 CommonNounContainer 和 JSONContainer 类:
import java.util.ArrayList;
public class CommonNounContainer {
private CommonNoun myCommonNoun;
private ArrayList<CommonNounContainer> children;
// ...
}
public class JSONContainer<T> {
private T myObject;
private ArrayList<JSONContainer<T>> children;
// ...
}
还有其他要求的类:
public class CommonNoun extends Concept {
// ...
}
public class Concept implements Serializable {
// ...
}
public class ConceptID implements Serializable {
// ...
}
这些是您提供的内容的翻译部分。如果您有任何进一步的问题或需要补充信息,请随时告诉我。
英文:
I'm reasonably confident in my first generics container, but stuck on how to word the casting on the client side. This is what was working before I got involved in learning <T>
stuff:
CommonNounContainer typeContainer = new Json().fromJson(CommonNounContainer.class, result);
I was looking at having to create a different container for each class, and that doesn't seem like good design. Below is my updated, non-working attempt to read in my new generics container:
JSONContainer<CommonNoun> typeContainer = new Json().fromJson(JSONContainer.class, result);
My IDE doesn't care for this phrasing, noting:
> Type safety: The expression of type JSONContainer needs unchecked
> conversion to conform to JSONContainer<CommonNoun>
When executed, my err log reads:
result = {"myObject":{"cid":{"oid":129},"name":"technology","form":1},"children":[]}
com.badlogic.gdx.utils.SerializationException: Field not found: cid (java.lang.Object)
Serialization trace:
{}.myObject.cid
myObject (semanticWeb.rep.concept.JSONContainer)
at com.badlogic.gdx.utils.Json.readFields(Json.java:854)
at com.badlogic.gdx.utils.Json.readValue(Json.java:1011)
at com.badlogic.gdx.utils.Json.readFields(Json.java:863)
at com.badlogic.gdx.utils.Json.readValue(Json.java:1011)
at com.badlogic.gdx.utils.Json.fromJson(Json.java:789)
at com.b2tclient.net.Communicator$2.handleHttpResponse(Communicator.java:95)
at com.badlogic.gdx.net.NetJavaImpl$2.run(NetJavaImpl.java:224)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:830)
I'm sure there's some way I'm supposed to include a reference to the CommonNoun type to the right of the equals sign, but I haven't been able to figure it out. How do I do it? There's lots of applicable posts concerning generics, casting, JSON, and stripping away of class information. One of them I tried to follow that wasn't about the casting above regarded adding the T class as a private variable within the container during construction:
https://stackoverflow.com/questions/3437897/how-do-i-get-a-class-instance-of-generic-type-t
but I ran into similar syntax issues trying to refer to the class correctly, just in a different spot along the process. I have my doubts, too, that I can read this class variable from the JSON file before telling JSON how to classify the information in the file.
Javadoc for the fromJson(Class<T>, String)
method:
Type Parameters:
<T>
Parameters:
type May be null if the type is unknown.
json
Returns:
May be null.
I may already have a viable answer submitted by deduper, but, as requested, here are the CommonNounContainer and JSONContainer classes:
import java.util.ArrayList;
public class CommonNounContainer {
private CommonNoun myCommonNoun;
private ArrayList<CommonNounContainer> children;
public CommonNounContainer(CommonNoun concept) {
myCommonNoun = concept;
children = new ArrayList<CommonNounContainer>();
}
//Creates an empty shell. This would be for categories you want to group by, but not display/select in the select box.
public CommonNounContainer() {
children = new ArrayList<CommonNounContainer>();
}
public void addChildren(ArrayList<CommonNounContainer> newChildren) {
children.addAll(newChildren);
}
public void addChild(CommonNoun concept) {
children.add(new CommonNounContainer(concept));
}
public ArrayList<CommonNounContainer> getChildren() {
return children;
}
public CommonNoun getValue() {
return myCommonNoun;
}
public boolean hasChildren() {
if (children.size() > 0) return true;
else return false;
}
public String toString() {
return myCommonNoun.toString();
}
}
public class JSONContainer<T> {
private T myObject;
private ArrayList<JSONContainer<T>> children;
// public Class<T> typeParameterClass;
public JSONContainer() {
}
public JSONContainer(T anObject) {
myObject = anObject;
children = new ArrayList<JSONContainer<T>>();
}
/* public JSONContainer(T anObject, Class<T> typeParameterClass) {
myObject = anObject;
children = new ArrayList<JSONContainer<T>>();
this.typeParameterClass = typeParameterClass;
}
*/
public void addChildren(ArrayList<JSONContainer<T>> newChildren) {
children.addAll(newChildren);
}
public void addChild(T concept) {
children.add(new JSONContainer<T>(concept));
}
public ArrayList<JSONContainer<T>> getChildren() {
return children;
}
public T getValue() {
return myObject;
}
public boolean hasChildren() {
if (children.size() > 0) return true;
else return false;
}
public String toString() {
return myObject.toString();
}
}
Additional classes requested:
public class CommonNoun extends Concept {
/**
*
*/
private static final long serialVersionUID = 6444629581712454049L;
public CommonNoun() {
super();
}
public CommonNoun(String name, ConceptID cidIn) {
super(name, cidIn);
this.form = ConceptDefs.COMMON_NOUN;
}
}
public class Concept implements Serializable {
/**
*
*/
private static final long serialVersionUID = 2561549161503772431L;
private ConceptID cid = null;
private final String name;
Integer form = 0;
// ArrayList<ProperRelationship> myRelationships = null;
/* @Deprecated
public Concept(String name) {
this.name = name;
}*/
public Concept() {
name = "";
}
public Concept(String name, ConceptID cidIn) {
// this(name);
this.name = name;
cid = cidIn;
}
/*
* This should be over-ridden by any subclasses
*/
public Integer getForm() {
return form;
}
public ConceptID getID() {
return cid;
}
public void setID(ConceptID cidIn) {
cid = cidIn;
}
//this doesn't make any sense. Throw exception?
public String getName() {
return name;
}
public boolean isCommon() {
return true;
}
/**
*
* @return
*/
@Override
public String toString() {
return getName() + "(" + cid.toString() + ")";
}
public boolean equals(Concept other) {
return ((getID().equals(other.getID())));
}
}
public class ConceptID implements Serializable {
long oid;
public ConceptID() {
oid = -1;
}
public ConceptID(long oid) {
this.oid = oid;
}
public long getValue() {
return oid;
}
/**
*
* @return
*/
@Override
public String toString() {
return Long.toString(oid);
}
public Long toLong() {
return Long.valueOf(oid);
}
public boolean equals(ConceptID other) {
return (oid == other.getValue());
}
/**
* Factory model for generating ConceptIDs
*
* This one is here as a convenience as many IDs come in as a String from web POSTs
* @param idAsString
* @return
*/
static public ConceptID parseIntoID(String idAsString) {
ConceptID returnID = null;
try {
returnID = new ConceptID( Long.parseLong(idAsString) );
} catch (Exception e) {
System.err.println("Expected the string, " + idAsString + ", to be Long parsable.");
e.printStackTrace();
}
return returnID;
}
答案1
得分: 1
TL;DR:
建议修复:
- 使用
_System.out.println( new Json( ).toJson( new JSONContainer<>( ... ) )_
来查看JSONContainer
的JSON
的正确字符串格式。 - 确保你传递给
Json.fromJson(Class<T>, String)
的result
输入参数与1
中打印出的格式相同。- 例如:
{myObject:{class:CommonNoun,cid:{oid:139},name:Jada Pinkett Smith,form:69},children:[{myObject:{class:CommonNoun,cid:{oid:666},name:Jaden Pinkett Smith,form:-666},children:[]},{myObject:{class:CommonNoun,cid:{oid:69},name:Willow Pinkett Smith,form:69},children:[]}]}
- 例如:
长答案:
> "我的集成开发环境(IDE)不喜欢这种措辞,提示如下:"
>
> 类型安全性:需要对 JSONContainer 的表达式进行未经检查的转换以符合 JSONContainer
这是编译器关于堆污染的警告。IDE 仅仅将这个编译器警告翻译成了一个更加用户友好的信息,显示在IDE中。
这只是一个警告,而不是错误。要消除这个警告,将这个:JSONContainer<CommonNoun> typeContainer = ...
改为这个:JSONContainer typeContainer = ...
。
> "当执行时,我的错误日志如下所示:"
>
> result = {"myObject":{"cid":{"oid":129},"name":"technology","form":1},"children":[]}
> com.badlogic.gdx.utils.SerializationException: 找不到字段:cid (java.lang.Object)...
导致这个错误的最可能原因是,就像错误消息所说的那样,你的 JSONContainer
类或 CommonNoun
类在你试图反序列化的 JSON
字符串中没有 cid
字段。
我通过以下代码重现了这个错误:
...
private static final String JADEN_AS_JSON = "{jden:{class:CommonNoun,person:Jaden,place:Hollywood,thing:HashBeen}}";
private static final String JADEN_FAILS_AS_ACTOR = "{jden:{class:CommonNoun,person:Jaden,place:Hollywood,thing:HasBeen, cid:{oid:129} }}";
public static void main(String... args) {
...
JSONContainer<CommonNoun> wtUnReifiableF = jden.fromJson(JSONContainer.class, JADEN_AS_JSON);
wtUnReifiableF = jden.fromJson(JSONContainer.class, JADEN_FAILS_AS_ACTOR); /* 这会导致你报告的错误 */
}
...
初步成功,但后来失败:
JSONContainer [ jden: CommonNoun [ person: Jaden Pinkett Smith, place: Hollywood, thing: HasBeen ] ]
{jden:{class:CommonNoun,person:Jaden Pinkett Smith,place:Hollywood,thing:HasBeen}}
{jden:{class:CommonNoun,person:Jaden,place:Hollywood,thing:HashBeen}}
Exception in thread "main" com.badlogic.gdx.utils.SerializationException: Field not found: cid (CommonNoun)
Serialization trace:
{}.jden.cid
jden (JSONContainer)
at com.badlogic.gdx.utils.Json.readFields(Json.java:893)
at com.badlogic.gdx.utils.Json.readValue(Json.java:1074)
at com.badlogic.gdx.utils.Json.readFields(Json.java:902)
at com.badlogic.gdx.utils.Json.readValue(Json.java:1074)
at com.badlogic.gdx.utils.Json.fromJson(Json.java:829)
at DeduperAnswer.main(DeduperAnswer.java:33)
通过实验,我已确认在存在 Cid
类的情况下,以及 CommonNoun
类具有 Cid
字段的情况下,尝试从具有以下值的 result
反序列化 JSONContainer
将会产生你最初报告的错误:
result = {"myObject":{"cid":{"oid":129},"name":"technology","form":1},"children":[]}
如果你的实际 CommonNoun
类的实现类似于我上面的 替代品(带有 Cid
字段),那么你需要使用与上述格式相同的方式重试你的 json.fromJson(Class<?>, String)
调用。
{myObject:{class:CommonNoun,cid:{oid:139},name:Jada Pinkett Smith,form:69},children:[{myObject:{class:CommonNoun,cid:{oid:666},name:Jaden Pinkett Smith,form:-666},children:[]},{myObject:{class:CommonNoun,cid:{oid:69},name:Willow Pinkett Smith,form:69},children:[]}]}
英文:
TL;DR:
Proposed Fix…
System.out.println( new Json( ).toJson( new JSONContainer<>( ... ) )
to see the correct string format of aJSONContainer
'sJSON
.- Make sure your
result
input argument toJson.fromJson(Class<T>, String)
is in the same format printed out in1
.- e.g.
{myObject:{class:CommonNoun,cid:{oid:139},name:Jada Pinkett Smith,form:69},children:[{myObject:{class:CommonNoun,cid:{oid:666},name:Jaden Pinkett Smith,form:-666},children:[]},{myObject:{class:CommonNoun,cid:{oid:69},name:Willow Pinkett Smith,form:69},children:[]}]}
- e.g.
The long answer…
> „My IDE doesn't care for this phrasing, noting:“
>
> Type safety: The expression of type JSONContainer needs unchecked conversion to conform to JSONContainer
It's the compiler warning you about heap pollution. The IDE merely translated this compiler warning (which is what you'd see on the command line)…
...Communicator.java uses unchecked or unsafe operations.
...Recompile with -Xlint:unchecked for details.
…into the more user-friendly message the IDE showed you.
It is only a warning; not an error. To make that warning go away, change this: JSONContainer<CommonNoun> typeContainer = ...
to this: JSONContainer typeContainer = ...
> „When executed, my err log reads:“
>
> result = {"myObject":{"cid":{"oid":129},"name":"technology","form":1},"children":[]}
> com.badlogic.gdx.utils.SerializationException: Field not found: cid (java.lang.Object)...
The most likely cause of that error is — like the error message says — either your JSONContainer
class or your CommonNoun
class does not have the cid
field that is present in the JSON
string you're trying to deserialize.
I was able to reproduce that error with this…
...
private static final String JADEN_AS_JSON = "{jden:{class:CommonNoun,person:Jaden,place:Hollywood,thing:HashBeen}}";
private static final String JADEN_FAILS_AS_ACTOR = "{jden:{class:CommonNoun,person:Jaden,place:Hollywood,thing:HasBeen, cid:{oid:129} }}";
static public void main( String ... args ){
out.printf( "%1$22s%n", "foo");
JSONContainer< CommonNoun > wtf = new JSONContainer< > ( );
CommonNoun wtBrattyF = new CommonNoun( "Jaden Pinkett Smith", "Hollywood", "HasBeen" );
wtf.setJden( wtBrattyF );
out.printf( "%1$42s%n", wtf );
Json jden = new Json();
out.printf("%1$59s%n", jden.toJson( wtf ) );
JSONContainer wtReifiableF = jden.fromJson(JSONContainer.class, JADEN_AS_JSON); /* This is fine */
out.printf("%1$59s%n", jden.toJson( wtReifiableF ) );
JSONContainer/*< CommonNoun >*/ wtUnReifiableF = jden.fromJson( JSONContainer.class, JADEN_AS_JSON );
wtUnReifiableF = jden.fromJson( JSONContainer.class, JADEN_FAILS_AS_ACTOR ); /* This causes the error you reported */
}
...
Early on it succeeds; but later on it fails…
JSONContainer [ jden: CommonNoun [ person: Jaden Pinkett Smith, place: Hollywood, thing: HasBeen ] ]
{jden:{class:CommonNoun,person:Jaden Pinkett Smith,place:Hollywood,thing:HasBeen}}
{jden:{class:CommonNoun,person:Jaden,place:Hollywood,thing:HashBeen}}
Exception in thread "main" com.badlogic.gdx.utils.SerializationException: Field not found: cid (CommonNoun)
Serialization trace:
{}.jden.cid
jden (JSONContainer)
at com.badlogic.gdx.utils.Json.readFields(Json.java:893)
at com.badlogic.gdx.utils.Json.readValue(Json.java:1074)
at com.badlogic.gdx.utils.Json.readFields(Json.java:902)
at com.badlogic.gdx.utils.Json.readValue(Json.java:1074)
at com.badlogic.gdx.utils.Json.fromJson(Json.java:829)
at DeduperAnswer.main(DeduperAnswer.java:33)
I have now confirmed by experimentation that given the existence of a Cid
class…
public class Cid {
int oid;
/* ... getter and setter elided ... */
}
… And given the existence of a CommonNoun
class that HAS A Cid
…
public class CommonNoun {
Cid cid;
String name;
int form;
/* ... getters and setters elided ... */
}
…Then trying to deserialize a JSONContainer
from a result
that has the following value, will produce the exact same error you originally reported…
result = {"myObject":{"cid":{"oid":129},"name":"technology","form":1},"children":[]}
If your actual CommonNoun
class is implemented like my stand-in above (with a Cid
field), then you need to retry your json.fromJson(Class<?>, String)
call with your result
string formatted like…
{myObject:{class:CommonNoun,cid:{oid:139},name:Jada Pinkett Smith,form:69},children:[{myObject:{class:CommonNoun,cid:{oid:666},name:Jaden Pinkett Smith,form:-666},children:[]},{myObject:{class:CommonNoun,cid:{oid:69},name:Willow Pinkett Smith,form:69},children:[]}]}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论