How to change already compiled .class file without decompile?
Asked Answered
C

10

43

I want to change .class file's method. I installed JD Eclipse Decompiler and opened the .class file. I added some codes and save .class file. But, .class file is not changing.

I don't know how to use decompiler. And if is it possible, how to change .class file without using decompiler.

I am using Ubuntu.

Regards

EDIT:

Here is my decompiled code:

/*     */ 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);
   }
 }
Chemmy answered 28/12, 2012 at 11:49 Comment(4)
why would you want to do that?Hade
Because idgenerator class not support BigDecimal. I use Hibernate and PostgreSQL and I get this error : this id generator generates long, integer, short or stringChemmy
Using a decompiler is 100x easier than the alternatives. If you find the idea of using a decompiler a bit much, I would try another approach which doesn't involve changing the class.Countertype
Of course, i will be very happy.Chemmy
M
49

You can follow these steps to modify your java class:

  1. Decompile the .class file as you have done and save it as .java
  2. Create a project in Eclipse with that java file, the original JAR as library, and all its dependencies
  3. Change the .java and compile
  4. Get the modified .class file and put it again inside the original JAR.
Mike answered 28/12, 2012 at 11:53 Comment(7)
I can't save .java file. Actually, i can't save anyway. I saved .class file but when I close and reopen my changes are disappear.Chemmy
Wouldn't it be better to download the source code for the file you want to modify (as it is part of Hibernate), change it, and recompile? You can use my method to recompile or just try to recompile the whole Hibernate (though this can be harder).Mike
Then, you have it. Just save it to a Java file, add the modifications in the forum, and do what I proposed.Mike
I can't save. When I close the .class file, changes are disappears. Because I can't recompile.Chemmy
You forgot one other option. Disassemble, modify, and reassemble. It works on any classfile, but it requires you to understand bytecode, which I highly doubt the OP does.Homologize
:-O. Now I understand. I was not stating options, but steps in a process. I was suggesting Breed to follow these steps to modify the java class.Mike
@izaera, I did it. My new .class file is shown properly. My edit is saved. But I have a problem. I get same error and when I clicked the error link I get this warning "Source not found for org.hibernate.id.IdGeneratorFactory" I can see .class file but it is not shown runtime.Chemmy
L
16

Use a bytecode editor, like:

http://set.ee/jbe/

Be careful because you need a very good knowledge of the Java bytecode.

You can also change the class at runtime with bytecode weaving (like AspectJ).

Liquescent answered 28/12, 2012 at 11:51 Comment(3)
Thanks for reply but i have no knowledge about java bytecode.Chemmy
I don't think you can change any class in runtime with reflection. You need a library to create classes on the fly to do something similar.Mike
Sometimes changing java bytecode is easier than getting dependencies right... Especially if you just have to make some minor changes. JBE threw errors in my case but Recaf worked perfectly.Phrasal
N
6

Recaf is a decompiler GUI that allows you to edit and recompile files. Here is the relevant portion of the manual:

The easiest way to edit bytecode is to edit it as decompiled source. This does not work for highly complex cases and obfuscation, but for most simple edits its all you’ll ever need to do. Simply open the class, make your changes as plain Java code, and save.

Nerve answered 1/12, 2021 at 4:45 Comment(2)
Very useful and up do date answer! ThanksGladiate
And in case the decompiled code isn't recompilable, there is the primary editing function, the assembler: coley.software/Recaf-documentation/use-edit-via-bytecode.htmlPrimulaceous
H
3

I added some codes and save .class file.

What you see in JD EClipse Decompiler is decompiled representation of byte code in the .class file. Even though you change the text it won't affect the byte code.

Hade answered 28/12, 2012 at 11:52 Comment(3)
That is the my problem. I changed but not effect.Chemmy
@BreedHansen, why not to generate String instead of BigDecimal? So the answer to your question is: it is almost impossible. Or you have to extract the source code to eclipse and try to generate another class file with your modifications.Hade
Thanks for detail reply. I want to do this. Is it really impossible? forum.hibernate.org/viewtopic.php?t=964410Chemmy
B
2

when you decompile and change the code you have to go on the root folder of your eclipse project and check your class in bin folder wich is on the same level as src. then open you original jar with zip tool ( 7zip is good for that ) and put the modified class in tha same package inside the jar.

Blouse answered 7/6, 2013 at 13:14 Comment(0)
A
2

You can use any decompiler to first decompile the file.

I had once faced a simillar problem where I didn't have source code of the application and had to make a very small change in a file.

Below is what I did:

  1. Extracted the class file from the jar

  2. Opened it in a decompiler (I use JD GUI, you can get it easily from many resources on internet) You may download it from here

  3. You can actually view all the files in a jar using JD GUI.

  4. Made changes to the file I wanted to and copied all the code from that file
  5. Created a new project in eclipse with only this class (with the same package structure as in the jar), provided the original jar as library and all other dependencies.
  6. Compiled the class, injected the .class file back to the jar from bin folder of my workspace
  7. Tested my change, celebrated it by sipping a cup of coffee :)
Ambivalence answered 8/6, 2017 at 8:56 Comment(0)
E
1

Use java assist Java library for manipulating the Java bytecode (.class file) of an application.

-> Spring , Hibernate , EJB using this for proxy implementation

-> we can bytecode manipulation to do some program analysis

-> we can use Javassist to implement a transparent cache for method return values, by intercepting all method invocations and only delegating to the super implementation on the first invocation.

Exultant answered 17/3, 2017 at 6:38 Comment(0)
S
0

You can change the code when you decompiled it, but it has to be recompiled to a class file, the decompiler outputs java code, this has to be recompiled with the same classpath as the original jar/class file

Sancha answered 28/12, 2012 at 11:51 Comment(3)
Thanks, I understood the idea. But i don't know how i do this?Chemmy
pull the decompiled code into eclipse, resolve dependencies, fix errors, and recompile with eclipse. put the resulting class file into the old jar. alternatively obtain original source code.Sancha
I can reach .class file's .java file only in Eclipse. So, i don't understood how "class file into the old jar"?Chemmy
C
0

Sometime we need to compile one single file out of thousand files to fix the problem. In such a case, One can create same folder structure like class path, decompile the file into java or copy java file from source code. Make required changes, compile one particular file into class with all dependency/classes in place and finally replace the class file. Finally restart the container. Once war is exploded file will not be replaced.

Crabbed answered 23/8, 2017 at 5:28 Comment(0)
P
-1

As far as I've been able to find out, there is no simple way to do it. The easiest way is to not actually convert the class file into an executable, but to wrap an executable launcher around the class file. That is, create an executable file (perhaps an OS-based, executable scripting file) which simply invokes the Java class through the command line.

If you want to actually have a program that does it, you should look into some of the automated installers out there.

Here is a way I've found:

[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]`
Privy answered 29/6, 2014 at 22:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.