1

jar ファイルの URL リストと、 のようなパス全体のクラス名がcom.mycompany.myproject.Testあります。これらの jar ファイルを検索して、その中の .class ファイルを取得するにはどうすればよいですか? 逆コンパイルに使用します。

String classname = "com.mycompany.myproject.Test";
URI uri = Tool.searchClass(jarList, classname);
// decompile .class
...

このようなサンプルコードはありますか?

追加: シェル スクリプトは優れていますが、Java コードでこの作業を行う方法はありますか?

追加:これを処理するために使用して静的メソッドを作成java.util.jar.JarFileしました。これが他の人に役立つことを願っています

次のコードはテスト済みで、正しく動作します。

/**
 * Search the class by classname specified in jarFile, if found and destFolder specified
 * Copy the .class file into destFolder with whole path.
 * @param classname
 * @param jarFile
 * @param destFolder
 * @return
 */
public static File searchCompressedFile(String classname, File jarFile, String destFolder) {
    try {
        // change classname "." to "/"
        if(classname.contains(".")){
            classname = classname.replace(".", "/");
        }

        JarFile jarF = new JarFile(jarFile);
        Enumeration<JarEntry> jarEntries = jarF.entries();

        while (jarEntries.hasMoreElements()) {
            JarEntry jarEntry = jarEntries.nextElement();
            if (jarEntry.getName().indexOf(classname) >= 0) {
                String filePath = jarFile.getAbsolutePath();
                System.out.println(classname + " is in " + filePath + "--" + jarEntry.getName());

                if (destFolder != null && !"".equals(destFolder)) {
                    // Make folder if dest folder not existed.
                    File destF = new File(destFolder);
                    if (!destF.exists()) {
                        destF.mkdirs();
                    }

                    File f = new File(destFolder + File.separator + jarEntry.getName());
                    if(!f.getParentFile().exists()){
                        f.getParentFile().mkdirs();
                    }
                    InputStream is = jarF.getInputStream(jarEntry);
                    FileOutputStream fos = new java.io.FileOutputStream(f);
                    while (is.available() > 0) {
                        fos.write(is.read());
                    }
                    fos.close();
                    is.close();

                    return f;
                }
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }

    System.out.println("Class not found in jar");
    return null;
}
4

5 に答える 5

1

EJPのヒントは基準点です。非ローカルURLを使用しているのは実際のケースなので、クラスローダーを作成し、クラスをロードして、そのバイトコードを取得する方が適切です。多分どういうわけかそのように:

    URLClassLoader classLoader = new URLClassLoader(list.toArray(new URL[0]));
    Class<?> clazz = classLoader.loadClass(path);
    File tmp = new File(System.getProperty("java.io.tmpdir"), path.replace(".", "_") + ".class");
    FileChannel tmpChannel = new FileOutputStream(tmp).getChannel();
    InputStream is = clazz.getResourceAsStream("/" + path.replace(".", "/") + ".class");
    tmpChannel.transferFrom(Channels.newChannel(is), 0, Long.MAX_VALUE);
    URI uri = tmp.toURI();
于 2012-07-02T05:30:08.603 に答える
1

jar ファイルは実際には.zip. java.util.zip.ZipInputStream次のように検索できます。

import java.util.zip.ZipInputStream;
import java.util.zip.ZipEntry;

public class Test {

    public static void main(String args[]){ 
        try{
                CodeSource src = Main.class.getProtectionDomain().getCodeSource();
                if( src != null ) {
                  URL jar = src.getLocation();  
                  ZipInputStream zip = new ZipInputStream(jar.openStream());                      
                  ZipEntry zipEntry = null;
                  while((zipEntry = zip.getNextEntry()) != null){
                    String entryName = zipEntry.getName();
                    // do what you want
                  }
                }
        }
        catch (Exception e){            
        }       
    }   
}

クラスJarFileを使用する別の回答も見つけました

于 2012-07-02T04:15:10.670 に答える
1

~/bin フォルダーに findClass.sh というシェル スクリプトがあります。

echo "Finding $2 in $1."
for jar in `find $1 -name \*.jar`
do
   echo -n "."
   for class in `jar tf $jar`
   do
     if [[ "`echo $class | grep $2`" = ""  ]] 
     then
        grep test /dev/null 
     else 
        echo -e "\n$jar : $class"
     fi
     done

 done

.jar ファイルのディレクトリが特に大きい場合は、検索に時間がかかることがあります。私は何百もの瓶でそれを使用しましたが、遅いですが効果的です.

于 2012-07-02T04:16:35.173 に答える
1

loadClass()の方法を使用しjava.net.URLClassLoaderます。

于 2012-07-02T04:29:53.347 に答える
0

逆コンパイルには単純な bash スクリプトを使用しています。

#!/bin/bash

if [ -z "$1" ] ; then
    echo "There is no argument please enter jar file name"
    exit -1
fi

FNAME=$1
FNAME_SHORT=`basename $1`
DNAME=${FNAME_SHORT/.*/}_jar

CLASS_DIR=${DNAME}/cls
SRC_DIR=${DNAME}/java

mkdir -p $CLASS_DIR
mkdir -p $SRC_DIR
echo "Unpacking ${FNAME}.."
( cd ${CLASS_DIR} ; unzip -o ../../${FNAME} ) > /dev/null 2>&1 || exit -1
CLASSES="$(cd $DNAME ; find cls -name "*.class" -print)"
if [ ! -z "$CLASSES" ] ; then
    for C in $CLASSES ; do
        CNAME=${C/.*/}
        CNAME=${CNAME#cls/}
        JFILE=$SRC_DIR/${CNAME}.java
        CNAME=${CNAME//\//.}
        if [ -f $JFILE ] ; then
            echo "Skipping $C..."
            continue
        fi
        echo -n "Decompile $C to $DNAME..."
        jad -o -f -d $DNAME/java -lnc -s .java -r $DNAME/$C > /dev/null 2>&1
        if [ $? != 0 ] ; then
            echo "FAILED"
            javap -c -classpath $CLASS_DIR ${CNAME} > $JFILE
        else
            echo "OK"
        fi
    done
fi
于 2012-07-02T04:19:48.093 に答える