GluonConnect JSON 转换器无法转换对象

GluonConnect JSON converter cannot convert object

在客户端应用程序上我有这个 POJO

public class Chicken {

    private String name;
    private int age;

    public Chicken(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

我运行这个

RestClient get = RestClient.create().method("GET")
        .host("http://localhost:8080/DevCrowd")
        .path("resources/chickens");
GluonObservableList<Chicken> sample = DataProvider.retrieveList(
        get.createListDataReader(Chicken.class));
System.out.println(sample);

但我收到错误消息:

WARNING: Failed to create object of type class com.devcrowd.test.Chicken from the following json object {"id":1,"name":"AAA","age":12}
java.lang.InstantiationException: com.gluonhq.notesapp.Chicken
    at java.lang.Class.newInstance(Class.java:427)
    at com.gluonhq.connect.converter.JsonConverter.readFromJson(JsonConverter.java:111)
    at com.gluonhq.connect.converter.JsonIterableInputConverter.next(JsonIterableInputConverter.java:108)
    at com.gluonhq.connect.provider.DataProvider.lambda$retrieveList(DataProvider.java:194)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NoSuchMethodException: com.gluonhq.notesapp.Chicken.<init>()
    at java.lang.Class.getConstructor0(Class.java:3082)
    at java.lang.Class.newInstance(Class.java:412)
    ... 6 more

在服务器上我有这个实体:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement
@Entity
@NamedQuery(name="all", query = "SELECT c FROM Chicken C")
public class Chicken {

    @Id
    @GeneratedValue
    private long id;
    private String name;
    private int age;

    public Chicken() {}

    public Chicken(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

和这项服务:

@Path("chickens")
public class ChickensResource {

    @Inject
    ChickenService cs;

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public String chickens() {
        JsonArrayBuilder jsonArrayBuilder = Json.createArrayBuilder();
        List<Chicken> chickens = cs.getAllChickens();
        chickens.stream().map(chicken -> Json.createObjectBuilder()
            .add("name", chicken.getName())
            .add("age", chicken.getAge())
            .build())
            .forEach(jsonArrayBuilder::add);
        return jsonArrayBuilder.build().toString();
    }

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public void save(JsonObject chicken) {
        String name = chicken.getString("name");
        int age = chicken.getInt("age");
        cs.save(new Chicken(name, age));
    }
}

我可以 POST 正确(我检查了数据库,我 POST 在那里,所以这就是错误堆栈准备好 Chicken 对象的原因)但我不能读回来。这是为什么?

您可以在 docs 中看到 JsonConverter::readFromJson:

Convert the provided JSON Object into a Java object. If a new instance could not be created from the specified targetClass in the constructor, then null will be returned.

The conversion works by inspecting all the property methods of the target class. A property method is any field that has both a getter and a setter method.

现在,如果您检查异常:

java.lang.InstantiationException: com.gluonhq.notesapp.Chicken
at java.lang.Class.newInstance(Class.java:427)

原因很清楚了:目标class(com.gluonhq.notesapp.Chicken)不能被实例化,因为它寻找一个无参数的构造函数。

您只需添加一个:

public class Chicken {

    private String name;
    private int age;

    public Chicken() { }

    public Chicken(String name, int age) {
        this.name = name;
        this.age = age;
    } 
    ...
}

编辑

DataProvider returns 一个可观察的列表,你应该使用 initializedProperty() 来找出列表何时准备好,这样你就可以得到它的内容:

RestClient get = RestClient.create().method("GET")
            .host("http://localhost:8080/DevCrowd")
            .path("/resources/chickens");

GluonObservableList<Chicken> sample =  DataProvider.retrieveList(
           get.createListDataReader(Chicken.class));

sample.initializedProperty().addListener((obs, ov, nv) -> {
    if (nv) {
        for (Chicken chicken : sample) {
            System.out.println(chicken);
        }
    }
});