2012-12-28 115 views
22

我想更改.class文件的方法。我安装了JD Eclipse Decompiler并打开了.class文件。我添加了一些代码并保存.class文件。但是.class文件没有改变。如何更改已编译的.class文件而不反编译?

我不知道如何使用反编译器。如果有可能,如何在不使用反编译器的情况下更改.class文件。

我使用的是Ubuntu。

问候

编辑:

这里是我的反编译代码:

/*  */ package org.hibernate.id; 
/*  */ 
/*  */ import java.io.Serializable; 
/*  */ import java.sql.ResultSet; 
/*  */ import java.sql.SQLException; 
/*  */ import java.util.HashMap; 
/*  */ import java.util.Properties; 
/*  */ import org.apache.commons.logging.Log; 
/*  */ import org.apache.commons.logging.LogFactory; 
/*  */ import org.hibernate.HibernateException; 
/*  */ import org.hibernate.MappingException; 
/*  */ import org.hibernate.dialect.Dialect; 
/*  */ import org.hibernate.type.Type; 
/*  */ import org.hibernate.util.ReflectHelper; 
/*  */ 
/*  */ public final class IdentifierGeneratorFactory 
/*  */ { 
/* 25 */ private static final Log log = LogFactory.getLog(IdentifierGeneratorFactory.class); 
/*  */ 
/* 64 */ private static final HashMap GENERATORS = new HashMap(); 
/*  */ 
/* 66 */ public static final Serializable SHORT_CIRCUIT_INDICATOR = new Serializable() { 
/*  */  public String toString() { return "SHORT_CIRCUIT_INDICATOR"; 
/*  */  } 
/* 66 */ }; 
/*  */ 
/* 70 */ public static final Serializable POST_INSERT_INDICATOR = new Serializable() { 
/*  */  public String toString() { return "POST_INSERT_INDICATOR"; 
/*  */  } 
/* 70 */ }; 
/*  */ 
/*  */ public static Serializable getGeneratedIdentity(ResultSet rs, Type type) 
/*  */  throws SQLException, HibernateException, IdentifierGenerationException 
/*  */ { 
/* 32 */  if (!(rs.next())) { 
/* 33 */  throw new HibernateException("The database returned no natively generated identity value"); 
/*  */  } 
/* 35 */  Serializable id = get(rs, type); 
/*  */ 
/* 37 */  if (log.isDebugEnabled()) log.debug("Natively generated identity: " + id); 
/* 38 */  return id; 
/*  */ } 
/*  */ 
/*  */ public static Serializable get(ResultSet rs, Type type) 
/*  */  throws SQLException, IdentifierGenerationException 
/*  */ { 
/* 45 */  Class clazz = type.getReturnedClass(); 
/* 46 */  if (clazz == Long.class) { 
/* 47 */  return new Long(rs.getLong(1)); 
/*  */  } 
/* 49 */  if (clazz == Integer.class) { 
/* 50 */  return new Integer(rs.getInt(1)); 
/*  */  } 
/* 52 */  if (clazz == Short.class) { 
/* 53 */  return new Short(rs.getShort(1)); 
/*  */  } 
/* 55 */  if (clazz == String.class) { 
/* 56 */  return rs.getString(1); 
/*  */  } 
       if(clazz == java.math.BigDecimal.class){ 
        return rs.getBigDecimal(1); 
       } 
/*  */ 
/* 59 */  throw new IdentifierGenerationException("this id generator generates long, integer, short or string78"); 
/*  */ } 
/*  */ 
/*  */ public static IdentifierGenerator create(String strategy, Type type, Properties params, Dialect dialect) 
/*  */  throws MappingException 
/*  */ { 
/*  */  try 
/*  */  { 
/* 92 */  Class clazz = getIdentifierGeneratorClass(strategy, dialect); 
/* 93 */  IdentifierGenerator idgen = (IdentifierGenerator)clazz.newInstance(); 
/* 94 */  if (idgen instanceof Configurable) ((Configurable)idgen).configure(type, params, dialect); 
/* 95 */  return idgen; 
/*  */  } 
/*  */  catch (Exception e) { 
/* 98 */  throw new MappingException("could not instantiate id generator", e); 
/*  */  } 
/*  */ } 
/*  */ 
/*  */ public static Class getIdentifierGeneratorClass(String strategy, Dialect dialect) { 
/* 103 */  Class clazz = (Class)GENERATORS.get(strategy); 
/* 104 */  if ("native".equals(strategy)) clazz = dialect.getNativeIdentifierGeneratorClass(); 
/*  */  try { 
/* 106 */  if (clazz == null) clazz = ReflectHelper.classForName(strategy); 
/*  */  } 
/*  */  catch (ClassNotFoundException e) { 
/* 109 */  throw new MappingException("could not interpret id generator strategy: " + strategy); 
/*  */  } 
/* 111 */  return clazz; 
/*  */ } 
/*  */ 
/*  */ public static Number createNumber(long value, Class clazz) throws IdentifierGenerationException { 
/* 115 */  if (clazz == Long.class) { 
/* 116 */  return new Long(value); 
/*  */  } 
/* 118 */  if (clazz == Integer.class) { 
/* 119 */  return new Integer((int)value); 
/*  */  } 
/* 121 */  if (clazz == Short.class) { 
/* 122 */  return new Short((short)(int)value); 
/*  */  } 

/*  */ 
/* 125 */  throw new IdentifierGenerationException("this id generator generates long, integer, short"); 
/*  */ } 
/*  */ 
/*  */ static 
/*  */ { 
/* 75 */  GENERATORS.put("uuid", UUIDHexGenerator.class); 
    GENERATORS.put("hilo", TableHiLoGenerator.class); 
    GENERATORS.put("assigned", Assigned.class); 
    GENERATORS.put("identity", IdentityGenerator.class); 
    GENERATORS.put("select", SelectGenerator.class); 
    GENERATORS.put("sequence", SequenceGenerator.class); 
    GENERATORS.put("seqhilo", SequenceHiLoGenerator.class); 
    GENERATORS.put("increment", IncrementGenerator.class); 
    GENERATORS.put("foreign", ForeignGenerator.class); 
    GENERATORS.put("guid", GUIDGenerator.class); 
    GENERATORS.put("uuid.hex", UUIDHexGenerator.class); 
    GENERATORS.put("sequence-identity", SequenceIdentityGenerator.class); 
    } 
} 
+1

你为什么要这么做? –

+1

因为idgenerator类不支持BigDecimal。我使用Hibernate和PostgreSQL,我得到这个错误:这个ID生成器生成长整型,短整型或字符串 –

+3

使用反编译器比替代方法要容易100倍。如果你发现使用反编译器的想法有点多,我会尝试另一种不涉及改变类的方法。 –

回答

8

使用一个字节码编辑器,如:

http://set.ee/jbe/

要小心,因为你需要一个非常了解Java字节码。

您还可以在运行时使用字节码编织(如AspectJ)更改类。

+1

感谢您的回复,但我没有关于java字节码的知识。 –

+2

我不认为你可以在运行时用反射来改变任何类。你需要一个库来动态创建类来做类似的事情。 – izaera

0

您可以更改代码,当你反编译它,但它必须重新编译为class文件,反编译器输出java代码,这必须与同一类路径重新编译为原jar/class文件

+0

谢谢,我明白了这个想法。但我不知道我是怎么做到的? –

+0

将反编译的代码拖入eclipse中,解析依赖关系,修复错误并使用eclipse重新编译。把生成的类文件放入旧的jar文件中。或者获得原始的源代码。 – epoch

+0

我只能在Eclipse中访问.class文件的.java文件。所以,我不明白“如何将旧文件放入旧jar”? –

3

我添加了一些代码并保存.class文件。

您在JD EClipse Decompiler中看到的是在.class文件中反编译字节码的表示形式。即使您更改文本,也不会影响字节码。

+0

这是我的问题。我改变了但没有效果。 –

+0

@BreedHansen,为什么不生成String而不是BigDecimal?所以你的问题的答案是:这几乎是不可能的。或者你必须提取源代码到eclipse,并尝试用你的修改生成另一个类文件。 –

+0

感谢您的详细回复。我想做这个。这真的不可能吗? https://forum.hibernate.org/viewtopic.php?t=964410 –

29

您可以按照下列步骤来修改你的java类:

  1. 反编译的.class文件,你所做的,并保存为名为.java
  2. 与Java文件在Eclipse中创建一个项目时,原来JAR 图书馆,以及所有依赖的
  3. 更改的.java和编译
  4. 获取修改后的.class文件,并把它再次原来 JAR内。
+0

我无法保存.java文件。其实,我无法保存。我保存了.class文件,但是当我关闭并重新打开时,我的更改即将消失。 –

+0

你能够复制并粘贴反编译的源代码吗? – izaera

+0

下载你想修改的文件的源代码(因为它是Hibernate的一部分)不是更好吗,修改它并重新编译?您可以使用我的方法重新编译,或者只是尝试重新编译整个Hibernate(尽管这可能会更困难)。 – izaera

2

当您反编译并更改代码时,您必须在您的eclipse项目的根文件夹中检查您的类在bin文件夹中,与src处于同一级别。然后用zip工具打开你原来的jar(7zip对此很好),并将修改后的类放入jar中的相同包中。

0

据我所知,没有简单的方法来做到这一点。最简单的方法是实际上不将类文件转换为可执行文件,而是将可执行文件包装到类文件中。也就是说,创建一个可执行文件(可能是一个基于OS的可执行脚本文件),它只需通过命令行调用Java类。

如果你想真的有一个程序来做到这一点,你应该看看那里的一些自动化安装程序。

这是一种方式,我发现:

[code] 
import java.io.*; 
import java.util.jar.*; 

class OnlyExt implements FilenameFilter{ 
String ext; 
public OnlyExt(String ext){ 
this.ext="." + ext; 
} 

@Override 
public boolean accept(File dir,String name){ 
return name.endsWith(ext); 
} 
} 

public class ExeCreator { 
public static int buffer = 10240; 
protected void create(File exefile, File[] listFiles) { 
try { 
byte b[] = new byte[buffer]; 
FileOutputStream fout = new FileOutputStream(exefile); 
JarOutputStream out = new JarOutputStream(fout, new Manifest()); 
for (int i = 0; i < listFiles.length; i++) { 
if (listFiles[i] == null || !listFiles[i].exists()|| listFiles[i].isDirectory()) 
System.out.println("Adding " + listFiles[i].getName()); 
JarEntry addFiles = new JarEntry(listFiles[i].getName()); 
addFiles.setTime(listFiles[i].lastModified()); 
out.putNextEntry(addFiles); 

FileInputStream fin = new FileInputStream(listFiles[i]); 
while (true) { 
int len = fin.read(b, 0, b.length); 
if (len <= 0) 
break; 
out.write(b, 0, len); 
} 
fin.close(); 
} 
out.close(); 
fout.close(); 
System.out.println("Jar File is created successfully."); 
} catch (Exception ex) {} 
} 

public static void main(String[]args){ 
ExeCreator exe=new ExeCreator(); 
FilenameFilter ff = new OnlyExt("class"); 
File folder = new File("./examples"); 
File[] files = folder.listFiles(ff); 
File file=new File("examples.exe"); 
exe.create(file, files); 
} 

} 


[/code]` 
1

使用java的帮助 Java库,用于操纵应用程序的Java字节码(.class文件)。

- > spring,hibernate的,使用这种用于代理实现EJB

- >我们可以字节码操作,做一些程序分析

- >我们就可以用了Javassist来实施方法的返回值的透明缓存通过拦截所有的方法调用,并且只在第一次调用时委托给超级实现。

0

您可以使用任何反编译器首先反编译文件。

我曾经遇到过一个类似的问题,那里没有应用程序的源代码,只好对文件做一个非常小的修改。

下面是我所做的:

  1. 摘自罐子

  2. 在反编译器打开它的类文件(我使用JD GUI,你可以轻易地得到它互联网上的许多资源) 您可以从here下载

  3. 您可以实际查看全部e使用JD GUI的jar文件。

  4. 到我想并从该文件
  5. 创建一个新项目在Eclipse中,只有这个类(使用相同的封装结构,在罐子)复制所有代码的文件所做的更改,提供的原始jar作为库和所有其他依赖项。
  6. 编译的类,从我的工作空间的bin文件夹中注入的.class文件回到罐子
  7. 测试了我的变化,喝着咖啡:)一杯庆祝它
0

有时我们需要编译千个文件中的一个单个文件来解决问题。在这种情况下,One可以像类路径一样创建相同的文件夹结构,将该文件反编译为java或从源代码复制java文件。进行必要的更改,将所有依赖项/类编译到一个类中,最后替换类文件。最后重新启动容器。一旦战争爆炸,文件将不会被替换。