Rust代码如何检查Java代码调用引发的异常?

Rust代码如何检查Java代码调用引发的异常?,rust,java-native-interface,Rust,Java Native Interface,我有调用Java方法的Rust代码: let cls = je.find_class("com/purplefrog/batikExperiment/ToPixels")?; let width = 400; let height = 400; let rgbs = je.new_byte_array(width*height*3)?; let rgbs2:JObject = JObject::from(rgbs); let result = je.call_static_method(cl

我有调用Java方法的Rust代码:

let cls = je.find_class("com/purplefrog/batikExperiment/ToPixels")?;

let width = 400;
let height = 400;
let rgbs = je.new_byte_array(width*height*3)?;
let rgbs2:JObject = JObject::from(rgbs);

let result = je.call_static_method(cls, "renderTo", "(II[B)V", &[
    JValue::from(width),
    JValue::from(height),
    JValue::from(rgbs2),
])?;
当我运行它时,会收到很多警告,如:

本机方法中的警告:当需要从CallVoidMethod调用时,JNI调用未检查异常
位于sun.dc.pr.PathStroker.dispose(本机方法)
在sun.dc.DuctusRenderingEngine.createStrokedShape中(DuctusRenderingEngine.java:108)
位于java.awt.BasicStroke.createStrokedShape(BasicStroke.java:301)
位于org.apache.batik.gvt.StrokeShapePainter.getPaintedArea(StrokeShapePainter.java:125)
位于org.apache.batik.gvt.StrokeShapePainter.getPaintedBounds2D(StrokeShapePainter.java:134)
位于org.apache.batik.gvt.CompositeShapePainter.getPaintedBounds2D(CompositeShapePainter.java:156)
位于org.apache.batik.gvt.ShapeNode.getPrimitiveBounds(ShapeNode.java:238)
位于org.apache.batik.gvt.AbstractGraphicsNode.getTransformedPrimitiveBounds(AbstractGraphicsNode.java:854)
位于org.apache.batik.gvt.AbstractGraphicsNode.getTransformedBounds(AbstractGraphicsNode.java:820)
位于org.apache.batik.gvt.CompositeGraphicsNode.getPrimitiveBounds(CompositeGraphicsNode.java:224)
位于org.apache.batik.gvt.CompositeGraphicsNode.getTransformedPrimitiveBounds(CompositeGraphicsNode.java:295)
位于org.apache.batik.gvt.AbstractGraphicsNode.getTransformedBounds(AbstractGraphicsNode.java:820)
位于org.apache.batik.gvt.CompositeGraphicsNode.getPrimitiveBounds(CompositeGraphicsNode.java:207)
位于org.apache.batik.gvt.AbstractGraphicsNode.getBounds(AbstractGraphicsNode.java:768)
位于org.apache.batik.gvt.AbstractGraphicsNode.paint(AbstractGraphicsNode.java:443)
在com.purplefrog.batikExperiment.ToPixels.renderTo(ToPixels.java:49)上
由于E_net4提出了这个问题可能是由核心调用之外的因素引起的,因此我提供了更完整的源代码:

main.rs:

use jni::{InitArgsBuilder, JNIVersion, JavaVM, AttachGuard, JNIEnv};
use jni::objects::{JValue, JObject, AutoLocal};

fn main() -> Result<(), jni::errors::Error>
{
    let jvm_args = InitArgsBuilder::new()
            .version(JNIVersion::V8)
            .option("-Xcheck:jni")
            .option(&format!("-Djava.class.path={}", heinous_classpath()))
            .build()
            .expect("impossible, failed to construct JVM initialization args");

    let jvm:JavaVM = JavaVM::new(jvm_args)?;

    let env:AttachGuard = jvm.attach_current_thread()?;
    let je:&JNIEnv = &env; // this is just so intellij's larval rust plugin can give me method name completion

    let cls = je.find_class("com/purplefrog/batikExperiment/ToPixels")?;

    je.exception_check()?;

    let width = 400;
    let height = 400;
    let rgbs = AutoLocal::new(&je,
                              JObject::from(je.new_byte_array(width*height*3)? ) );
    je.exception_check()?;

    println!("before calling renderTo()");

    let result = je.call_static_method(cls, "renderTo", "(II[B)V", &[
        JValue::from(width),
        JValue::from(height),
        JValue::from(rgbs.as_obj()),
    ])?;
    je.exception_check()?;

    println!("{:?}", result);

    let blen = je.get_array_length(*rgbs.as_obj())? as usize;
    je.exception_check()?;
    let mut rgbs3:Vec<i8> = vec![0; blen];
    println!("byte array length = {}", blen);

    je.get_byte_array_region(*rgbs.as_obj(), 0, &mut rgbs3)?;
    je.exception_check()?;

    save_as_PPM(width, height, &rgbs3, "/tmp/x.ppm").expect("failed to save PPM");

    return Ok(());
}

pub fn save_as_PPM(width: i32, height: i32, rgbs3: & Vec<i8>, file_name: &str)-> Result<(),std::io::Error>
{
    use std::fs::File;
    use std::path::Path;
    use std::io::Write;
    let mut f = File::create(Path::new(file_name))?;
    f.write_all(format!("P6\n{} {} 255\n", width, height).as_bytes())?;
    let tmp: &[u8] = unsafe { &*(rgbs3.as_slice() as *const _ as *const [u8]) };
    f.write_all(tmp)?;
    println!("wrote {}", file_name);

    Ok(())
}

fn heinous_classpath() -> String
{
    let x = "/home/thoth/src/batik-experiment/target/appassembler/etc\
:/home/thoth/src/batik-experiment/target/appassembler/repo/org/apache/xmlgraphics/batik-rasterizer/1.11/batik-rasterizer-1.11.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/org/apache/xmlgraphics/batik-svgrasterizer/1.11/batik-svgrasterizer-1.11.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/org/apache/xmlgraphics/batik-parser/1.11/batik-parser-1.11.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/org/apache/xmlgraphics/batik-awt-util/1.11/batik-awt-util-1.11.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/org/apache/xmlgraphics/xmlgraphics-commons/2.3/xmlgraphics-commons-2.3.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/commons-io/commons-io/1.3.1/commons-io-1.3.1.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/commons-logging/commons-logging/1.0.4/commons-logging-1.0.4.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/org/apache/xmlgraphics/batik-xml/1.11/batik-xml-1.11.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/xml-apis/xml-apis-ext/1.3.04/xml-apis-ext-1.3.04.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/org/apache/xmlgraphics/batik-transcoder/1.11/batik-transcoder-1.11.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/org/apache/xmlgraphics/batik-anim/1.11/batik-anim-1.11.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/org/apache/xmlgraphics/batik-css/1.11/batik-css-1.11.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/org/apache/xmlgraphics/batik-ext/1.11/batik-ext-1.11.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/org/apache/xmlgraphics/batik-svg-dom/1.11/batik-svg-dom-1.11.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/org/apache/xmlgraphics/batik-bridge/1.11/batik-bridge-1.11.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/org/apache/xmlgraphics/batik-script/1.11/batik-script-1.11.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/org/apache/xmlgraphics/batik-dom/1.11/batik-dom-1.11.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/xalan/xalan/2.7.2/xalan-2.7.2.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/xalan/serializer/2.7.2/serializer-2.7.2.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/xml-apis/xml-apis/1.3.04/xml-apis-1.3.04.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/org/apache/xmlgraphics/batik-gvt/1.11/batik-gvt-1.11.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/org/apache/xmlgraphics/batik-svggen/1.11/batik-svggen-1.11.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/org/apache/xmlgraphics/batik-util/1.11/batik-util-1.11.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/org/apache/xmlgraphics/batik-constants/1.11/batik-constants-1.11.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/org/apache/xmlgraphics/batik-i18n/1.11/batik-i18n-1.11.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/org/apache/xmlgraphics/batik-codec/1.11/batik-codec-1.11.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/com/purplefrog/penrose/1.0-SNAPSHOT/penrose-1.0-SNAPSHOT.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/com/purplefrog/knotwork/1.0-SNAPSHOT/knotwork-1.0-SNAPSHOT.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/com/purplefrog/batikExperiment/batikExperiment/1.0-SNAPSHOT/batikExperiment-1.0-SNAPSHOT.jar";
    return String::from(x);
}
使用jni:{InitArgsBuilder,JNIVersion,JavaVM,AttachGuard,JNIEnv};
使用jni::objects::{JValue,JObject,autoloc};
fn main()->结果
{
让jvm_args=InitArgsBuilder::new()
.version(JNIVersion::V8)
.option(“-Xcheck:jni”)
.option(&format!(“-Djava.class.path={}”,henious_classpath()))
.build()
.expect(“不可能,无法构造JVM初始化参数”);
让jvm:JavaVM=JavaVM::new(jvm_args)?;
让env:AttachGuard=jvm.attach_current_thread()?;
让je:&JNIEnv=&env;//这正是intellij的幼虫锈菌插件可以给我方法名的原因
设cls=je.find_class(“com/purplefrog/batikExperiment/ToPixels”)?;
je.异常检查()?;
宽度=400;
设高度=400;
设rgbs=autoloc::new(&je),
JObject::from(je.new_byte_数组(宽度*高度*3)?);
je.异常检查()?;
println!(“调用renderTo()之前”);
让result=je.调用静态方法(cls,“renderTo”,“II[B)V”&[
JValue::from(宽度),
JValue::from(高度),
JValue::from(rgbs.as_obj()),
])?;
je.异常检查()?;
println!(“{:?}”,结果);
设blen=je.get_数组_长度(*rgbs.as_obj())?as usize;
je.异常检查()?;
让mut rgbs3:Vec=Vec![0;blen];
println!(“字节数组长度={}”,blen);
je.get_byte_array_region(*rgbs.as_obj()、0和mut rgbs3)?;
je.异常检查()?;
保存为PPM(宽度、高度和rgbs3,“/tmp/x.PPM”)。预期(“保存PPM失败”);
返回Ok(());
}
发布fn另存为PPM(宽度:i32,高度:i32,rgbs3:&Vec,文件名:&str)->结果
{
使用std::fs::File;
使用std::path::path;
使用std::io::Write;
让mut f=File::create(路径::new(文件名))?;
f、 写入所有(格式!(“P6\n{}{}255\n”,宽度,高度).as_bytes())?;
设tmp:&[u8]=unsafe{&*(rgbs3.as_slice()as*const u as*const[u8]);
f、 全部写入(tmp)?;
println!(“写入{}”,文件名);
好(())
}
fn henious_classpath()->字符串
{
让x=“/home/thoth/src/batik实验/target/appassembler/etc\
:/home/thoth/src/batik-experiment/target/appassembler/repo/org/apache/xmlgraphics/batik-rasterizer/1.11/batik-rasterizer-1.11.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/org/apache/xmlgraphics/batik-svgrasterizer/1.11/batik-svgrasterizer-1.11.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/org/apache/xmlgraphics/batik-parser/1.11/batik-parser-1.11.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/org/apache/xmlgraphics/batik-awt-util/1.11/batik-awt-util-1.11.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/org/apache/xmlgraphics/xmlgraphics-commons/2.3/xmlgraphics-commons-2.3.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/commons-io/commons-io/1.3.1/commons-io-1.3.1.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/commons-logging/commons-logging/1.0.4/commons-logging-1.0.4.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/org/apache/xmlgraphics/batik-xml/1.11/batik-xml-1.11.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/xml-api/xml-api-ext/1.3.04/xml-api-ext-1.3.04.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/org/apache/xmlgraphics/batik-transcoder/1.11/batik-transcoder-1.11.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/org/apache/xmlgraphics/batik-anim/1.11/batik-anim-1.11.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/org/apache/xmlgraphics/batik-css/1.11/batik-css-1.11.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/org/apache/xmlgraphics/batik-ext/1.11/batik-ext-1.11.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/org/apache/xmlgraphics/batik-svg-dom/1.11/batik-svg-dom-1.11.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/org/apache/xmlgraphics/batik-bridge/1.11/batik-bridge-1.11.jar\
:/home/thoth/src/batik-experiment/target/appassembler/repo/org/apache/xmlgraphics/batik-script/1.11/batik-script-1.11.jar\
:/h
[package]
name = "rust_call_jni"
version = "0.1.0"
authors = ["Robert Forsman <git@thoth.purplefrog.com>"]
edition = "2018"


[dependencies.jni]
version="0.12.3"
features=["invocation"]
package com.purplefrog.batikExperiment;

import org.apache.batik.anim.dom.*;
import org.apache.batik.bridge.*;
import org.apache.batik.gvt.*;
import org.apache.batik.gvt.renderer.*;
import org.apache.batik.util.*;
import org.w3c.dom.*;

import javax.imageio.*;
import java.awt.*;
import java.awt.color.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.io.*;
import java.util.List;

public class ToPixels
{
    public static void main(String[] args)
        throws IOException
    {
        Document document = ultraflower();

        // create the GVT
        GraphicsNode gn = parseSVG(document);

        BufferedImage bi = renderImageTest1(gn);

        ImageIO.write(bi, "PNG", new File("/tmp/x.png"));
    }

    public static void renderTo(int width, int height, byte[] rgbPixels)
    {
        System.out.println("renderTo");
        try {
            List<GraphicsNode> gns = sampleGN1();
            System.out.println("graphics node "+gns);
            BufferedImage bi = rgbToWritableRaster(width, height, rgbPixels);
            System.out.println("BufferedImage "+bi);
            Graphics2D g = bi.createGraphics();
            System.out.println(g);

            double s = width / 1920.;

            g.scale(s, s);
            g.translate(0, (height/s-1080)/2.0);
            for (Object child : gns) {
                ((GraphicsNode) child).paint(g);
            }
            System.out.println("painted");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static BufferedImage rgbToWritableRaster(int width, int height, byte[] rgbPixels)
    {
        ColorModel cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB),
            new int[] {8,8,8}, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
        System.out.println("ColorModel "+cm);
        System.out.println(rgbPixels.length +" vs "+(width*height*3));
        DataBuffer buffer = new DataBufferByte(rgbPixels, width*height*3);
        System.out.println("databuffer "+buffer);
        WritableRaster wr = Raster.createWritableRaster(cm.createCompatibleSampleModel(width, height), buffer, new Point());
        System.out.println("writableraster "+wr);
        return new BufferedImage(cm, wr, false, null);
    }

    public static class Exp2 {
        public static void main(String[] args)
            throws IOException
        {
            int width = 400;
            int height = 600;
            byte[] rgbs = new byte[width * height *3];
            renderTo(width, height, rgbs);
            String fname = "/tmp/x.ppm";
            OutputStream ostr = new FileOutputStream(fname);
            ostr.write(("P6\n"+width+" "+height+" 255\n").getBytes());
            ostr.write(rgbs);
            ostr.close();
        }
    }

    public static List<GraphicsNode> sampleGN1()
        throws IOException
    {
        GraphicsNode gn = parseSVG(ultraflower());
        CanvasGraphicsNode canvas = (CanvasGraphicsNode) gn.getRoot().getChildren().get(0);
        return canvas.getChildren();
    }

    public static BufferedImage renderImageTest1(GraphicsNode gn)
    {
        BufferedImage bi;
        if (false) {
            StaticRenderer sr = new StaticRenderer();
            sr.setTree(gn);

            bi = sr.getOffScreen();
        } else {
            bi = new BufferedImage(400,400, BufferedImage.TYPE_INT_ARGB);
            Graphics2D g = bi.createGraphics();
            if (false) {
                g.scale(0.25, 0.25);
                gn.paint(g);
            } else {
                RootGraphicsNode rootGN = (RootGraphicsNode) gn;
                rootGN.getChildren();
                CanvasGraphicsNode canvasGN = (CanvasGraphicsNode) rootGN.getChildren().get(0);
                double s = 400 / 1920.;
                if (false) {
                    AffineTransform at = new AffineTransform(s, 0, 0, s, 0, 0);
                    //canvasGN.setViewingTransform(at);
                    canvasGN.setPositionTransform(at);
                    canvasGN.paint(g);
                    // this appears to clip according to the viewBox
                } else {
                    g.scale(s, s);
                    g.translate(0, (1920-1080)/2.0);
                    for (Object child : canvasGN.getChildren()) {
                        ((GraphicsNode) child).paint(g);
                    }
                }
            }
        }
        return bi;
    }

    public static GraphicsNode parseSVG(Document document)
    {
        UserAgent userAgent = new UserAgentAdapter();
        DocumentLoader loader = new DocumentLoader(userAgent);
        BridgeContext bctx = new BridgeContext(userAgent, loader);
        bctx.setDynamicState(BridgeContext.STATIC);
        GVTBuilder builder = new GVTBuilder();
        return builder.build(bctx, document);
    }

    public static Document ultraflower()
        throws IOException
    {
        String fname = "/home/thoth/art/ultraflower/ultraflower3.svg";

        // create the document
        String parser = XMLResourceDescriptor.getXMLParserClassName();
        SAXSVGDocumentFactory f = new SAXSVGDocumentFactory(parser);
        return f.createDocument(fname, new FileInputStream(fname));
    }

    public static class Madness1
    {
        public static void main(String[] args)
            throws IOException
        {
            String resource = "example1.svg";
            String parser = XMLResourceDescriptor.getXMLParserClassName();
            SAXSVGDocumentFactory f = new SAXSVGDocumentFactory(parser);
            Document doc = f.createDocument(resource, Madness1.class.getResourceAsStream(resource));

            GraphicsNode gn = parseSVG(doc);

            RootGraphicsNode rootGN = (RootGraphicsNode)gn;
            CanvasGraphicsNode canvasGN = (CanvasGraphicsNode) rootGN.getChildren().get(0);

            CompositeGraphicsNode gn1 = (CompositeGraphicsNode) canvasGN.getChildren().get(1);
            System.out.println(gn1.getOutline());
        }
    }
}
<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/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.purplefrog.batikExperiment</groupId>
    <artifactId>batikExperiment</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>batikExperiment</name>
    <url>http://maven.apache.org</url>

    <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.5.1</version>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                    </configuration>
                </plugin>

                <plugin>
                  <groupId>org.codehaus.mojo</groupId>
                  <artifactId>appassembler-maven-plugin</artifactId>
                  <version>1.10</version>
                  <configuration>
                    <programs>
                      <program>
                        <mainClass>com.purplefrog.batikExperiment.PathConverter</mainClass>
                        <id>pathConverter</id>
                      </program>
                    </programs>
                  </configuration>
                </plugin>

            </plugins>
        </build>

    <dependencies>
        <dependency>
            <groupId>org.apache.xmlgraphics</groupId>
            <artifactId>batik-rasterizer</artifactId>
            <version>1.11</version>
        </dependency>
        <dependency>
            <groupId>com.purplefrog</groupId>
            <artifactId>penrose</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>
WARNING in native method: JNI call made without checking exceptions when required to from CallStaticVoidMethod
    at sun.awt.X11.XToolkit.waitForEvents(Native Method)
    at sun.awt.X11.XToolkit.run(XToolkit.java:574)
    at sun.awt.X11.XToolkit.run(XToolkit.java:538)
    at java.lang.Thread.run(Thread.java:748)
pub fn jvm8_args_with_classpath(classpath: &&str) -> InitArgs {
    let jvm_args = InitArgsBuilder::new()
        .version(JNIVersion::V8)
        .option("-Xcheck:jni")
        .option(&format!("-Djava.class.path={}", classpath))
        .option("-Djava.awt.headless=true")
        .build()
        .expect("impossible, failed to construct JVM initialization args");
    jvm_args
}