Get a jar file from a path, and change its classes names - java

So I need to make a java console app that gets a jar file path and prints all the classes names to the console.
Then I want it to change all of the classes names to 3 random letters from the abc "ABC" (for example) and then I need it to create a new jar file with the same code in the classes but with the new classes names.
Now my idea for storing the classes code
ArrayList> that way each index will represent a class and each index of the ArrayList would represent a line in that class
also maybe will not need a decompiler if you can get the bytecode and just transfer it to the new file were creating
Now I don't really have much experience working with files like that in Java and in C# I have worked with files some times but not in that level, but I would be happy to learn, I also understand that it may be problematic to just create a new jar with the code of the old one
I hope there is a short efficient way to do what I need here
Also, I don't need this to be a big project right now and that's why I do everything in one class
here is what I got right now
private static ArrayList<String> usedNames;
private static final String letters = "abcdefghijklmnopqrstuvwxyz";
private static Random rnd;
public static void main(String args[]) throws Exception
{
usedNames = new ArrayList<String>();
usedNames.add("");
rnd = new Random();
// reading
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
System.out.println("Enter a jar path: ");
String inputPath = reader.readLine();
System.out.println("Enter a output path: ");
String outputPath = reader.readLine();
// getting all class names from jar
List<String> classNames = new ArrayList<String>();
ZipInputStream zip = new ZipInputStream(new FileInputStream(inputPath + ".jar"));
for (ZipEntry entry = zip.getNextEntry(); entry != null; entry = zip.getNextEntry()) {
if (!entry.isDirectory() && entry.getName().endsWith(".class")) {
// This ZipEntry represents a class. Now, what class does it represent?
String className = entry.getName().replace('/', '.'); // including ".class"
classNames.add(className.substring(0, className.length() - ".class".length()));
}
}
// print all classes names
for (String s : classNames)
System.out.println(s);
// getting the code of each class to some sort of data structure
// changing classes names to random letters
// creating a new jar file with the classes in location outputPath
}
private static String getRandomClassName() {
String str = "";
while (usedNames.contains(str)) {
for (int i = 0; i < 3; i++)
str += letters.charAt(rnd.nextInt(27));
}
usedNames.add(str);
return str;
}

Related

Recursion Java vs Python

last week i made this java file wondering to search in my pc files which contains certain words i input.
After to have done it i thought "why not translating it in python?" and in python i have seen that it runs out of memory (because of the recursion), but in java didn't (in python the code works if i dont give a lot of dirs and files), i put here the 2 codes and the error (java vs python) so u can help me(sorry for my english i am not mother tongue).
JAVA:
package com.company;
import java.io.*;
import java.util.ArrayList;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
System.out.println("Input path to start(remember the / at the end):");
Scanner input = new Scanner(System.in);
String path=input.nextLine();
ArrayList<String> words= new ArrayList<>();
String word="";
while(!word.equals("//quit")){
System.out.println("Input word to search (input://quit to stop):");
word=input.nextLine();
if(!word.equals("//quit"))
words.add(word);
}
Finder finder= new Finder(path,castToArray(words));
finder.readFile();
}
private static void readFiles(Finder finder){
String[] files = finder.printFiles();
for(int i=0; i< files.length;i++){
System.out.println(files[i]);
}
}
private static String[] castToArray(ArrayList<String> words){
String[] w0rds = new String[words.size()];
for(int i=0; i< words.size(); i++){
w0rds[i]= words.get(i);
}
return w0rds;
}
}
class Finder {
private String[] words;
private File file;
private String path;
Finder(String path,String... words){
this.words=words;
this.path=path;
file= new File(path);
}
public String[] printFiles(){
String[] files;
files=file.list();
return files;
}
public void readFile(){
String[] files= printFiles();
for(int i=0; i< files.length;i++){
File f = new File(file.getPath()+"/"+files[i]);
if(!f.isDirectory()){
searchWord(f,words);
}else {
Finder finder = new Finder(path+f.getName()+"/",words);
finder.readFile();
}
}
}
public File getFile() {
return file;
}
public void searchWord(File file,String... words){
DataInputStream dis = null;
try {
dis = new DataInputStream(new FileInputStream(file));
byte[] bytes = new byte[512];
dis.readFully(bytes);
String obj = new String(bytes);
for(int i=0; i< words.length;i++){
if(obj.contains(words[i])){
System.out.println(file.getName());
break;
}
}
} catch (FileNotFoundException e) {
} catch (IOException e) {
}
}
}
PYTHON:
import os
class Finder:
path = ""
words= []
def readFile(self,path,words):
new_file = open(path, "r")
data=new_file.read(8192)
new_file.close()
for word in words:
if(data.find(word,0,len(data))!=-1):
print "name: "+new_file.name+" path: "+path
break
def __init__(self,path, words):
self.path=path
self.words=words
def __del__(self):
files=os.listdir(path)
for file in files:
if(os.path.isdir(path+file)!=True):
self.readFile(path+file,words)
else:
dirpath = path+file+"/"
finder = Finder(path,words)
path= raw_input("input path to start(remember the / at the end):\n")
words=[]
word = ""
while word != "//quit":
word=raw_input("input word to search (write //quit to start searching):\n")
if word != "//quit":
words.append(word);
print "start searching for "+str(words)+"..."
finder = Finder(path,words)
PYTHON ERROR:
Exception RuntimeError: 'maximum recursion depth exceeded' in <bound method Finder.__del__ of <__main__.Finder instance at 0x7f5c0b4f4d40>> ignored
Exception RuntimeError: 'maximum recursion depth exceeded' in <bound method Finder.__del__ of <__main__.Finder instance at 0x7f5c0b4f4c68>> ignored
Exception RuntimeError: 'maximum recursion depth exceeded' in <bound method Finder.__del__ of <__main__.Finder instance at 0x7f5c0b4f4d40>> ignored
Exception RuntimeError: 'maximum recursion depth exceeded' in <bound method Finder.__del__ of <__main__.Finder instance at 0x7f5c0b4f4c68>> ignored
In python, you rarely should use the __del__ method. It is a special magic method that is called at an arbitrary time (when the object is garbage-collected) with very few applications and multiple caveats. Instead, for most use cases, you should use a .close() method you call explicitly or with a context manager like contextlib.closing.
That said, I don't know why you made a __del__ method at all since in your java code there is nothing like that. Closest java thing would be a finalize method, but you're not using it, so why did you chose to use __del__ in your translation?
Anyway, in python you can use os.walk() instead of os.listdir() to traverse your directory tree - os.walk() is iteratively recursive so it can handle any path depth without running out of call stack space:
for pth, dirs, files in os.walk(path):
for filename in files:
self.readFile(os.path.join(pth, filename))
This code snippet will call readFile with all files in all subfolders.
The problem in your python code is, that you use the global path variable in __del__ instead of self.path. Therefore you get an infinite recursion.
Better convert your class into functions:
import os
def readFile(path, words):
with open(path, "r") as new_file:
data = new_file.read(8192)
for word in words:
if word in data:
print "name: {} path: {}".format(new_file.name, path)
break
def search(path, words):
files = os.listdir(path)
for filename in files:
fullname = os.path.join(path, filename)
if not os.path.isdir(fullname):
readFile(fullname, words)
else:
search(fullname, words)
path = raw_input("input path to start: ")
words = []
while True:
word = raw_input("input word to search (write //quit to start searching): ")
if word == "//quit":
break
words.append(word)
print "start searching for {}...".format(', '.join(words))
search(path, words)

Reading multiple text files java

I'm having trouble on reading multiple text files to fit into one scanner for example I have multiple text files that are named text1.txt, text2.txt etc... I'm trying to make it so that once the user enters which text file number they want it will bring up that data via arrays.
File txt = new File("text.txt");
void readTextFiles() throws IOException {
String line[] = new String[100];
Scanner readTextFiles= new Scanner(txt);
while (readTextFiles.hasNextLine()) {
line[q] = readTextFiles.nextLine();
if (line[q].trim() != "") {
String item[] = line[i].split(" ");
time[q] = item[0];
date[q] = item[1];
}
q++;
}
readTextFiles.close();
}
my logic works like this but its a code error:
File txt= new File("txt" + textFileNumber + ".txt");
int textFileNumber=0;`
If I understood correctly, the error you got is because the initialisation of the local variable does not precede it's use. You need to declare the textFileNumber before its usage in the string concatenation.
Further you are implementing this functionality as a method. So why not make the file number a method parameter?
public void readTextFiles(int fileNumber){
File txtFile = new File("text" + fileNumber + ".txt");
//logic
}

search a column word in csv file and replace it by another value java

I have two csv file, main and look.
main file contains a list of word like this:
a,c,e,f
b,d,o,f
and look.csv contain two rows like this:
a,f,j
1,0,1
I want to search for each word of main.csv and find a match in look.csv. if there was a match, i replace word in main.csv by a value that is in the row 2 from look.csv
i write this code
public class lookup {
public static void main(String args[]) throws FileNotFoundException
{
String word;
Scanner main = new Scanner(new File("C:\\Users\\sa\\Desktop\\hotel2\\all.csv"));
main.useDelimiter(",");
Scanner look=new Scanner (new File("C:\\Users\\sa\\Desktop\\comtedad.csv"));
while (main.hasNext())
{
word=main.next() ;
while (look.hasNext()){
if (main.next().equals(look.next())) {//code for replacing}
}
}
main.close();
}}
how can i access to second row of look.scv when two entry were matched?
A few things to note before posting my solution:
there is no easy way to replace the contents of a file while reading it, you have to create a new one and output what you need there
if you want to replace values, then this is good place use a Map
your code implies that the look.csv file contains only 2 lines
The following would achieve what you are looking for, but again, the output is in a different file (you can rename afterwards if you wish to do so) :
public class Main {
public static void main(String[] args) throws Exception {
//1. create Scanners that will look through the CSV files
Scanner main = new Scanner(new File("main.csv"));
Scanner look = new Scanner(new File("look.csv"));
//2. create the final CSV file that will contain both the replaced words and non-replaced words from main.csv
FileWriter replaced = new FileWriter(createReplacedCsv());
//3. store contents of look.csv in a Map
Map<String, String> lookCsvWords = storeLookCsvInSet(look);
//4. Store the contents of the file in a StringBuilder, so you can use the StringBuilder.deleteCharAt(int)
// and .lastIndexOf(String) to delete the last comma
StringBuilder builder = new StringBuilder();
//5. keep track of the line we are on
int line = 0;
//6. iterate through main.csv and search for replaceable words, and write them to replaced.csv if they are found
while (main.hasNext()) {
//search the first line for replaceable chars
String[] wordsInLine = main.nextLine().split(",");
for (String word : wordsInLine) {
if (lookCsvWords.containsKey(word) && line == 0) {
word = lookCsvWords.get(word);
}
builder.append(word).append(",");
}
line ++;
builder.deleteCharAt(builder.lastIndexOf(","));
builder.append("\n");
}
//7. write the contents of the StringBuilder to the file
replaced.write(builder.toString());
replaced.close();
}
/*
* Creates the replaced.csv file if it doesn't exist
*/
private static File createReplacedCsv() throws Exception {
File replacedCsv = new File("replaced.csv");
replacedCsv.createNewFile();
return replacedCsv;
}
/*
* Store the words within look.csv in a Map.
* This method assumes that look.csv has only two lines
*/
private static Map<String, String> storeLookCsvInSet(Scanner lookScanner) throws Exception {
Map<String, String> lookCsvWordMappings = new HashMap<String, String>();
String[] line1Values = lookScanner.nextLine().split(",");
String[] line2Values = lookScanner.nextLine().split(",");
for (int i=0; i<line1Values.length; i++) {
lookCsvWordMappings.put(line1Values[i], line2Values[i]);
}
return lookCsvWordMappings;
}
}
Try first to load look.csv in a Mapping data structure like Map<String,String> like this :
Map<String,String> mapping=new HashMap<String,String>()
Scanner look=new Scanner (new File("C:\\Users\\sa\\Desktop\\look.csv"));
String[] keys=look.nextLine().split(",");
String[] values=look.nextLine().split(",");
for(int i=0;i<keys.length;++i)
mapping.put(keys[i],values[i]);
then write a new file while reading the main file like this ;
Scanner main = new Scanner(new File("C:\\Users\\sa\\Desktop\\hotel2\\all.csv"));
PrintWriter mainOutput = new PrintWriter (new File("C:\\Users\\sa\\Desktop\\hotel2\\all.out.csv"));
while (main.hasNext()){
String[] nextTokens=main.nextLine().split(",");
for(String token:nextTokens)
if(mapping.get(token)!=null)
{
mainOutput .print(mapping.get(token)+",");
}else {
mainOutput .print(token+",");
}
mainOutput .println();
}
mainOutput .close();

JAVA - How to create an array of objects?

I need to read a CSV file into an array of Objects.
I didn't realise that it had to go into one, and just made an ArrayList instead. I now need to fix that, and have no idea what I'm doing.
This is my code to read the CSV file into a multidimensional array.
public static void readClub() throws IOException {
BufferedReader clubBR = new BufferedReader(new FileReader(new File("nrlclubs.txt")));
String line = "";
ArrayList<String[]> clubsArr = new ArrayList<String[]>();
while ((line = clubBR.readLine()) != null) {
String[] club = new String[3];
for (int i = 0; i < 3; i++) {
String[] value = line.split(",", 3);
club[i] = value[i];
}
clubsArr.add(club);
}
A snippet of my CSV file is this:
Glebe,G Shield,Glebe District
Cumberland,C Shield,Central Cumberland
Annandale,A Shield,Annandale District
University,Lion,Sydney Uni Rugby League Club
Souths,Rabbit,South Sydney,Rabbitohs
Easts,Rooster,Eastern Suburbs,Roosters,Sydney Roosters
Balmain,Tiger,Tigers,Balmain Tigers
Newtown,Jets,Jets,Newtown Jets,Bluebags
The first word is the Team name, the second word is the Team mascot, and the rest are the alias's.
Now the question is, how do i do the same thing, but with an Array of Objects (in a class called Clubs)?
I just spent a few hours trying to get this working, only to be told its wrong, and the Array of Objects is doing my head in :'(
Thanks heaps!
edit:
ok, the actual question is this:
the program should read the content of the data file (NRLclubs.txt) into memory into an appropriate array of objects (see previous page for descriptions of the class). Do not assume that the file exists.
The description of the class is this:
Club class: the Club class represents an individual NRL club within the competition. The Club class needs to store data for the current club name, current club mascot, any aliases by which the club is or has been known. As well as the normal methods that should be created for a class (eg, constructors, ‘setters’, and ‘getters’) you will need to decide upon appropriate methods for this class based upon the general requirements of the assignment specification.
Create a new Class that will hold the data of a row.
In the easiest case you could create a class like this:
class MyClass {
public String column1;
public String column2;
public ArrayList<String> aliases = new ArrayList<String>();
public void addAliases(String[] a){
for(int i=2;i<a.length;i++){
aliases.add(a[i]);
}
}
}
Then change your ArrayList like so: ArrayList<MyClass> clubsArr = new ArrayList<MyClass>();
and your reading part like so:
while ((line = clubBR.readLine()) != null) {
MyClass club = new MyClass;
String[] value = line.split(",", 3);
club.column1 = value[0];
club.column2 = value[1];
// etc...
clubsArr.add(club);
}
MyClass[] clubs = clubsArr.toArray();
That way you will later be able to get a value from one of the objects by using its attributename (in this case for example .column2) instead of some index you would have to keep in mind.
Note that you can call the attributes in the class to your liking (e.g. clubname instead of column1)
EDIT (to help with OPs edit)
To check, if the file exists, replace the line
BufferedReader clubBR = new BufferedReader(new FileReader(new File("nrlclubs.txt")));
with
File file = new File("nrlclubs.txt");
if(!file.exists()){
System.exit(1); // no use to go any further if we have no input
}
BufferedReader clubBR = new BufferedReader(new FileReader(file));
I don't understand your question well but maybe you are looking for this:
public static void readClub() throws IOException {
BufferedReader clubBR = new BufferedReader(new FileReader(new File("nrlclubs.txt")));
String line = "";
ArrayList<Clubs> clubs = new ArrayList<Clubs>();
while ((line = clubBR.readLine()) != null) {
Clubs club = new Clubs();
String[] value = line.split(",", 3);
club.name = value[0];
club.mascot = value[1];
club.alias = value[2];
clubs.add(club);
}
}

Correct way of accessing a file with name

Ok I need someone to clear things up for me.
I saw a hundred different ways of accessing a file to read in it (FileReader).
I tried all of them and can't find a way to do it correctly.
If I try :
String path = Engine.class.getResource("Words.txt").toString();
or
URL url = getClass().getResource("Words.txt");
String path = url.getFile();
File myFile = new File(path);
I go directly to :
dispatchUncaughtException
I just don't know where to look anymore since no one seems to agree on the good way to do it. Also, what is that kind of exception ?There must be an easy way to do this since it is such an easy task. I just want my program to see my Words.txt file that is in the SRC folder of my project.
Full code if it helps :
public String GetWord()
{
String [] Words = new String [10];
int random = (int)(Math.random() * 10);
URL url = getClass().getResource("Words.txt");
String path = url.getFile();
File myFile = new File(path);
try
{
FileReader myReader = new FileReader(myFile);
BufferedReader textReader = new BufferedReader(myReader);
for(int i = 0; i < 10; i++)
{
Words[i] = textReader.readLine();
}
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
return Words[random];
}
String path = Engine.class.getResource("Words.txt").toString();
For that to work, your file has to be in the same package as the Engine class. So, you probably want to move your file to the package where the class is at.
If you want to move the file into some other package then you need to specify the location starting from the root of the classpath. e.g. /some/other/pkg/Words.txt.
For a file which is not in the classpath, you need the full path along with the file name, to be able to read the file. The SRC folder itself is not a package and not in the classpath.
In that case, you can do something as follows:
FileInputStream fis = new FileInputStream("C:\\path\\to\\file\\Words.txt");
BufferedReader br = new BufferedReader(new InputStreamReader(fis));
If you use Java 7 I recommend using newBufferedReader. It's more efficient and easier to use than the BufferedReader. I also modified your code to match the Java Code Conventions.
Working exmaple:
public String getWord() {
String[] words = new String[10];
int random = (int) (Math.random() * 10);
Path path = Paths.get("src" + System.getProperty("file.separator")
+ "Words.txt");
try {
BufferedReader textReader = Files.newBufferedReader(path,
StandardCharsets.UTF_8);
for (int i = 0; i < 10; i++) {
words[i] = textReader.readLine();
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
return words[random];
}

Categories

Resources