如何从JSON正确读取此泛型? [英] How do I read this Generics correctly from JSON?

查看:88
本文介绍了如何从JSON正确读取此泛型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对我的第一个泛型容器很有信心,但是在客户端如何使用强制转换的措辞上却固执己见.这是我参与学习<T>知识之前的工作方式:

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);

我的IDE对此短语不满意,请注意:

My IDE doesn't care for this phrasing, noting:

类型安全:无需检查JSONContainer类型的表达式 转换以符合JSONContainer

Type safety: The expression of type JSONContainer needs unchecked conversion to conform to 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)

我敢肯定,应该以某种方式在等号右边添加对CommonNoun类型的引用,但我还无法弄清楚.我该怎么做?关于泛型,强制转换,JSON和剥离类信息,有很多适用的文章.我尝试遵循的其中之一与上面的强制转换无关,认为在构造过程中将T类添加为容器内的私有变量:

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:

如何获取类实例通用类型T?

但是我遇到了类似的语法问题,试图在过程中的另一个位置正确地引用该类.我也有疑问,我可以在告诉JSON如何对文件中的信息进行分类之前从JSON文件读取此类变量.

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. 

我可能已经有一个由重复数据删除器提交的可行答案,但是根据要求,这是CommonNounContainer和JSONContainer类:

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();
    }
}

要求的其他课程:

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 :

建议的修复方法...

Proposed Fix…

  1. System.out.println( new Json( ).toJson( new JSONContainer<>( ... ) ) 查看 JSONContainer 正确 字符串格式JSON .
  2. 使 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:[]}]}
  1. System.out.println( new Json( ).toJson( new JSONContainer<>( ... ) ) to see the correct string format of a JSONContainer's JSON.
  2. Make sure your result input argument to Json.fromJson(Class<T>, String) is in the same format printed out in 1.
    • 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:[]}]}



详细答案 ...



The long answer

我的IDE对此短语不满意,请注意:"

Type safety: The expression of type JSONContainer needs unchecked conversion to conform to JSONContainer

这是编译器警告您有关 堆污染 . IDE只是翻译了此编译器警告(这是您在命令行上看到的)…

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.

…进入IDE向您显示的用户友好消息中.

…into the more user-friendly message the IDE showed you.

这只是一个警告;没有错误.要使该警告消失,请将以下内容: JSONContainer<CommonNoun> typeContainer = ... 更改为以下内容: JSONContainer typeContainer = ...

It is only a warning; not an error. To make that warning go away, change this: JSONContainer<CommonNoun> typeContainer = ... to this: JSONContainer typeContainer = ...

执行后,我的错误日志显示为:"

result = {"myObject":{"cid":{"oid":129},"name":"technology","form":1},"children":[]}
com.badlogic.gdx.utils.SerializationException: Field not found: cid (java.lang.Object)...

最可能导致该错误的原因是-,如错误消息中所述-您的 JSONContainer 类或您的 CommonNoun 您要反序列化的 JSON 字符串中没有 cid 字段.

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)



我现在已经通过实验证实,鉴于存在 Cid 类……



I have now confirmed by experimentation that given the existence of a Cid class…

public class Cid { 
    
    int oid;        

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

...并且由于存在 HAS A Cid ...

… 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 ... */
}

...然后尝试从具有以下值的 result 中反序列化 JSONContainer ,将产生与您最初报告的完全相同的错误...

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

如果您的实际 CommonNoun 类是像上面的 stand-in 一样(带有Cid字段的)实现的,则您需要使用格式为...

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

这篇关于如何从JSON正确读取此泛型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆