我有Rust代码调用Java方法:
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),
])?;
运行它时,会收到很多警告,例如:
WARNING in native method: JNI call made without checking exceptions when required to from CallVoidMethod
at sun.dc.pr.PathStroker.dispose(Native Method)
at sun.dc.DuctusRenderingEngine.createStrokedShape(DuctusRenderingEngine.java:108)
at java.awt.BasicStroke.createStrokedShape(BasicStroke.java:301)
at org.apache.batik.gvt.StrokeShapePainter.getPaintedArea(StrokeShapePainter.java:125)
at org.apache.batik.gvt.StrokeShapePainter.getPaintedBounds2D(StrokeShapePainter.java:134)
at org.apache.batik.gvt.CompositeShapePainter.getPaintedBounds2D(CompositeShapePainter.java:156)
at org.apache.batik.gvt.ShapeNode.getPrimitiveBounds(ShapeNode.java:238)
at org.apache.batik.gvt.AbstractGraphicsNode.getTransformedPrimitiveBounds(AbstractGraphicsNode.java:854)
at org.apache.batik.gvt.AbstractGraphicsNode.getTransformedBounds(AbstractGraphicsNode.java:820)
at org.apache.batik.gvt.CompositeGraphicsNode.getPrimitiveBounds(CompositeGraphicsNode.java:224)
at org.apache.batik.gvt.CompositeGraphicsNode.getTransformedPrimitiveBounds(CompositeGraphicsNode.java:295)
at org.apache.batik.gvt.AbstractGraphicsNode.getTransformedBounds(AbstractGraphicsNode.java:820)
at org.apache.batik.gvt.CompositeGraphicsNode.getPrimitiveBounds(CompositeGraphicsNode.java:207)
at org.apache.batik.gvt.AbstractGraphicsNode.getBounds(AbstractGraphicsNode.java:768)
at org.apache.batik.gvt.AbstractGraphicsNode.paint(AbstractGraphicsNode.java:443)
at 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);
}
Cargo.toml:
[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"]
ToPixels.java:
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());
}
}
}
pom.xml:
<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>
如何修改我的代码以检查异常,以使其不会显示数百种此类警告?
答案 0 :(得分:1)
在JNI下进行开发时,可能引发异常的函数必须紧随ExceptionCheck
或ExceptionOccurred
原语之后才能正确处理异常。在jni
板条箱中,它们被转换为方法exception_occurred
和exception_check
。方法call_static_method
或call_method
本身不会执行异常处理。
let result = je.call_static_method(cls, "renderTo", "(II[B)V", &[
JValue::from(width),
JValue::from(height),
JValue::from(rgbs2),
])?;
je.exception_check()?;
另请参阅:
答案 1 :(得分:0)
另一个类似异常的来源是Java的事件处理循环
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)
这使我研究了禁用Java的GUI事件循环的可能性。通过修改我的代码以将-Djava.awt.headless=true
传递给JVM,我消除了警告流。
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
}