Link to home
Start Free TrialLog in
Avatar of IW-SNK
IW-SNKFlag for United Kingdom of Great Britain and Northern Ireland

asked on

Edit java class file : decompile and recompile without reopening full application

Hello Everyone,

We have a java application which needs to be amended to update an FTP password within a class file.

I have inherited this application from a developer who is no longer with us, we have no documentation and do not have access to the original source files. Is it possible to recompile an individual application class file without opening the whole project in eclipse?

This is the decompiled class file:
package com.abc.ftp;

import java.io.IOException;
import java.io.InputStream;
import java.net.SocketException;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;

public class FtpSender
{

    private static final String HOSTNAME = "xxx.xxx.xxx.xxx";
    private static final String USERNAME = "username";
    private static final String PASSWORD = "password";
    private FTPClient client;

    public FtpSender()
        throws SocketException, IOException
    {
        client = new FTPClient();
        client.connect("xxx.xxx.xxx.xxx");
        if(!FTPReply.isPositiveCompletion(client.getReplyCode()))
        {
            throw new IOException("Unable to connect to ftp server : xxx.xxx.xxx.xxx");
        }
        client.login("username", "password");
        if(!FTPReply.isPositiveCompletion(client.getReplyCode()))
        {
            throw new IOException("Unable to login as username to ftp server : xxx.xxx.xxx.xxx");
        } else
        {
            return;
        }
    }

    public void send(InputStream in, String desiredPath)
        throws IOException
    {
        client.storeFile(desiredPath, in);
        if(!FTPReply.isPositiveCompletion(client.getReplyCode()))
        {
            throw new IOException((new StringBuilder("Unable to store file at : ")).append(desiredPath).toString());
        } else
        {
            return;
        }
    }
}

Open in new window


Many thanks in advance,
Ian.
Avatar of CEHJ
CEHJ
Flag of United Kingdom of Great Britain and Northern Ireland image

Looks like you've been lucky there. Try compiling it standalone. Take a backup of the jar file or directory in which that class appears, then either update the jar or overwrite the class file depending on whether the class is in a jar or a directory
Avatar of IW-SNK

ASKER

Hi Cehj,

Thanks for your comment. The class file is located in a subdirectory of the .jar file.

Apologies if this is a really basic question, I'm not a java developer! but how do I compile the revised text file as a class file?

I initially decomplied with Cavaj to ensure the FtpSender.class file was the one that contained the FTP password.

In eclipse I can open the text version but I am unable to compile, how would I do this? Do I need to create a project first?

If I try to open the .class compiled file in eclipse I receive the following error:
Could not open the editor:
The Class File Viewer cannot handle the given input ('org.eclipse.ui.ide.FileStoreEditorInput').

Many thanks,
Ian.
ASKER CERTIFIED SOLUTION
Avatar of CEHJ
CEHJ
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Sorry - you said not

Have you got a JDK installed on your system? If so, you can use javac

If not, start a separate, new, Eclipse project and add that source to your project. Add the necessary jars (Apache Commons Net etc) and let the source compile. Copy the resulting class file into the old project (which should have been backed up first)
Or you can bypass Eclipse and compile your decompiled .java file with the different password (is that what you want to do?), then replace the previous .class file in the .jar file with your new .class file.
Avatar of IW-SNK

ASKER

I'm going to attempt to compile without using eclipse, using javac.
Does it matter which version of the SDK I install? Does it need to be the same version used for the original application?

It's better to get the same SDK, but it might not matter.  It depends on the method signatures.  Don't you have javac on the machine with the jars?  If you don't, then you do have a jre -- get the sdk which matches it.
Avatar of IW-SNK

ASKER

Thanks for the info MrCoffee365.
I'll update the thread once i have installed and compiled the class.
Cheers,
Ian.
Avatar of IW-SNK

ASKER

I have installed the JDK and registered the PATH variables.

I ran the following from the command prompt with this result:

C:\java_app_path>javac FtpSender.class
javac: invalid flag: FtpSender.class
Usage: javac <options> <source files>
use -help for a list of possible options

Open in new window


Something is wrong somewhere.

I then changed the file from .class to .java and the following errors appeared:
FtpSender.java:6: package org.apache.commons.n
import org.apache.commons.net.ftp.FTPClient;

Open in new window


I am now going to try via eclipse, that way I can load the packages.

Many thanks,
Ian.
Is that the real package name? If not, give me the real package name and i'll supply you with the files you need
The design of that class is poor:

a. there are hardcoded credentials in it - hence your current problem
b. the ftp connection isn't closed properly (i wonder if it even works?)

The following (assuming it DOES work) is about the minimum required to get it to work with arbitrary credentials without recompilation:
package com.abc.ftp;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;

import java.io.IOException;
import java.io.InputStream;

import java.net.SocketException;


public class FtpSender {
    private static final String HOSTNAME;
    private static final String USERNAME;
    private static final String PASSWORD;
    private FTPClient client;
    static {
	java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("credentials");
	HOSTNAME = bundle.getString("hostname");
	USERNAME = bundle.getString("username");
	PASSWORD = bundle.getString("password");
    }


    public FtpSender() throws SocketException, IOException {

        client = new FTPClient();

        client.connect(HOSTNAME);

        if (!FTPReply.isPositiveCompletion(client.getReplyCode())) {
            throw new IOException(
                "Unable to connect to ftp server : " + HOSTNAME);
        }

        client.login(USERNAME, PASSWORD);

        if (!FTPReply.isPositiveCompletion(client.getReplyCode())) {
            throw new IOException(
                "Unable to login as username to ftp server : " + HOSTNAME);
        } else {
            return;
        }
    }

    public void send(InputStream in, String desiredPath)
        throws IOException {
        client.storeFile(desiredPath, in);

        if (!FTPReply.isPositiveCompletion(client.getReplyCode())) {
            throw new IOException((new StringBuilder(
                    "Unable to store file at : ")).append(desiredPath).toString());
        } else {
            return;
        }
    }
}

Open in new window

Or you can just add the jars to your classpath when you compile the .java file.

So: you compile .java files, you run .class files.  

Run these commands to compile your .java file.  Then you'll need to replace the .class file in the jar.

set CLASSPATH=.;comabc.jar
javac C:/java_app_path/FtpSender.java

Then you'll need to replace the .class file in comabc.jar (I don't know the name of the .jar file these are in -- you'll have to put the right name in):

jar uf comabc.jar com\abc\ftp\FtpSender.class
Avatar of IW-SNK

ASKER

Thanks so much for your support with this issue. Unfortunately my lack of experience/understanding of java has made this a difficult task.

I followed Cehj's approach with the revised file - updating teh .class file with the new code and saving as a text file with the .class extension. I then ran the application with the uncompiled .class but this did not produce the desired effect. The application generated an error which was not the error text as created in the new file. This makes me think that the application does not store the FTP details in this class file but perhaps somewhere else in the application.

I am going to reach out to the original developer in the hope that he can point me in the direction of the original eclipse project.

Thanks again for your support with this issue.
Ian.
Avatar of IW-SNK

ASKER

Hi Cehj,

Just for clarrification, when you wrote:
The following (assuming it DOES work) is about the minimum required to get it to work with arbitrary credentials without recompilation:

Does this means that a .class file can be used / accessed by the jar application without recompilation?

ie. decomplie, edit, save as uncompiled file with same name and the app can use it.

Many thanks,
Ian.
Avatar of gordon_vt02
gordon_vt02

IW, when you decompile the source, save it as a .java file instead of a .class file and make sure you put it in the same directory structure you found it in in the jar.  The javac compiler (or Eclipse, if you go that route) will create the .class file for you.
>>Does this means that a .class file can be used / accessed by the jar application without recompilation?

No -- we mentioned this before.  A .java file is source code -- it cannot be run or executed by anything.  A .class file is the compiled code -- that is what is run.

CEHJ was suggesting you rewrite the code to behave differently.
Avatar of IW-SNK

ASKER

Hi Mrcoffee365,
Thanks for the clarrification, I thought that was the case.
Cheers,
Ian.
Avatar of IW-SNK

ASKER

Thanks for the great feedback on this issue. In the end I had to locate the original source files and the amend to the was very easy.
Cheers,
Ian.
Avatar of IW-SNK

ASKER

My initial question was not answered, recompile .class without eclipse. The solution was to use eclipse so this was the best match comment.
Too bad you didn't follow up with all the experts.  I was answering directly how to recompile a .java file into a .class file without using eclipse.   If you use EE again, try to work with the experts on the problem you want to solve.
And i'd strongly advise  you to use the code i gave you or something like it or you could well have a similar problem again
Avatar of IW-SNK

ASKER

Thanks for the feedback, I will take this onboard.