Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 30 additions & 21 deletions src/main/java/com/appland/appmap/output/v1/CodeObject.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
package com.appland.appmap.output.v1;

import com.alibaba.fastjson.annotation.JSONField;

import com.appland.appmap.util.Logger;

import javassist.CtBehavior;
import javassist.CtClass;
import javassist.bytecode.SourceFileAttribute;

import java.lang.reflect.Modifier;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Collections;
import java.util.*;
import java.util.regex.Matcher;

/**
* Represents a package, class or method.
Expand Down Expand Up @@ -79,7 +75,7 @@ public CodeObject setLocation(String location) {
public List<CodeObject> getChildren() {
return this.children;
}

/**
* Return the list of children, or an empty list if there are
* none. {@code getChildren} behaves differently to satisfy
Expand All @@ -100,15 +96,15 @@ private CodeObject setFile(String file) {
this.file = file;
return this;
}

@JSONField(serialize = false, deserialize = false)
private Integer lineno;
private CodeObject setLineno(Integer lineno) {
this.lineno = lineno;
return this;
}


@Override
public boolean equals(Object obj) {
if (obj == null) {
Expand All @@ -129,7 +125,7 @@ public boolean equals(Object obj) {
&& codeObject.isStatic == this.isStatic
&& (codeObject.file == null? this.file == null : codeObject.file.equals(this.file))
&& codeObject.lineno == this.lineno;

}

/**
Expand Down Expand Up @@ -194,12 +190,25 @@ public CodeObject(CodeObject src) {
* @return An estimated source file path
*/
public static String getSourceFilePath(CtClass classType) {
String[] parts = {
"src", "main", "java",
classType.getPackageName().replace('.', '/'),
classType.getClassFile().getSourceFile()
};
return String.join("/", parts);
String sourceFilePath = null;
if (classType.getClassFile2().getAttribute("SourceFile") != null) {
sourceFilePath = getSourceFilePathWithDebugInfo(classType);
} else {
sourceFilePath = getSourceCodePath(classType);
}
return sourceFilePath;
}

private static String getSourceFilePathWithDebugInfo(CtClass classType) {
return classType.getName().substring(0, classType.getName().lastIndexOf("."))
.replaceAll("\\.", Matcher.quoteReplacement("/"))
+ "/" + ((SourceFileAttribute) classType.getClassFile2()
.getAttribute("SourceFile")).getFileName();
}

private static String getSourceCodePath(CtClass classType) {
return classType.getName().replaceAll("\\.", Matcher.quoteReplacement("/"))
.replaceAll("\\$\\w+", "") + ".java";
}

/**
Expand Down Expand Up @@ -321,7 +330,7 @@ public CodeObject get(String path) {
public CodeObject findChild(String name, Boolean isStatic, int lineNumber) {
for (CodeObject child : this.safeGetChildren()) {
if (child.name.equals(name)
&& child.isStatic == isStatic
&& child.isStatic == isStatic
&& child.lineno == lineNumber) {
return child;
}
Expand Down Expand Up @@ -357,7 +366,7 @@ private boolean equalBySubstring(String s1, String s2, int start, int end) {

return true;
}

public CodeObject findChildBySubstring(String name, int start, int end) {
for (CodeObject child : this.safeGetChildren()) {
if (equalBySubstring(child.name, name, start, end)) {
Expand All @@ -367,7 +376,7 @@ public CodeObject findChildBySubstring(String name, int start, int end) {

return null;
}

/**
* Add an immediate child to this CodeObject.
* @param child The child to be added
Expand Down
31 changes: 31 additions & 0 deletions src/test/java/com/appland/appmap/output/v1/CodeObjectTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.appland.appmap.output.v1;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.NotFoundException;
import org.junit.Test;

import static org.junit.Assert.*;

public class CodeObjectTest {

@Test
public void getSourceFilePath_for_RegularClass() throws NotFoundException {
CtClass testCtClass = ClassPool.getDefault().get("com.appland.appmap.ExampleClass");
assertEquals("com/appland/appmap/ExampleClass.java", CodeObject.getSourceFilePath(testCtClass));
}
Comment on lines +12 to +16
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems unlikely, but is there any way of us capturing the source path relative to the project root? If we wanted to open this file, we'd need to know if it was located in src/java/test or src/java/main. We could choose a file with the best partial match but without the full relative path we'll always have edge cases.

🤔


@Test
public void getSourceFilePath_for_InnerClass_ResultInBaseClass() throws NotFoundException {
CtClass testCtClass = ClassPool.getDefault().get("com.appland.appmap.output.v1.testclasses.ExampleInnerClass$StaticFinalInnerClass");
assertEquals("com/appland/appmap/output/v1/testclasses/ExampleInnerClass.java", CodeObject.getSourceFilePath(testCtClass));
}

@Test
public void getSourceFilePath_for_AnonymousClass_ResultInBaseClass() throws NotFoundException {
CtClass testCtClass = ClassPool.getDefault().get("com.appland.appmap.output.v1.testclasses.Anonymous$1");
assertEquals("com/appland/appmap/output/v1/testclasses/Anonymous.java", CodeObject.getSourceFilePath(testCtClass));
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.appland.appmap.output.v1.testclasses;

public class Anonymous {

public static Runnable getAnonymousImpl(){
return new Runnable() {
@Override
public void run() {
System.err.println("Hello Anonymous!");
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.appland.appmap.output.v1.testclasses;

import com.appland.appmap.ExampleClass;

public class ExampleInnerClass extends ExampleClass {

private static final class StaticFinalInnerClass {

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public void testBuild() throws Exception {
Method myMethod = testClass.getMethod("myMethod");

myMethod.invoke(obj);
assertEquals(myMethodMessage + "\n", systemOutRule.getLog());
assertEquals(myMethodMessage + System.getProperty("line.separator"), systemOutRule.getLog());
}

@Test
Expand All @@ -52,7 +52,7 @@ public void testMultiParameter() throws Exception {
double y = 12.0;

myMethod.invoke(obj, x, y);
assertEquals(x + " " + y + "\n", systemOutRule.getLog());
assertEquals(x + " " + y + System.getProperty("line.separator"), systemOutRule.getLog());
assertEquals(2, myMethod.getParameterCount());

assertArrayEquals(new Class<?>[]{ int.class, double.class }, myMethod.getParameterTypes());
Expand Down