简体   繁体   English

如何从 JSON 正确读取此 Generics?

[英]How do I read this Generics correctly from JSON?

I'm reasonably confident in my first generics container, but stuck on how to word the casting on the client side.我对我的第一个 generics 容器有相当的信心,但坚持如何在客户端进行转换。 This is what was working before I got involved in learning <T> stuff:这是我参与学习<T>之前的工作:

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.我正在考虑必须为每个 class 创建一个不同的容器,这似乎不是一个好的设计。 Below is my updated, non-working attempt to read in my new generics container:以下是我在新的 generics 容器中读取的更新但无效的尝试:

JSONContainer<CommonNoun> typeContainer = new Json().fromJson(JSONContainer.class, result);

My IDE doesn't care for this phrasing, noting:我的 IDE 不关心这个措辞,注意:

Type safety: The expression of type JSONContainer needs unchecked conversion to conform to JSONContainer类型安全:JSONContainer 类型的表达式需要未经检查的转换才能符合 JSONContainer

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.我确定有某种方法我应该在等号右侧包含对 CommonNoun 类型的引用,但我无法弄清楚。 How do I do it?我该怎么做? There's lots of applicable posts concerning generics, casting, JSON, and stripping away of class information.有很多关于generics,铸造,JSON,剥离class信息的帖子。 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:我试图遵循的其中一个不是关于上面的转换,即在构建过程中将 T class 作为容器内的私有变量添加:

How do I get a class instance of generic type T? 如何获得泛型 T 的 class 实例?

but I ran into similar syntax issues trying to refer to the class correctly, just in a different spot along the process.但我在尝试正确引用 class 时遇到了类似的语法问题,只是在过程中的不同位置。 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.我也有疑问,在告诉 JSON 如何对文件中的信息进行分类之前,我是否可以从 JSON 文件中读取这个 class 变量。

Javadoc for the fromJson(Class<T>, String) method : fromJson(Class<T>, String)方法的 Javadoc

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:我可能已经有 deduper 提交的可行答案,但是,根据要求,这里是 CommonNounContainer 和 JSONContainer 类:

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;

    }

TL;DR : TL;博士

Proposed Fix…建议修复…

  1. System.out.println( new Json( ).toJson( new JSONContainer<>(... ) ) to see the correct string format of a JSONContainer 's JSON . System.out.println( new Json( ).toJson( new JSONContainer<>(... ) )查看JSONContainerJSON正确字符串格式。
  2. Make sure your result input argument to Json.fromJson(Class<T>, String) is in the same format printed out in 1 .确保Json.fromJson(Class<T>, String)result输入参数与1中打印的格式相同。
    • eg {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:[]}]}例如{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:[]}]}


The long answer长答案……

My IDE doesn't care for this phrasing, noting: 我的 IDE 不关心这个措辞,注意:

 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 )… IDE 只是翻译了这个编译器警告(这是你在命令行上看到的)......

...Communicator.java uses unchecked or unsafe operations.
...Recompile with -Xlint:unchecked for details.

…into the more user-friendly message the IDE showed you. …进入更用户友好的消息 IDE 向您展示。

It is only a warning;这只是一个警告; not an error.不是错误。 To make that warning go away, change this: JSONContainer<CommonNoun> typeContainer =... to this: JSONContainer typeContainer =...要使警告 go 消失,请将此: JSONContainer<CommonNoun> typeContainer =...更改为: 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.该错误的最可能原因是 -就像错误消息所说- 您的JSONContainer class 或您的CommonNoun class 没有您尝试解压的JSON字符串中存在的cid字段。

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…我现在已经通过实验证实了Cid类的存在……

public class Cid { 
    
    int oid;        

    /* ... getter and setter elided ... */
}

… And given the existence of a CommonNoun class that HAS A Cid ……鉴于存在一个CidCommonNoun class……

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中反序列JSONContainer ,将产生与您最初报告的完全相同的错误…

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…如果您的实际CommonNoun class 像我上面的替身一样实现(带有Cid字段),那么您需要重试json.fromJson(Class<?>, String)调用, result字符串格式如下......

{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:[]}]}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM