Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
369 views
in Technique[技术] by (71.8m points)

java - Generate JNI header files for class files in JDK 10

An integral part of the Java Native Interface (JNI), is the bridging of JVM code and native code through C headers. The way to generate these header files used to be quite straight forward: simply call the command line utility javah on class files. This process would then generate prototypes for any method marked with the native modifier.

As of Java 10 however, the javah utility has been removed, and its suggested replacement is a new flag "-h" to javac. The replacement works fine if one has the Java source files available, however falls short in cases where only compiled class files are available. (The issue that sparked this question is that I'm trying to generate JNI bindings from Scala sources. My current approach has been to compile them first and then run javah over the resulting class files.)

In a situation where only compiled class files are available, is there a way to generate C header files, similar to the way javah used to?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You can always go via javap. I know, I know. It's ugly, has lots of assumptions, but in case you desperately need to generate headers for lots of files it might be the only option.

#!/bin/bash

# FIRST_ARG - full class name (with package)
# SECOND_ARG - class path

CLASS_NAME=`javap -cp $2 $1 | 
  grep -v "Compiled from" | 
  grep "public class" | 
  cut -f3 -d" " | 
  awk -F"." '{ print $NF }'`

PACKAGE_NAME=`javap -cp $2 $1 | 
  grep -v "Compiled from" | 
  grep "public class" | 
  cut -f3 -d" " | 
  sed s/.${CLASS_NAME}$//`

DIR_NAME=`echo $PACKAGE_NAME | sed 's|.|/|g'`
mkdir -p java_jni/${DIR_NAME}

JAVA_FILE_NAME="java_jni/${DIR_NAME}/${CLASS_NAME}.java"

echo "package ${PACKAGE_NAME};" > ${JAVA_FILE_NAME}
echo "public class ${CLASS_NAME} {" >> ${JAVA_FILE_NAME}

javap -cp $2 $1 | grep "native" | while read line; do
  param=0
  comma=`echo $line | grep "," | wc -l`
  while [ $comma -gt 0 ]; do
    line=`echo $line | sed "s/,/ param_${param}|/"`
    let param=param+1
    comma=`echo $line | grep "," | wc -l`
  done
  line=`echo $line | sed "s/)/ param_${param})/" | sed 's/|/,/g'`
  echo "  $line" >> ${JAVA_FILE_NAME}
done

echo "}" >> ${JAVA_FILE_NAME}

mkdir -p c_header
javac -h c_header ${JAVA_FILE_NAME}

I bet it can be made way more beautiful.

For me, now, when I slowly start to think about inevitable move towards Java 10, and all these cases, where I might be surprised by non existing Java source code, I think it's not a bad idea to have some tool at my disposal. Just in case.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...