1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117 | package Torello.Java.Additional;
import java.io.UncheckedIOException;
import Torello.Java.FileRW;
import java.io.IOException;
/**
* This utilizes the class {@link ConstantPool} to facilitate loading a Java-Class
* from any directory. There is no requirement that the {@code '.class'} file be properly placed
* in a sub-directory that has a name which mirrors the full Package-Name of the class which is to
* be loaded.
*/
public class ByteArrClassLoader extends ClassLoader
{
public ByteArrClassLoader(ClassLoader parentClassLoader)
{ super(parentClassLoader); }
public ByteArrClassLoader() { super(); }
public Class<?> defineClass(String name, byte[] classBytes)
{ return defineClass(name, classBytes, 0, classBytes.length); }
/**
* Retrieves a Java {@code java.lang.Class} instance from a {@code '.class'}-File, using only
* the File-Name of said file.
*
* @param classFileName The File-Name of any Java {@code '.class'}-File
* @return An instance of {@code java.lang.Class}
* @see #defineClass(String, byte[])
*/
public Class<?> readJavaClass(final String classFileName)
throws IOException
{
final byte[] bArr = FileRW.readBinary(classFileName);
return this.defineClass(extractClassName(bArr), bArr);
}
/**
* Retrieves a Java {@code java.lang.Class} instance from a {@code '.class'}-File, using only
* the File-Name of said file.
*
* <BR /><BR /><B CLASS=JDDescLabel>Exception Suppression:</B>
*
* <BR />This method suppresses the {@code java.io.IOException}, and wraps it in Java's
* {@code UncheckedIOExceptoin}. This can make things such as Lambda-Expressions easier.
*
* @param classFileName The File-Name of any Java {@code '.class'}-File
* @return An instance of {@code java.lang.Class}
* @see #defineClass(String, byte[])
*/
public Class<?> readJavaClassNOIOE(final String classFileName)
{
try
{
final byte[] bArr = FileRW.readBinary(classFileName);
return this.defineClass(extractClassName(bArr), bArr);
}
catch(IOException ioe)
{ throw new UncheckedIOException(ioe); }
}
/**
* Retrieves a Java {@code java.lang.Class} instance from a {@code byte[]}-Array which has
* been loaded from disk from a {@code '.class'}-File.
*
* @param bArr Any Java {@code '.class'}-File, as a {@code byte[]}-Array
* @return An instance of {@code java.lang.Class}
* @see #defineClass(String, byte[])
*/
public Class<?> readJavaClass(final byte[] bArr)
{ return this.defineClass(extractClassName(bArr), bArr); }
// Exception-Message Helper ...
private static final String exMsgStart(int classRecordIndex)
{
return
"The byte[]-Array location which must contain Constant-Pool Table-Index for this " +
"Class' Name actually contained a bad-value (" + classRecordIndex + ") because it " +
"pointed to an index that ";
}
/**
* Loads the Constant-Pool from a Java {@code '.class'}-File and extracts that class'
* name.
*
* @param bArr The {@code byte[]}-Array associated with a Java Class.
* @see ConstantPool
*/
public static String extractClassName(byte[] bArr)
{
final ConstantPool cp = new ConstantPool(bArr);
final int i = cp.tableSizeBytes + 13;
if (i >= bArr.length) throw new ClassFileArrayException
("The provided byte[]-Array isn't long enough to be a valid Java '.class' File.");
final int classRecordIndex =
((bArr[i-1] & 0xFF) << 8) | (bArr[i] & 0xFF);
if (classRecordIndex >= cp.tableSize) throw new ClassFileArrayException(
exMsgStart(classRecordIndex) + "was out of range of the " +
"ContantPool's size (which is " + cp.tableSize + ')'
);
if (cp.tags.get(classRecordIndex) != ConstantPool.TAG_CLASS)
throw new ClassFileArrayException
(exMsgStart(classRecordIndex) + "does not contain a 'Class' Tag-Kind ");
String ret = (String) cp.dereferencedValues.get(classRecordIndex);
return ret.replace('/', '.');
}
}
|