mirror of
https://github.com/corda/corda.git
synced 2025-06-02 15:40:53 +00:00
ensure ClassLoader.getPackage works with all class libraries
There's more work to do to derive all the properties of a given class from its code source (e.g. JAR file), but this at least ensures that ClassLoader.getPackage will actually return something non-null when appropriate.
This commit is contained in:
parent
e9e365d698
commit
8740d76154
@ -74,6 +74,21 @@ public class SystemClassLoader extends ClassLoader {
|
|||||||
return null;
|
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
|
// OpenJDK's java.lang.ClassLoader.getResource makes use of
|
||||||
// sun.misc.Launcher to load bootstrap resources, which is not
|
// sun.misc.Launcher to load bootstrap resources, which is not
|
||||||
// appropriate for the Avian build, so we override it to ensure we
|
// 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();
|
String name = getCanonicalName();
|
||||||
int index = name.lastIndexOf('.');
|
int index = name.lastIndexOf('.');
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
return new Package(name.substring(0, index),
|
return getClassLoader().getPackage(name.substring(0, index));
|
||||||
null, null, null, null, null, null, null, null);
|
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -17,9 +17,12 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
public abstract class ClassLoader {
|
public abstract class ClassLoader {
|
||||||
private final ClassLoader parent;
|
private final ClassLoader parent;
|
||||||
|
private Map<String, Package> packages;
|
||||||
|
|
||||||
protected ClassLoader(ClassLoader parent) {
|
protected ClassLoader(ClassLoader parent) {
|
||||||
if (parent == null) {
|
if (parent == null) {
|
||||||
@ -33,6 +36,45 @@ public abstract class ClassLoader {
|
|||||||
this(getSystemClassLoader());
|
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() {
|
public static ClassLoader getSystemClassLoader() {
|
||||||
return ClassLoader.class.getClassLoader();
|
return ClassLoader.class.getClassLoader();
|
||||||
}
|
}
|
||||||
|
@ -1577,9 +1577,6 @@ class Classpath {
|
|||||||
virtual const char*
|
virtual const char*
|
||||||
bootClasspath() = 0;
|
bootClasspath() = 0;
|
||||||
|
|
||||||
virtual void
|
|
||||||
updatePackageMap(Thread* t, object class_) = 0;
|
|
||||||
|
|
||||||
virtual object
|
virtual object
|
||||||
makeDirectByteBuffer(Thread* t, void* p, jlong capacity) = 0;
|
makeDirectByteBuffer(Thread* t, void* p, jlong capacity) = 0;
|
||||||
|
|
||||||
|
@ -238,6 +238,36 @@ Avian_avian_SystemClassLoader_getClass
|
|||||||
(getJClass(t, reinterpret_cast<object>(arguments[0])));
|
(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
|
#ifdef AVIAN_HEAPDUMP
|
||||||
|
|
||||||
extern "C" AVIAN_EXPORT void JNICALL
|
extern "C" AVIAN_EXPORT void JNICALL
|
||||||
|
@ -22,6 +22,7 @@ extern "C" int JNI_OnLoad(JavaVM*, void*);
|
|||||||
#include "avian/machine.h"
|
#include "avian/machine.h"
|
||||||
#include "avian/classpath-common.h"
|
#include "avian/classpath-common.h"
|
||||||
#include "avian/process.h"
|
#include "avian/process.h"
|
||||||
|
#include "avian/util.h"
|
||||||
|
|
||||||
#ifdef PLATFORM_WINDOWS
|
#ifdef PLATFORM_WINDOWS
|
||||||
const char* getErrnoDescription(int err); // This function is defined in mingw-extensions.cpp
|
const char* getErrnoDescription(int err); // This function is defined in mingw-extensions.cpp
|
||||||
@ -488,9 +489,22 @@ class MyClasspath : public Classpath {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void
|
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*
|
virtual const char*
|
||||||
@ -499,12 +513,6 @@ class MyClasspath : public Classpath {
|
|||||||
return AVIAN_CLASSPATH;
|
return AVIAN_CLASSPATH;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void
|
|
||||||
updatePackageMap(Thread*, object)
|
|
||||||
{
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual object
|
virtual object
|
||||||
makeDirectByteBuffer(Thread* t, void* p, jlong capacity)
|
makeDirectByteBuffer(Thread* t, void* p, jlong capacity)
|
||||||
{
|
{
|
||||||
|
@ -133,12 +133,6 @@ class MyClasspath : public Classpath {
|
|||||||
return AVIAN_CLASSPATH;
|
return AVIAN_CLASSPATH;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void
|
|
||||||
updatePackageMap(Thread*, object)
|
|
||||||
{
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual object
|
virtual object
|
||||||
makeDirectByteBuffer(Thread* t, void* p, jlong capacity)
|
makeDirectByteBuffer(Thread* t, void* p, jlong capacity)
|
||||||
{
|
{
|
||||||
|
@ -774,62 +774,6 @@ class MyClasspath : public Classpath {
|
|||||||
return 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
|
virtual object
|
||||||
makeDirectByteBuffer(Thread* t, void* p, jlong capacity)
|
makeDirectByteBuffer(Thread* t, void* p, jlong capacity)
|
||||||
{
|
{
|
||||||
|
@ -3042,6 +3042,61 @@ findInTable(Thread* t, object table, object name, object spec,
|
|||||||
return 0;
|
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
|
||||||
|
|
||||||
namespace vm {
|
namespace vm {
|
||||||
@ -4295,7 +4350,7 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_,
|
|||||||
if (class_) {
|
if (class_) {
|
||||||
hashMapInsert(t, classLoaderMap(t, loader), spec, class_, byteArrayHash);
|
hashMapInsert(t, classLoaderMap(t, loader), spec, class_, byteArrayHash);
|
||||||
|
|
||||||
t->m->classpath->updatePackageMap(t, class_);
|
updatePackageMap(t, class_);
|
||||||
} else if (throw_) {
|
} else if (throw_) {
|
||||||
throwNew(t, throwType, "%s", &byteArrayBody(t, spec, 0));
|
throwNew(t, throwType, "%s", &byteArrayBody(t, spec, 0));
|
||||||
}
|
}
|
||||||
|
@ -249,6 +249,9 @@ public class Reflection {
|
|||||||
expect(getClass().getDeclaringClass() == null);
|
expect(getClass().getDeclaringClass() == null);
|
||||||
}
|
}
|
||||||
}.run();
|
}.run();
|
||||||
|
|
||||||
|
expect(avian.testing.annotations.Test.class.getPackage().getName().equals
|
||||||
|
("avian.testing.annotations"));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static class Baz {
|
protected static class Baz {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user