How to determine line number for the method with java ASM? - java

I need to determine line number of specific method in class using ObjectWeb ASM library. Line number of method declaration or first line in method's body are equally accepted as right answers (6 or 7 in example).
Example:
1. public class Foo {
...
6. public void bar() {
7. try {
8. try {
9. System.out.println(); //first executable line
I try to use MethodVisitor's visitLineNumber method, but it visit only first executable line (line 9 in example).
I found solution for this problem on JavaAssist library (link). But is there a way to solve this with ASM?
EDIT:
Following snippet gave same result, line 9 instead of 6 or 7.
public static int getLineNumber(String path) throws IOException {
final File f = new File(path);
try (FileInputStream fis = new FileInputStream(f)) {
ClassReader reader = new ClassReader(fis);
ClassNode clNode = new ClassNode(Opcodes.ASM5);
reader.accept(clNode, Opcodes.ASM5);
for (MethodNode mNode : (List<MethodNode>) clNode.methods) {
if (mNode.name.equals("bar")) {
ListIterator<AbstractInsnNode> it = mNode.instructions.iterator();
while (it.hasNext()) {
AbstractInsnNode inNode = it.next();
if (inNode instanceof LineNumberNode) {
return ((LineNumberNode) inNode).line;
}
}
}
}
}
return -1;
}

The line numbers provided by any bytecode processing library are based on the LineNumberTable attribute which maps executable instructions of the method to line numbers. So it’s a fundamental limitation that you can not find source code lines in the class file which do not cause the generation of executable byte code.
Sometimes it even depends on the compiler, which source code line a construct spanning multiple lines gets assigned to.

public static LineNumberNode findLineNumberForInstruction(InsnList
insnList, AbstractInsnNode insnNode) {
Validate.notNull(insnList);
Validate.notNull(insnNode);
int idx = insnList.indexOf(insnNode);
Validate.isTrue(idx != -1);
// Get index of labels and insnNode within method
ListIterator<AbstractInsnNode> insnIt = insnList.iterator(idx);
while (insnIt.hasPrevious()) {
AbstractInsnNode node = insnIt.previous();
if (node instanceof LineNumberNode) {
return (LineNumberNode) node;
}
}
return null;
}

Related

Is there any better file search algorithm than recursion?

I have used recursion to search for particular type of file (for example .pdf files is used here).
My recursion algorithm searches for all subfolder.
However I found that it lacks performance when there is too many sub-folder. sub-sub-folder, sub-sub-sub-folder.
I want to know if there is better algorithm for file searching.
Below is my recursion code for file searching. I have used .pdf file as an example
import java.io.File;
public class FInd {
public static void main(String[] args) {
File f = new File("D:/");
find(f);
}
public static void find(File f){
File []list = f.listFiles();
try{
for(int i=0;i<list.length && list.length>0;i++){
if(list[i].isFile() && (list[i].getName().contains(".pdf")) ||
list[i].getName().contains(".PDF"))
System.out.println(list[i].getAbsolutePath());
if(list[i].isDirectory()) find(list[i]);
}
}catch(Exception e){
}
}
}
This code is somewhat faster or equal to when compared to search option in file explorer. I want to know any faster algorithm than this
try the iterative way
public class Find {
public static void main(String[] args) {
File f = new File("D:/");
Stack stack = new Stack<File>();
stack.push(f);
while (!stack.empty())
{
f = (File) stack.pop();
File []list = f.listFiles();
try{
for(int i=0;i<list.length && list.length>0;i++){
if(list[i].isFile() && (list[i].getName().contains(".pdf")) ||
list[i].getName().contains(".PDF"))
System.out.println(list[i].getAbsolutePath());
if(list[i].isDirectory()) stack.push(list[i]);
}
}catch(Exception e){
}
}
the problem with threading is that launching them has a cost, so the increase in file browsing + recursion has to be better than the additional cost of N folders/threads.
This is a simple method that uses a loop (the classical replacement for recursion)
static boolean avoidRecursion(String target){
File currentDir = new File(System.getProperty("user.home"));
Stack<File> dirs = new Stack<File>();
dirs.push(currentDir);
do{
for(File f : dirs.pop().listFiles()){
if (f.isDirectory())
dirs.push(f);
else{
if (f.getName().equals(target))
return true;
}
}
}while(!dirs.isEmpty());
return false;
}
Measure both approaches and choose the option that is faster
Probaply you could use multithreading...
Each folder you enter, you start at new thread... Even if you have more threads than your CPU, it ist not a Problem since Windows Can run much more threads...
Use the Files.walk() method which returns a Java8 Stream. You can parallelize that calculation quite easily by using a parallel stream.
Use the following convenient idiom in a try with resources method:
try(Stream vals = Files.walk(rootPath)){
.... }
In the rootPath, you could use Paths.get("root location") to actually get to the root location.

Merge sort java.lang.StackOverflowError

I am working on a project for school and things are going well until i tried to perform a merge sort on my ArrayList.
It will run but then it errors out. The first error of many is Exception in thread "main" java.lang.StackOverflowError.
I have looked over the code and cant find out why the error is occurring.
It does give me a location ( line 74:first_half = mergeSort(first_half); ) but i don't see the issue.
public static void main(String[] args) throws IOException {
// URL url = new
// URL("https://www.cs.uoregon.edu/Classes/15F/cis212/assignments/phonebook.txt");
FileReader fileReader = new FileReader("TestSort.txt");
BufferedReader bufferReader = new BufferedReader(fileReader);
String entry = bufferReader.readLine();
// Scanner s = new Scanner(url.openStream());
// int count = 0;
while (entry != null) {
// String person = s.nextLine();
String phoneNum = entry.substring(0, 7);
String name = entry.substring(9);
PhonebookEntry newentry = new PhonebookEntry(name, phoneNum);
phoneBook.add(newentry);
entry = bufferReader.readLine();
}
// ********************Selection
// Sort*************************************
ArrayList<PhonebookEntry> sortList = new ArrayList<PhonebookEntry>(phoneBook);
for (int min = 0; min < sortList.size(); min++) {
for (int i = min; i < sortList.size(); i++) {
int res = sortList.get(min).getName().compareTo(sortList.get(i).getName());
if (res > 0) {
PhonebookEntry temp = sortList.get(i);
sortList.set(i, sortList.get(min));
sortList.set(min, temp);
}
}
}
for (PhonebookEntry sortentry : sortList) {
System.out.println(sortentry);
}
System.out.println(mergeSort(mergeSortList));
}
// *****************************merge sort******************************************
static int mergecounter = 0;
static ArrayList<PhonebookEntry> mergeSortList = new ArrayList<PhonebookEntry>(appMain.phoneBook);
public static ArrayList<PhonebookEntry> mergeSort(ArrayList<PhonebookEntry> mergeSortLists) {
if (mergeSortLists.size() == 1) {
return mergeSortLists;
}
int firstHalf = mergeSortLists.size() % 2 == 0 ? mergeSortLists.size() / 2 : mergeSortLists.size() / 2 + 1;
ArrayList<PhonebookEntry> first_half = new ArrayList<PhonebookEntry>(mergeSortLists.subList(0, firstHalf));
ArrayList<PhonebookEntry> mergeSortHalf2 = new ArrayList<PhonebookEntry>(
mergeSortLists.subList(first_half.size(), mergeSortLists.size()));
System.out.println(++mergecounter);
first_half = mergeSort(first_half);
mergeSortHalf2 = mergeSort(mergeSortHalf2);
return merge(first_half, mergeSortHalf2);
}
public static ArrayList<PhonebookEntry> merge(ArrayList<PhonebookEntry> first_half,
ArrayList<PhonebookEntry> mergeSortHalf2) {
ArrayList<PhonebookEntry> returnMerge = new ArrayList<PhonebookEntry>();
while (first_half.size() > 0 && mergeSortHalf2.size() > 0) {
if (first_half.get(0).getName().compareTo(mergeSortHalf2.get(0).getName()) > 0) {
returnMerge.add(mergeSortHalf2.get(0));
mergeSortHalf2.remove(0);
}
else {
returnMerge.add(first_half.get(0));
first_half.remove(first_half.get(0));
}
}
while (first_half.size() > 0) {
returnMerge.add(first_half.get(0));
first_half.remove(first_half.get(0));
}
while (mergeSortHalf2.size() > 0) {
returnMerge.add(mergeSortHalf2.get(0));
mergeSortHalf2.remove(mergeSortHalf2.get(0));
}
return returnMerge;
}
}
My opinion there is no error in code.
How so sure?
I ran you code in my environment and its executed without any error.
With the text file i found at https://www.cs.uoregon.edu/Classes/15F/cis212/assignments/phonebook.txt As input
and done a simple implementation for PhonebookEntry
Then why is this error?
First off all try to understand the error, I mean why StackOverflowError occur. As there are lots of I am not going to explain this
But please read the top answer of this two thread and i am sure you will know why this happen.
Thread 1: What is a StackOverflowError?
Thread 2: What actually causes a Stack Overflow error?
If you read those I hope you understand the summury is You Ran Out Of Memory.
Then why I didnt got that error: Possible reason is
In my environment I configured the jvm to run with a higher memory 1024m to 1556m (as eclipse parameter)
Now lets analyze your case with solution:
Input: you have big input here ( 50,000 )
To check you code try to shorten the input and test.
You have executed two algorithm in a sigle method over this big Input:
When a method execute all its varibles stay in the memory untill it complete its execution.
so when you are calling merge sort all previouly user vairables and others stay in the memory which can contribute to this situation
Now if you use separated method and call them from the main method like write an method for selection sort, all its used varible will go out of scope
and possibly be free (if GC collect them) after the selection sort is over.
So write two separated method for reading input file and selection sort.
And Please Please close() those FileReader and BufferedReader.
Get out of those static mehtod . Make them non static create and object of the class and call them from main method
So its all about code optimization
And also you can just increase the memory for jvm and test by doing like this java -Xmx1556m -Xms1024m when ruining the app in command line
BTW, Thanks for asking this this question its gives me something to think about

CharStack class works with javac but does not return anything in Eclipse console

I'm trying to modify the CharStack class (below) in Eclipse, but I'm unable to get it to do anything in the console when I run it, though it works fine when compiled with javac.exe
Is this something to do with carriage returns, perhaps? How do I signal to Eclipse that I'm ready for it to accept the input and return a result (the -1)?
The algorithm for the class is just:
while (there is a character to read)
push the character onto a stack;
while (there are characters on the stack)
pop off a character and print it;
The concept of a stack is a perfect candidate for becoming a class. It has a well-defined interface (push() and pop()) and some rules to enforce (you can only take data from the top, you can only remove as many elements as you insert). Here is a simple implementation of a stack that holds characters:
import java.io.*;
public class CharStack
{
private char[] m_data;
private int m_ptr;
public CharStack(int size)
{
m_ptr = 0;
m_data = new char[(size > 1 ? size : 10)];
}
public void push(char c)
{
if (m_ptr >= m_data.length)
{
// Grow the array automatically
char[] tmp =
new char[m_data.length * 2];
System.arraycopy(m_data, 0,
tmp, 0,
m_data.length);
m_data = tmp;
}
m_data[m_ptr++] = c;
}
public char pop()
{
return m_data[--m_ptr];
}
public boolean hasMoreElements()
{
return (m_ptr != 0);
}
public static void main(String[] argv)
throws IOException
{
CharStack s = new CharStack(10);
int i;
while ( (i = System.in.read()) != -1 )
{
s.push((char) i);
}
while (s.hasMoreElements())
{
System.out.write(s.pop());
}
System.out.println();
}
}
When I run this in Windows CLI I get:
C:\user>java CharStack
12345
54321
What you're looking for is the EOF character, represented OS-agnostically in this Java class.
In Windows that would be Ctrl-Z. Presumably this is implicit when you're on the Windows CLI version, but not so in Eclipse.

ArrayIndexOutOfBoundsException converting C# to Java

I'm working on a program that will go through a list of records (IDs and Tickets) and parse them into two list respectively. It will also cross search the lists to see which IDs have a corresponding ticket based on names. Here is a link to an earlier version: here
Now, I've been rewritting with the help of some C# code from a coworker, but I'm having trouble with a parsing method. Here is the C# version:
public void parseLine(string _line)
{
if(string.IsNullOrWhiteSpace(_line)){ return;}
code = _line.Substring(0, 3);
ticketID = _line.Substring(3, 10);
string tmp = _line.Substring(13).Trim();
//get the first and last name
string [] tmp1 = tmp.Split(",".ToCharArray());
if(!(tmp1.Length > 1))
{
throw new Exception("unable to get the first and last name");
}
lastname = tmp1[0];
firstname = tmp1[1].Trim();
}
Here is my Java version:
public void parseLine(String line) throws Exception {
// code will store Ticket code *Alpha ticketId will store 10
// *digit code
code = line.substring(0, 3);
ticketId = line.substring(3, 10);
// tmp will store everything afterthe first 13 characters of
// line and trim the name(s)
String tmp = line.substring(13).trim();
// tmp1 array
String[] tmp1 = tmp.split(".*,.*");
if (tmp1.length > 1) {
throw new Exception("UNABLE TO GET NAME");
}
last = tmp1[0];
first = tmp1[1].trim();
}
This is in a seperate class, that will model the people with tickets. My main class(so far) which invokes the actual parseLine method is as follows:
public class ParkingTickets {
public static void main(String[] args) throws
FileNotFoundException, Exception {
ArrayList<TicketPeople> tickets = new ArrayList<>();
HashMap<String, List<SbPeople>> people = new HashMap<>();
File srcFile = new File("source.txt");
Scanner myScanner = new Scanner(srcFile);
while (myScanner.hasNextLine()) {
String line = myScanner.nextLine();
//System.out.println(line);
if (line.matches("^\\p{Alpha}.*$")) {
//System.out.printf("Ticket: %s%n", line);
TicketPeople t = new TicketPeople();
t.parseLine(line);
tickets.add(t);
}
myScanner.close();
}
}
}
the compiler points at the if statement in the parseLine method, and obviously the parseLine method in main class, when I tried stepping through that sepcifiv line, I see that it's starts parsing the the data from the source file but something is off. From the documentation the error means: Thrown to indicate that an array has been accessed with an illegal index. The index is either negative or greater than or equal to the size of the array.
I used an ArrayList for the ticket list and from what I understand it is a dynamic list that does not need to be set with a specific index size. I'm still learning and am having trouble understanding this exception. I would greatly appreciate any help.
Your call to split() in Java, doesn't match the split() from C#.
// String[] tmp1 = tmp.split(".*,.*");
String[] tmp1 = tmp.split(","); // <-- ",".
also, your check logic seems to have been reversed. But, I would suggest
if (tmp1.length != 2) {
throw new Exception("UNABLE TO GET NAME");
}
1) In C# it is Substring(int startIndex, int length). In java String substring(int startindex, int endindex).
2)The java code has also changed the exception logic. In C# code ther eis a not if(!(tmp1.Length > 1)), whereas in java code, if (tmp1.length > 1)

How does this normalize function work?

I was doing a Junit tutorial and I came across this normalize function that was being tested. It was defined like this:
public static String normalizeWord(String word) {
try {
int i;
Class<?> normalizerClass = Class.forName("java.text.Normalizer");
Class<?> normalizerFormClass = null;
Class<?>[] nestedClasses = normalizerClass.getDeclaredClasses();
for (i = 0; i < nestedClasses.length; i++) {
Class<?> nestedClass = nestedClasses[i];
if (nestedClass.getName().equals("java.text.Normalizer$Form")) {
normalizerFormClass = nestedClass;
}
}
assert normalizerFormClass.isEnum();
Method methodNormalize = normalizerClass.getDeclaredMethod(
"normalize",
CharSequence.class,
normalizerFormClass);
Object nfcNormalization = null;
Object[] constants = normalizerFormClass.getEnumConstants();
for (i = 0; i < constants.length; i++) {
Object constant = constants[i];
if (constant.toString().equals("NFC")) {
nfcNormalization = constant;
}
}
return (String) methodNormalize.invoke(null, word, nfcNormalization);
} catch (Exception ex) {
return null;
}
}
How does this function work? What is it actually doing?
It does the same as:
import java.text.Normalizer;
try {
return Normalizer.normalize(word, Normalizer.Form.NFC);
} catch (Exception ex) {
return null;
}
Except that all operations are performed via Reflection.
It's using reflection to call
java.text.Normalizer.normalize(word, java.text.Normalizer.Form.NFC);
Presumably to allow it to run on Java versions before 1.6 which don't have this class.
This function offers services regarding strings normalization for Unicode.
In Unicode, you can represent the same thing in many ways. For example, you have a character with accent. You can represent it joined, using one single Unicode character, or decomposed (the original letter, without accents, then the modifier - the accent).
The class comes in Java 6. For Java 5, there's a SUN proprietary class.
See class info.olteanu.utils.TextNormalizer in Phramer project (http://sourceforge.net/projects/phramer/ , www.phramer.org ) for a way to get a normalizer both in Java 5 (SUN JDK) and in Java 6, without any compilation issues (the code will compile in any version >= 5 and the code will run in both JVMs, although SUN discarded the Java 5 proprietary class).

Categories