【问题标题】:Gluon Client Plugin: Building APK with Jackson and Java Time ModuleGluon 客户端插件:使用 Jackson 和 Java 时间模块构建 APK
【发布时间】:2021-03-25 05:25:52
【问题描述】:

这是来自 gluon client samples 项目的 HelloFX 项目。

我添加了一个名为“Person”的模型。

package hellofx;
import java.time.LocalDate;

public class Person {
    private Integer id;
    private String name;
    private LocalDate dob;

    // Getters and Setters
}

并在'pom.xml'中添加了如下依赖:

  • 杰克逊数据绑定
  • jackson-datatype-jsr310

并在主类中增加了序列化和反序列化方法。

public class HelloFX extends Application {

    private Label parseStatusLabel = new Label("");
    
    private String serializedString = null;

    public void start(Stage stage) {
        String javaVersion = System.getProperty("java.version");
        String javafxVersion = System.getProperty("javafx.version");
        Label label = new Label("Hello, JavaFX " + javafxVersion + ", running on Java " + javaVersion + ".");

        ImageView imageView = new ImageView(new Image(HelloFX.class.getResourceAsStream("/hellofx/openduke.png")));
        imageView.setFitHeight(200);
        imageView.setPreserveRatio(true);

        Button serButton = new Button("Serialize");
        serButton.setOnAction(e -> serialize());

        Button deserButton = new Button("Deserialize");
        deserButton.setOnAction(e -> deserialize());

        VBox root = new VBox(30, imageView, label, serButton, deserButton, parseStatusLabel);
        root.setAlignment(Pos.CENTER);
        Scene scene = new Scene(root, 640, 480);
        scene.getStylesheets().add(HelloFX.class.getResource("styles.css").toExternalForm());
        stage.setScene(scene);
        stage.show();
    }

    private void serialize() {
        Person person = new Person();
        person.setId(1);
        person.setName("John Doe");
        person.setDob(LocalDate.of(1960, 10, 10));

        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new JavaTimeModule());

        try {
            serializedString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(person);
            parseStatusLabel.setText("Serialization success \n" + serializedString);
        } catch (JsonProcessingException e) {
            parseStatusLabel.setText("Serialization failed");
            e.printStackTrace();
        }
    }

    private void deserialize() {
        try {
            ObjectMapper mapper = new ObjectMapper();
            mapper.registerModule(new JavaTimeModule());

            Person person = mapper.readValue(serializedString, Person.class);
            parseStatusLabel.setText("Deserialization successful > " + person);
        } catch (JsonMappingException e) {
            parseStatusLabel.setText("Deserialization failed");
            e.printStackTrace();
        } catch (JsonProcessingException e) {
            parseStatusLabel.setText("Deserialization failed");
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        launch(args);
    }

}

我在桌面上运行它并且运行良好。序列化和反序列化都有效。 然后我尝试使用 mvn client:build -P android 构建 APK,运行 mvn client:runagent 后会引发以下错误事件。

[Thu Mar 25 10:38:59 IST 2021][INFO] We will now compile your code for aarch64-linux-android. This may take some time.
[Thu Mar 25 10:39:14 IST 2021][INFO] [SUB] [hellofx.hellofx:215]    classlist:   5,873.73 ms,  0.96 GB
[Thu Mar 25 10:39:16 IST 2021][INFO] [SUB] [hellofx.hellofx:215]        (cap):     288.58 ms,  0.96 GB
[Thu Mar 25 10:39:17 IST 2021][INFO] [SUB] [hellofx.hellofx:215]        setup:   2,968.21 ms,  0.96 GB
[Thu Mar 25 10:40:25 IST 2021][INFO] [SUB] [hellofx.hellofx:215]     (clinit):   1,142.49 ms,  3.74 GB
[Thu Mar 25 10:40:25 IST 2021][INFO] [SUB] [hellofx.hellofx:215]   (typeflow):  30,888.81 ms,  3.74 GB
[Thu Mar 25 10:40:25 IST 2021][INFO] [SUB] [hellofx.hellofx:215]    (objects):  28,773.30 ms,  3.74 GB
[Thu Mar 25 10:40:25 IST 2021][INFO] [SUB] [hellofx.hellofx:215]   (features):   5,209.44 ms,  3.74 GB
[Thu Mar 25 10:40:26 IST 2021][INFO] [SUB] [hellofx.hellofx:215]     analysis:  68,730.14 ms,  3.74 GB
[Thu Mar 25 10:40:26 IST 2021][INFO] [SUB] Warning: Aborting stand-alone image build. Unsupported features in 11 methods[Thu Mar 25 10:40:26 IST 2021][INFO] [SUB] Detailed message:
[Thu Mar 25 10:40:26 IST 2021][INFO] [SUB] Error: com.oracle.graal.pointsto.constraints.UnresolvedElementException: Discovered unresolved method during parsing: com.fasterxml.jackson.databind.DeserializationContext.extractScalarFromObject(com.fasterxml.jackson.core.JsonParser, com.fasterxml.jackson.databind.JsonDeserializer, java.lang.Class). To diagnose the issue you can use the --allow-incomplete-classpath option. The missing method is then reported at run time when it is accessed the first time.
[Thu Mar 25 10:40:26 IST 2021][INFO] [SUB] Trace:
[Thu Mar 25 10:40:26 IST 2021][INFO] [SUB]      at parsing com.fasterxml.jackson.datatype.jsr310.deser.DurationDeserializer.deserialize(DurationDeserializer.java:137)
[Thu Mar 25 10:40:26 IST 2021][INFO] [SUB] Call path from entry point to com.fasterxml.jackson.datatype.jsr310.deser.DurationDeserializer.deserialize(JsonParser, DeserializationContext):
[Thu Mar 25 10:40:26 IST 2021][INFO] [SUB]      at com.fasterxml.jackson.datatype.jsr310.deser.DurationDeserializer.deserialize(DurationDeserializer.java:125)
[Thu Mar 25 10:40:26 IST 2021][INFO] [SUB]      at com.fasterxml.jackson.datatype.jsr310.deser.DurationDeserializer.deserialize(DurationDeserializer.java:43)
[Thu Mar 25 10:40:26 IST 2021][INFO] [SUB]      at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4482)
[Thu Mar 25 10:40:26 IST 2021][INFO] [SUB]      at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3434)
[Thu Mar 25 10:40:26 IST 2021][INFO] [SUB]      at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3402)
[Thu Mar 25 10:40:26 IST 2021][INFO] [SUB]      at hellofx.HelloFX.deserialize(HelloFX.java:99)
[Thu Mar 25 10:40:26 IST 2021][INFO] [SUB]      at com.oracle.svm.reflect.HelloFX_deserialize_15f8adc753d5dce15c2070972d1be99d7c98ca42_239.invoke(Unknown Source)
[Thu Mar 25 10:40:26 IST 2021][INFO] [SUB]      at java.lang.reflect.Method.invoke(Method.java:566)
[Thu Mar 25 10:40:26 IST 2021][INFO] [SUB]      at com.sun.prism.GraphicsPipeline.createPipeline(GraphicsPipeline.java:224)
[Thu Mar 25 10:40:26 IST 2021][INFO] [SUB]      at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.init(QuantumRenderer.java:91)
[Thu Mar 25 10:40:26 IST 2021][INFO] [SUB]      at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:124)
[Thu Mar 25 10:40:26 IST 2021][INFO] [SUB]      at com.oracle.svm.jni.JNIJavaCallWrappers.jniInvoke_ARRAY:Ljava_lang_Runnable_2_0002erun_00028_00029V(generated:0)
[Thu Mar 25 10:40:26 IST 2021][INFO] [SUB] Error: com.oracle.graal.pointsto.constraints.UnresolvedElementException: Discovered unresolved method during parsing: com.fasterxml.jackson.databind.DeserializationContext.extractScalarFromObject(com.fasterxml.jackson.core.JsonParser, com.fasterxml.jackson.databind.JsonDeserializer, java.lang.Class). To diagnose the issue you can use the --allow-incomplete-classpath option. The missing method is then reported at run time when it is accessed the first time.
[Thu Mar 25 10:40:26 IST 2021][INFO] [SUB] Trace:
[Thu Mar 25 10:40:26 IST 2021][INFO] [SUB]      at parsing com.fasterxml.jackson.datatype.jsr310.deser.InstantDeserializer.deserialize(InstantDeserializer.java:213)
[Thu Mar 25 10:40:26 IST 2021][INFO] [SUB] Call path from entry point to com.fasterxml.jackson.datatype.jsr310.deser.InstantDeserializer.deserialize(JsonParser, DeserializationContext):
[Thu Mar 25 10:40:26 IST 2021][INFO] [SUB]      at com.fasterxml.jackson.datatype.jsr310.deser.InstantDeserializer.deserialize(InstantDeserializer.java:202)
[Thu Mar 25 10:40:26 IST 2021][INFO] [SUB]      at com.fasterxml.jackson.datatype.jsr310.deser.InstantDeserializer.deserialize(InstantDeserializer.java:50)
[Thu Mar 25 10:40:26 IST 2021][INFO] [SUB]      at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4482)
[Thu Mar 25 10:40:26 IST 2021][INFO] [SUB]      at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3434)
[Thu Mar 25 10:40:26 IST 2021][INFO] [SUB]      at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3402)
[Thu Mar 25 10:40:26 IST 2021][INFO] [SUB]      at hellofx.HelloFX.deserialize(HelloFX.java:99)
[Thu Mar 25 10:40:26 IST 2021][INFO] [SUB]      at com.oracle.svm.reflect.HelloFX_deserialize_15f8adc753d5dce15c2070972d1be99d7c98ca42_239.invoke(Unknown Source)
[Thu Mar 25 10:40:26 IST 2021][INFO] [SUB]      at java.lang.reflect.Method.invoke(Method.java:566)
[Thu Mar 25 10:40:26 IST 2021][INFO] [SUB]      at com.sun.prism.GraphicsPipeline.createPipeline(GraphicsPipeline.java:224)
[Thu Mar 25 10:40:26 IST 2021][INFO] [SUB]      at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.init(QuantumRenderer.java:91)
[Thu Mar 25 10:40:26 IST 2021][INFO] [SUB]      at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:124)
[Thu Mar 25 10:40:26 IST 2021][INFO] [SUB]      at 

这是full log

我已经在不使用“LocalDate”和“JavaTimeModule”的情况下测试了该应用程序,并且能够构建 APK 并且解析也有效。

这是完整的 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>hellofx</groupId>
    <artifactId>hellofx</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>HelloFX</name>

    <properties>
        <main.class>hellofx.HelloFX</main.class>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.release>11</maven.compiler.release>
        <javafx.version>15.0.1</javafx.version>
        <javafx.maven.plugin.version>0.0.5</javafx.maven.plugin.version>
        <client.maven.plugin.version>0.1.38</client.maven.plugin.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-controls</artifactId>
            <version>${javafx.version}</version>
        </dependency>

        <!-- Added jackson dependency here -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.11.1</version>
        </dependency>
        <!-- Added JavaTime data type -->
        <dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-jsr310</artifactId>
            <version>2.12.2</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
            </plugin>

            <plugin>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-maven-plugin</artifactId>
                <version>${javafx.maven.plugin.version}</version>
                <configuration>
                    <mainClass>${main.class}</mainClass>
                </configuration>
            </plugin>

            <plugin>
                <groupId>com.gluonhq</groupId>
                <artifactId>client-maven-plugin</artifactId>
                <version>${client.maven.plugin.version}</version>
                <configuration>
                     <target>${client.target}</target>
                     <mainClass>${main.class}</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <profiles>
        <profile>
            <id>desktop</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <properties>
                <client.target>host</client.target>
            </properties>
        </profile>
        <profile>
            <id>ios</id>
            <properties>
                <client.target>ios</client.target>
            </properties>
        </profile>
        <profile>
            <id>android</id>
            <properties>
                <client.target>android</client.target>
            </properties>
        </profile>
    </profiles>

</project>

如何解决这个问题?

更新 #1:-

  1. 所有 JSON 配置文件均已使用 'client:runagent' 目标创建:-
    在有关此问题的previous question 中,Jose Pereda 指示我使用“mvn client:runagent”。因为我在 WSL 中使用 Ubuntu,所以我在 windows 命令提示符下运行了这个目标,并编辑了一些配置文件以删除 windows 特定的配置。
  2. 问题不是由杰克逊引起的,“JavaTimeModule”是:-
    我已经从 'Person' 中删除了 LocalDate 'dob' 属性,并在 HelloFX.java 中注释掉了以下内容。
    mapper.registerModule(new JavaTimeModule());
    之后,我能够构建和运行 APK,并且序列化和反序列化都工作了。

我还尝试按照 dzim 的建议在基板文件夹下手动添加“reflectionconfig.json”。但是会出现同样的问题。

【问题讨论】:

  • 简短回答:您需要更新反射配置。稍后我将尝试编译更详细的答案。 Gluon 提供的documentation 更详细。
  • 请注意(因为我只是在回答中简要提及):您可能需要将您的资源添加到pom.xml。有些已经被 Gluon 列入白名单(使用一些通配符),但我不记得它们都是什么。我总是将我认为必要的所有内容添加到pom.xml 中的resourcesList 节点。

标签: java gluon-mobile javafx-11


【解决方案1】:

的长答案你需要更新你的反射配置。(因为Jackson 正在做什么,GraalVM 需要知道它,因为它是预编译的)。

文档

最重要的是:确保您已阅读 Gluon 提供的 documentation

它详细描述了你可以做什么。

client:runagent

主题client:runagent 描述,您可以附加 GraalVM 的代理来检测所有反射等。

我是手动完成的,效果很好。但它是
a) 详尽且
b) 做的太多了。

Gluon 已经准备好与 JavaFX 相关的所有内容,因此您只需添加您的具体内容。

配置

请参阅here,了解有关在您的应用需要一些额外配置时需要执行的操作的更多一般详细信息。 这不仅涉及反射,还涉及其他任何内容(目标平台、资源、特定于平台的构建信息等)。

你的实际问题

反射配置

我也有一个使用 Jackson 的小应用程序。

在您的 maven 资源 (src/main/resources) 下添加 META-INF/substrate/config
添加一个名为reflectionconfig.jsonjson 文件并添加以下内容:

[
  {
    "name": "com.fasterxml.jackson.databind.ObjectMapper",
    "methods": [
      { "name": "<init>", "parameterTypes": [] },
      { "name": "<init>", "parameterTypes": ["com.fasterxml.jackson.core.JsonFactory"] }
    ]
  }
]

这告诉 GraalVM(我想,我不是 100% 确定,tbh),它需要初始化这个类和指定的方法,以便在生成的 AOT 本机可执行文件中进行反射。

pom.xml

更新您的 client-maven-plugin &lt;configuration&gt; 部分,以包含有关您要使用 Jackson 反序列化/序列化的类的更多信息。

<configuration>
  <!-- ... main class, etc. -->

  <reflectionList>

    <!-- ... -->

    <!-- our own JSON data classes below -->
    
    <!-- more Jackson stuff -->
    <list>com.fasterxml.jackson.core.JsonFactory</list>

    <!-- ... -->
  </reflectionList>
</configuration>

总结

至少我的应用程序就足够了。

如果您添加像 Ikonli 这样的依赖项,您需要更多配置。直接或间接使用反射的所有内容(也包括您自己的代码)都需要添加到一个位置(反射配置)或另一个位置(pom.xml)。

例如:如果您使用 FXML,据我所知,您的控制器和 FXML 中使用的所有小部件也需要添加到 pom.xml

干杯


2021 年 3 月 30 日编辑

首先:很遗憾听到您仍在为此苦苦挣扎。我有点错过了关于 Jackson JavaTimeModule 的部分......

我曾经从另一个开发人员那里得到提示,将以下参数添加到您的原生图像参数-H:+AllowIncompleteClasspath(请参阅here)。

生成的文件有时也需要一些调整才能正常工作:大多数时候删除一些指向 graalvm 本身的链接,或 com.sun 的东西。
昨天我在使用 Kotlin-Reflect 时遇到了一些困难,我需要添加一些反射和资源。也可能是这种情况。

我不知道这是否可行,但您可以尝试手动将上述方法添加到反射配置 JSON:

[
{
  "name":"com.fasterxml.jackson.databind.DeserializationContext",
  "methods":[{"name":"extractScalarFromObject","parameterTypes":["com.fasterxml.jackson.core.JsonParser","com.fasterxml.jackson.databind.JsonDeserializer","java.lang.Class"] }]
}
]

也许向 JSON 配置添加一些资源也可能会有所帮助:

{
  "resources":{
  "includes":[
    // others
    {"pattern":"META-INF/services/.*"}
  ]},
  "bundles":[]
}

为什么?因为模块中有一个服务加载器定义。见here

但老实说:如果没有真正可以尝试的应用程序(不,我不会尝试在这里重新创建你的应用程序),我可能无法交付最后缺失的部分......

¯\(ツ)

【讨论】:

  • 嗨,我已经运行了'client:runagent'。但问题仍然存在。我试过手动添加 json 配置。它也没有用。我已经更新了问题以获取更多详细信息。请看一看。
  • @Manikandan 看看,如果编辑的答案可以帮助你。否则我不得不说:准备一点 Repo 或 Gist 并尝试在 GraalVMs 问题跟踪器(在 GitHub 上)上提出 question
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-21
  • 1970-01-01
  • 2014-02-18
相关资源
最近更新 更多