Skip to content

Commit 05c8466

Browse files
committed
documentation
1 parent 66ec435 commit 05c8466

File tree

6 files changed

+189
-14
lines changed

6 files changed

+189
-14
lines changed

README.md

+98-8
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,39 @@ Information about classes, hierarchies, annotations, methods, fields, and their
1818
- [Full api reference](../../wiki/Api-reference)
1919
- [3-address bytecode representation](../../wiki/Three-address-instruction-list-IR)
2020

21-
## Examples
21+
## Installation
22+
23+
Gradle:
24+
```kotlin
25+
implementation(group = "org.jacodb", name = "jacodb-api", version = "1.2.0")
26+
implementation(group = "org.jacodb", name = "jacodb-core", version = "1.2.0")
27+
implementation(group = "org.jacodb", name = "jacodb-analysis", version = "1.2.0")
28+
```
29+
30+
or
31+
32+
Maven:
33+
```xml
34+
<dependencies>
35+
<dependency>
36+
<groupId>org.jacodb</groupId>
37+
<artifactId>jacodb-core</artifactId>
38+
<verison>1.2.0</verison>
39+
</dependency>
40+
<dependency>
41+
<groupId>org.jacodb</groupId>
42+
<artifactId>jacodb-api</artifactId>
43+
<verison>1.2.0</verison>
44+
</dependency>
45+
<dependency>
46+
<groupId>org.jacodb</groupId>
47+
<artifactId>jacodb-analysis</artifactId>
48+
<verison>1.2.0</verison>
49+
</dependency>
50+
</dependencies>
51+
```
52+
53+
## Concepts
2254

2355
API has two levels: the one representing in filesystem (**bytecode** and **classes**) and the one appearing at runtime (**types**).
2456

@@ -27,6 +59,26 @@ API has two levels: the one representing in filesystem (**bytecode** and **class
2759

2860
Both levels are connected to `JcClasspath`. You can't modify **classes** retrieved from pure bytecode. **types** may be constructed manually by generics substitution.
2961

62+
### Classes
63+
64+
```java
65+
public static void getStringFields() throws Exception {
66+
JcDatabase database = JacoDB.async(new JcSettings().useProcessJavaRuntime()).get();
67+
JcClassOrInterface clazz = database.asyncClasspath(emptyList()).get().findClassOrNull("java.lang.String");
68+
System.out.println(clazz.getDeclaredFields());
69+
}
70+
```
71+
72+
Kotlin
73+
```kotlin
74+
val database = jacodb {
75+
useProcessJavaRuntime()
76+
}
77+
val clazz = database.classpath().findClassOrNull("java.lang.String")
78+
```
79+
80+
More complex examples:
81+
3082
Java
3183
```java
3284
class Example {
@@ -55,14 +107,14 @@ class Example {
55107
System.out.println(JcClasses.getConstructors(jcClass).size());
56108

57109
// At this point the database read the method bytecode and return the result.
58-
return jcClass.getDeclaredMethods().get(0).body();
110+
return jcClass.getDeclaredMethods().get(0).asmNode();
59111
}
60112
}
61113
```
62114

63115
Kotlin
64116
```kotlin
65-
suspend fun findNormalDistribution(): Any {
117+
suspend fun findNormalDistribution(): MethodNode {
66118
val commonsMath32 = File("commons-math3-3.2.jar")
67119
val commonsMath36 = File("commons-math3-3.6.1.jar")
68120
val buildDir = File("my-project/build/classes/java/main")
@@ -86,13 +138,12 @@ suspend fun findNormalDistribution(): Any {
86138
println(jcClass.annotations.size)
87139

88140
// At this point the database read the method bytecode and return the result.
89-
return jcClass.methods[0].body()
141+
return jcClass.methods[0].asmNode()
90142
}
91143
```
92144

93-
94-
95-
Note: the `body` method returns `null` if the to-be-processed JAR-file was changed or removed. Class could be in incomplete environment (i.e super class, interface, return type or parameter of method is not found in classpath) then api will throw `NoClassInClasspathException` at runtime.
145+
Class could be in incomplete environment (i.e super class, interface, return type or parameter of method is not found in classpath) then api will throw `NoClassInClasspathException` at runtime.
146+
To fix this install `UnknownClasses` feature into classpath during creation.
96147

97148
The database can watch for file system changes in the background and refresh the JAR-files explicitly:
98149

@@ -117,7 +168,6 @@ Kotlin
117168
watchFileSystem()
118169
useProcessJavaRuntime()
119170
loadByteCode(listOf(lib1, buildDir))
120-
persistent("")
121171
}
122172

123173
// A user rebuilds the buildDir folder.
@@ -171,6 +221,46 @@ Kotlin
171221
}
172222
```
173223

224+
## Features
225+
226+
Features could be used for whole `JcDatabase` or particular `JcClasspath`
227+
228+
### Usages
229+
230+
Database feature for searching usages of fields and methods.
231+
232+
```kotlin
233+
val database = jacodb {
234+
install(Usages)
235+
}
236+
```
237+
238+
see [more](https://jacodb.org/documentation/database-features/#usages)
239+
240+
### Unknown Classes
241+
242+
Mocks unknown classes. It's a grace way to handle incomplete classpaths
243+
244+
```kotlin
245+
val database = jacodb {}
246+
val classpath = database.classpath(listOf(UnknownClasses))
247+
248+
val clazz = classpath.findClass("UnknownClasses") // will return `JcClassOrInterface` instance
249+
```
250+
251+
see [more](https://jacodb.org/documentation/classpath-features/#unknownClasses)
252+
253+
254+
### InMemory hierarchy
255+
256+
A bit faster hierarchy but consume more RAM memory:
257+
258+
```kotlin
259+
val database = jacodb {
260+
install(InMemoryHierarchy)
261+
}
262+
```
263+
see [more](https://jacodb.org/documentation/database-features/#inmemoryhierarchy)
174264

175265
## Multithreading
176266

jacodb-api/src/main/kotlin/org/jacodb/api/Classes.kt

+6
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ interface JcClassOrInterface : JcAnnotatedSymbol, JcAccessible {
4848

4949
fun <T> extensionValue(key: String): T?
5050

51+
/**
52+
* lookup instance for this class. Use it to resolve field/method references from bytecode instructions
53+
*
54+
* It's not necessary that looked up method will return instance preserved in [JcClassOrInterface.declaredFields] or
55+
* [JcClassOrInterface.declaredMethods] collections
56+
*/
5157
val lookup: JcLookup<JcField, JcMethod>
5258

5359
val isAnnotation: Boolean

jacodb-api/src/main/kotlin/org/jacodb/api/JcLookup.kt

+38-1
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,52 @@
1717
package org.jacodb.api
1818

1919
/**
20-
* lookup for fields and methods in [JcClassOrInterface] and [JcClassType]
20+
* lookup for fields and methods in [JcClassOrInterface] and [JcClassType].
21+
*
22+
* It's not necessary that looked up method will return instance preserved in [JcClassOrInterface.declaredFields] or
23+
* [JcClassOrInterface.declaredMethods] collections
2124
*/
2225
@JvmDefaultWithoutCompatibility
2326
interface JcLookup<Field : JcAccessible, Method : JcAccessible> {
2427

28+
/**
29+
* lookup for field with specific name
30+
* @param name of field
31+
*/
2532
fun field(name: String): Field? = field(name, null)
33+
34+
/**
35+
* lookup for field with specific name and expected type. Used during instructions parsing. In this case field type is preserved
36+
* in Java bytecode
37+
*
38+
* @param name of field
39+
* @param typeName expected type of field
40+
*/
2641
fun field(name: String, typeName: TypeName?): Field?
42+
43+
/**
44+
* Lookup for method based on name and description:
45+
* - in current class search for private methods too
46+
* - in parent classes and interfaces search only for visible methods
47+
*
48+
* @param name method name
49+
* @param description jvm description of method
50+
*/
2751
fun method(name: String, description: String): Method?
2852

53+
/**
54+
* Lookup for static method based on name and description
55+
*
56+
* @param name method name
57+
* @param description jvm description of method
58+
*/
2959
fun staticMethod(name: String, description: String): Method?
60+
61+
/**
62+
* Lookup for methods placed in special instructions i.e `private` and `super` calls.
63+
*
64+
* @param name method name
65+
* @param description jvm description of method
66+
*/
3067
fun specialMethod(name: String, description: String): Method?
3168
}

jacodb-api/src/main/kotlin/org/jacodb/api/Types.kt

+6
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,12 @@ interface JcClassType : JcRefType, JcAccessible {
101101

102102
val innerTypes: List<JcClassType>
103103

104+
/**
105+
* lookup instance for this class. Use it to resolve field/method references from bytecode instructions
106+
*
107+
* It's not necessary that looked up method will return instance preserved in [JcClassType.declaredFields] or
108+
* [JcClassType.declaredMethods] collections
109+
*/
104110
val lookup: JcLookup<JcTypedField, JcTypedMethod>
105111

106112
}

jacodb-core/src/main/kotlin/org/jacodb/impl/features/classpaths/JcUnknownClass.kt

+34
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,40 @@ class JcUnknownField(enclosingClass: JcUnknownClass, name: String, type: TypeNam
9292
}
9393
}
9494

95+
/**
96+
* Feature for mocking references to unknown classes. I.e let's assume that we have:
97+
*
98+
* ```
99+
* class Bar {
100+
*
101+
* int x = 0;
102+
*
103+
* public void run() {
104+
* System.out.println("Hello world");
105+
* }
106+
* }
107+
*
108+
* class Foo extends Bar {
109+
*
110+
* Bar f = new Bar();
111+
*
112+
* public void call() {
113+
* System.out.println(f.x);
114+
* run();
115+
* }
116+
* }
117+
* ```
118+
*
119+
* Let's assume that we have classpath that contains class `Foo` and doesn't contain `Bar`. Default behavior for
120+
* classpath is to fail on trying to access class that doesn't exist. i.e parsing method instructions will fail, reading
121+
* class hierarchy will fail, resolving method will fail.
122+
*
123+
* UnknownClasses feature fix this behaviour. All references pointing to nowhere will be resolved as special implementation
124+
* of [JcClassOrInterface] instance. Such instance will have **empty** [JcClassOrInterface.declaredFields] and
125+
* [JcClassOrInterface.declaredMethods] but all resolutions done through [JcClassOrInterface.lookup] interface will return
126+
* mocked instances
127+
*
128+
*/
95129
object UnknownClasses : JcClasspathExtFeature {
96130
override fun tryFindClass(classpath: JcClasspath, name: String): JcClasspathExtFeature.JcResolvedClassResult {
97131
return JcResolvedClassResultImpl(name, JcUnknownClass(classpath, name))

jacodb-examples/src/main/java/org/jacodb/examples/JavaReadMeExamples.java

+7-5
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,7 @@
1616

1717
package org.jacodb.examples;
1818

19-
import org.jacodb.api.JcClassOrInterface;
20-
import org.jacodb.api.JcClassType;
21-
import org.jacodb.api.JcClasspath;
22-
import org.jacodb.api.JcDatabase;
23-
import org.jacodb.api.JcType;
19+
import org.jacodb.api.*;
2420
import org.jacodb.api.ext.JcClasses;
2521
import org.jacodb.impl.JacoDB;
2622
import org.jacodb.impl.JcSettings;
@@ -29,6 +25,7 @@
2925
import java.io.File;
3026
import java.util.Arrays;
3127

28+
import static java.util.Collections.emptyList;
3229
import static java.util.Collections.singletonList;
3330

3431
public class JavaReadMeExamples {
@@ -40,6 +37,11 @@ public class JavaReadMeExamples {
4037
private static File lib2 = new File("2");
4138
private static File buildDir = new File("3");
4239

40+
public static void getStringFields() throws Exception {
41+
JcDatabase database = JacoDB.async(new JcSettings().useProcessJavaRuntime()).get();
42+
JcClassOrInterface clazz = database.asyncClasspath(emptyList()).get().findClassOrNull("java.lang.String");
43+
System.out.println(clazz.getDeclaredFields());
44+
}
4345

4446
public static MethodNode findNormalDistribution() throws Exception {
4547
File commonsMath32 = new File("commons-math3-3.2.jar");

0 commit comments

Comments
 (0)