mirror of
https://github.com/corda/corda.git
synced 2025-03-17 17:45:17 +00:00
Merge pull request #205 from dicej/getPackage
ensure ClassLoader.getPackage works with all class libraries
This commit is contained in:
commit
c5012cda72
@ -74,6 +74,21 @@ public class SystemClassLoader extends ClassLoader {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected Package getPackage(String name) {
|
||||
Package p = super.getPackage(name);
|
||||
if (p == null) {
|
||||
String source = getPackageSource(name);
|
||||
if (source != null) {
|
||||
// todo: load attributes from JAR manifest
|
||||
definePackage(name, null, null, null, null, null, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
return super.getPackage(name);
|
||||
}
|
||||
|
||||
protected static native String getPackageSource(String name);
|
||||
|
||||
// OpenJDK's java.lang.ClassLoader.getResource makes use of
|
||||
// sun.misc.Launcher to load bootstrap resources, which is not
|
||||
// appropriate for the Avian build, so we override it to ensure we
|
||||
|
@ -559,8 +559,7 @@ public final class Class <T> implements Type, AnnotatedElement {
|
||||
String name = getCanonicalName();
|
||||
int index = name.lastIndexOf('.');
|
||||
if (index >= 0) {
|
||||
return new Package(name.substring(0, index),
|
||||
null, null, null, null, null, null, null, null);
|
||||
return getClassLoader().getPackage(name.substring(0, index));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
@ -17,9 +17,12 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
|
||||
public abstract class ClassLoader {
|
||||
private final ClassLoader parent;
|
||||
private Map<String, Package> packages;
|
||||
|
||||
protected ClassLoader(ClassLoader parent) {
|
||||
if (parent == null) {
|
||||
@ -33,6 +36,45 @@ public abstract class ClassLoader {
|
||||
this(getSystemClassLoader());
|
||||
}
|
||||
|
||||
private Map<String, Package> packages() {
|
||||
if (packages == null) {
|
||||
packages = new HashMap();
|
||||
}
|
||||
return packages;
|
||||
}
|
||||
|
||||
protected Package getPackage(String name) {
|
||||
synchronized (this) {
|
||||
return packages().get(name);
|
||||
}
|
||||
}
|
||||
|
||||
protected Package[] getPackages() {
|
||||
synchronized (this) {
|
||||
return packages().values().toArray(new Package[packages().size()]);
|
||||
}
|
||||
}
|
||||
|
||||
protected Package definePackage(String name,
|
||||
String specificationTitle,
|
||||
String specificationVersion,
|
||||
String specificationVendor,
|
||||
String implementationTitle,
|
||||
String implementationVersion,
|
||||
String implementationVendor,
|
||||
URL sealBase)
|
||||
{
|
||||
Package p = new Package
|
||||
(name, implementationTitle, implementationVersion,
|
||||
implementationVendor, specificationTitle, specificationVersion,
|
||||
specificationVendor, sealBase, this);
|
||||
|
||||
synchronized (this) {
|
||||
packages().put(name, p);
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
public static ClassLoader getSystemClassLoader() {
|
||||
return ClassLoader.class.getClassLoader();
|
||||
}
|
||||
|
@ -1577,9 +1577,6 @@ class Classpath {
|
||||
virtual const char*
|
||||
bootClasspath() = 0;
|
||||
|
||||
virtual void
|
||||
updatePackageMap(Thread* t, object class_) = 0;
|
||||
|
||||
virtual object
|
||||
makeDirectByteBuffer(Thread* t, void* p, jlong capacity) = 0;
|
||||
|
||||
|
@ -238,6 +238,36 @@ Avian_avian_SystemClassLoader_getClass
|
||||
(getJClass(t, reinterpret_cast<object>(arguments[0])));
|
||||
}
|
||||
|
||||
extern "C" AVIAN_EXPORT int64_t JNICALL
|
||||
Avian_avian_SystemClassLoader_getPackageSource
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object name = reinterpret_cast<object>(arguments[0]);
|
||||
PROTECT(t, name);
|
||||
|
||||
ACQUIRE(t, t->m->classLock);
|
||||
|
||||
THREAD_RUNTIME_ARRAY(t, char, chars, stringLength(t, name) + 2);
|
||||
stringChars(t, name, RUNTIME_ARRAY_BODY(chars));
|
||||
replace('.', '/', RUNTIME_ARRAY_BODY(chars));
|
||||
RUNTIME_ARRAY_BODY(chars)[stringLength(t, name)] = '/';
|
||||
RUNTIME_ARRAY_BODY(chars)[stringLength(t, name) + 1] = 0;
|
||||
|
||||
object key = makeByteArray(t, RUNTIME_ARRAY_BODY(chars));
|
||||
|
||||
object array = hashMapFind
|
||||
(t, root(t, Machine::PackageMap), key, byteArrayHash, byteArrayEqual);
|
||||
|
||||
if (array) {
|
||||
return reinterpret_cast<uintptr_t>
|
||||
(makeLocalReference
|
||||
(t, t->m->classpath->makeString
|
||||
(t, array, 0, byteArrayLength(t, array))));
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef AVIAN_HEAPDUMP
|
||||
|
||||
extern "C" AVIAN_EXPORT void JNICALL
|
||||
|
@ -22,6 +22,7 @@ extern "C" int JNI_OnLoad(JavaVM*, void*);
|
||||
#include "avian/machine.h"
|
||||
#include "avian/classpath-common.h"
|
||||
#include "avian/process.h"
|
||||
#include "avian/util.h"
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
const char* getErrnoDescription(int err); // This function is defined in mingw-extensions.cpp
|
||||
@ -488,9 +489,22 @@ class MyClasspath : public Classpath {
|
||||
}
|
||||
|
||||
virtual void
|
||||
boot(Thread*)
|
||||
boot(Thread* t)
|
||||
{
|
||||
// ignore
|
||||
object c = resolveClass
|
||||
(t, root(t, Machine::BootLoader), "java/lang/ClassLoader");
|
||||
PROTECT(t, c);
|
||||
|
||||
object constructor = resolveMethod
|
||||
(t, c, "<init>", "(Ljava/lang/ClassLoader;Z)V");
|
||||
PROTECT(t, constructor);
|
||||
|
||||
t->m->processor->invoke
|
||||
(t, constructor, root(t, Machine::BootLoader), 0, true);
|
||||
|
||||
t->m->processor->invoke
|
||||
(t, constructor, root(t, Machine::AppLoader),
|
||||
root(t, Machine::BootLoader), false);
|
||||
}
|
||||
|
||||
virtual const char*
|
||||
@ -499,12 +513,6 @@ class MyClasspath : public Classpath {
|
||||
return AVIAN_CLASSPATH;
|
||||
}
|
||||
|
||||
virtual void
|
||||
updatePackageMap(Thread*, object)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
|
||||
virtual object
|
||||
makeDirectByteBuffer(Thread* t, void* p, jlong capacity)
|
||||
{
|
||||
|
@ -133,12 +133,6 @@ class MyClasspath : public Classpath {
|
||||
return AVIAN_CLASSPATH;
|
||||
}
|
||||
|
||||
virtual void
|
||||
updatePackageMap(Thread*, object)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
|
||||
virtual object
|
||||
makeDirectByteBuffer(Thread* t, void* p, jlong capacity)
|
||||
{
|
||||
|
@ -774,62 +774,6 @@ class MyClasspath : public Classpath {
|
||||
return classpath;
|
||||
}
|
||||
|
||||
virtual void
|
||||
updatePackageMap(Thread* t, object class_)
|
||||
{
|
||||
PROTECT(t, class_);
|
||||
|
||||
if (root(t, Machine::PackageMap) == 0) {
|
||||
setRoot(t, Machine::PackageMap, makeHashMap(t, 0, 0));
|
||||
}
|
||||
|
||||
object className = vm::className(t, class_);
|
||||
if ('[' != byteArrayBody(t, className, 0)) {
|
||||
THREAD_RUNTIME_ARRAY
|
||||
(t, char, packageName, byteArrayLength(t, className));
|
||||
|
||||
char* s = reinterpret_cast<char*>(&byteArrayBody(t, className, 0));
|
||||
char* p = strrchr(s, '/');
|
||||
|
||||
if (p) {
|
||||
int length = (p - s) + 1;
|
||||
memcpy(RUNTIME_ARRAY_BODY(packageName),
|
||||
&byteArrayBody(t, className, 0),
|
||||
length);
|
||||
RUNTIME_ARRAY_BODY(packageName)[length] = 0;
|
||||
|
||||
object key = vm::makeByteArray
|
||||
(t, "%s", RUNTIME_ARRAY_BODY(packageName));
|
||||
PROTECT(t, key);
|
||||
|
||||
hashMapRemove
|
||||
(t, root(t, Machine::PackageMap), key, byteArrayHash,
|
||||
byteArrayEqual);
|
||||
|
||||
object source = classSource(t, class_);
|
||||
if (source) {
|
||||
// note that we strip the "file:" prefix, since
|
||||
// Package.defineSystemPackage expects an unadorned
|
||||
// filename:
|
||||
const unsigned PrefixLength = 5;
|
||||
unsigned sourceNameLength = byteArrayLength(t, source)
|
||||
- PrefixLength;
|
||||
THREAD_RUNTIME_ARRAY(t, char, sourceName, sourceNameLength);
|
||||
memcpy(RUNTIME_ARRAY_BODY(sourceName),
|
||||
&byteArrayBody(t, source, PrefixLength),
|
||||
sourceNameLength);
|
||||
|
||||
source = vm::makeByteArray(t, "%s", RUNTIME_ARRAY_BODY(sourceName));
|
||||
} else {
|
||||
source = vm::makeByteArray(t, "avian-dummy-package-source");
|
||||
}
|
||||
|
||||
hashMapInsert
|
||||
(t, root(t, Machine::PackageMap), key, source, byteArrayHash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual object
|
||||
makeDirectByteBuffer(Thread* t, void* p, jlong capacity)
|
||||
{
|
||||
|
@ -3042,6 +3042,61 @@ findInTable(Thread* t, object table, object name, object spec,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
updatePackageMap(Thread* t, object class_)
|
||||
{
|
||||
PROTECT(t, class_);
|
||||
|
||||
if (root(t, Machine::PackageMap) == 0) {
|
||||
setRoot(t, Machine::PackageMap, makeHashMap(t, 0, 0));
|
||||
}
|
||||
|
||||
object className = vm::className(t, class_);
|
||||
if ('[' != byteArrayBody(t, className, 0)) {
|
||||
THREAD_RUNTIME_ARRAY
|
||||
(t, char, packageName, byteArrayLength(t, className));
|
||||
|
||||
char* s = reinterpret_cast<char*>(&byteArrayBody(t, className, 0));
|
||||
char* p = strrchr(s, '/');
|
||||
|
||||
if (p) {
|
||||
int length = (p - s) + 1;
|
||||
memcpy(RUNTIME_ARRAY_BODY(packageName),
|
||||
&byteArrayBody(t, className, 0),
|
||||
length);
|
||||
RUNTIME_ARRAY_BODY(packageName)[length] = 0;
|
||||
|
||||
object key = vm::makeByteArray
|
||||
(t, "%s", RUNTIME_ARRAY_BODY(packageName));
|
||||
PROTECT(t, key);
|
||||
|
||||
hashMapRemove
|
||||
(t, root(t, Machine::PackageMap), key, byteArrayHash,
|
||||
byteArrayEqual);
|
||||
|
||||
object source = classSource(t, class_);
|
||||
if (source) {
|
||||
// note that we strip the "file:" prefix, since OpenJDK's
|
||||
// Package.defineSystemPackage expects an unadorned filename:
|
||||
const unsigned PrefixLength = 5;
|
||||
unsigned sourceNameLength = byteArrayLength(t, source)
|
||||
- PrefixLength;
|
||||
THREAD_RUNTIME_ARRAY(t, char, sourceName, sourceNameLength);
|
||||
memcpy(RUNTIME_ARRAY_BODY(sourceName),
|
||||
&byteArrayBody(t, source, PrefixLength),
|
||||
sourceNameLength);
|
||||
|
||||
source = vm::makeByteArray(t, "%s", RUNTIME_ARRAY_BODY(sourceName));
|
||||
} else {
|
||||
source = vm::makeByteArray(t, "avian-dummy-package-source");
|
||||
}
|
||||
|
||||
hashMapInsert
|
||||
(t, root(t, Machine::PackageMap), key, source, byteArrayHash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace vm {
|
||||
@ -4295,7 +4350,7 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_,
|
||||
if (class_) {
|
||||
hashMapInsert(t, classLoaderMap(t, loader), spec, class_, byteArrayHash);
|
||||
|
||||
t->m->classpath->updatePackageMap(t, class_);
|
||||
updatePackageMap(t, class_);
|
||||
} else if (throw_) {
|
||||
throwNew(t, throwType, "%s", &byteArrayBody(t, spec, 0));
|
||||
}
|
||||
|
@ -249,6 +249,9 @@ public class Reflection {
|
||||
expect(getClass().getDeclaringClass() == null);
|
||||
}
|
||||
}.run();
|
||||
|
||||
expect(avian.testing.annotations.Test.class.getPackage().getName().equals
|
||||
("avian.testing.annotations"));
|
||||
}
|
||||
|
||||
protected static class Baz {
|
||||
|
Loading…
x
Reference in New Issue
Block a user