Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Watson2016-10-26 16:43:02 +0000
committerThomas Watson2016-10-27 15:55:38 +0000
commit1c6c4c37e9993d0a163590962477682d9c43ed7c (patch)
tree1d40dd4db604697d5a55a24a6aad0712ead25d98
parente13ed4ada2d35b760bce681b6b7887279d0e6416 (diff)
downloadrt.equinox.framework-1c6c4c37e9993d0a163590962477682d9c43ed7c.tar.gz
rt.equinox.framework-1c6c4c37e9993d0a163590962477682d9c43ed7c.tar.xz
rt.equinox.framework-1c6c4c37e9993d0a163590962477682d9c43ed7c.zip
Bug 502209 - Reflection used for URL handler support breaks on Java 9
Change-Id: I8069523103f1e3966feb9856e2a1100eda6b02b2 Signed-off-by: Thomas Watson <tjwatson@us.ibm.com>
-rw-r--r--bundles/org.eclipse.osgi/.settings/org.eclipse.jdt.core.prefs8
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/url/EquinoxFactoryManager.java4
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/url/MultiplexingFactory.java56
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/url/MultiplexingURLStreamHandler.java24
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/url/SetAccessible.bytesbin0 -> 2264 bytes
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/url/SetAccessible.java.src83
6 files changed, 157 insertions, 18 deletions
diff --git a/bundles/org.eclipse.osgi/.settings/org.eclipse.jdt.core.prefs b/bundles/org.eclipse.osgi/.settings/org.eclipse.jdt.core.prefs
index 15d2ec557..be242e5a9 100644
--- a/bundles/org.eclipse.osgi/.settings/org.eclipse.jdt.core.prefs
+++ b/bundles/org.eclipse.osgi/.settings/org.eclipse.jdt.core.prefs
@@ -9,10 +9,14 @@ org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled
org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled
org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
+org.eclipse.jdt.core.compiler.annotation.nonnull.secondary=
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
+org.eclipse.jdt.core.compiler.annotation.nonnullbydefault.secondary=
org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
+org.eclipse.jdt.core.compiler.annotation.nullable.secondary=
org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.7
@@ -38,7 +42,7 @@ org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
-org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
@@ -71,12 +75,14 @@ org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=warning
org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning
+org.eclipse.jdt.core.compiler.problem.nonnullTypeVariableFromLegacyInvocation=warning
org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
org.eclipse.jdt.core.compiler.problem.nullReference=warning
org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.pessimisticNullAnalysisForFreeTypeVariables=warning
org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/url/EquinoxFactoryManager.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/url/EquinoxFactoryManager.java
index 90c98c0ec..c267a95e7 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/url/EquinoxFactoryManager.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/url/EquinoxFactoryManager.java
@@ -92,7 +92,7 @@ public class EquinoxFactoryManager {
Object lock;
try {
Field streamHandlerLockField = URL.class.getDeclaredField("streamHandlerLock"); //$NON-NLS-1$
- streamHandlerLockField.setAccessible(true);
+ MultiplexingFactory.setAccessible(streamHandlerLockField);
lock = streamHandlerLockField.get(null);
} catch (NoSuchFieldException noField) {
// could not find the lock, lets sync on the class object
@@ -229,7 +229,7 @@ public class EquinoxFactoryManager {
for (int i = 0; i < fields.length; i++) {
boolean isStatic = Modifier.isStatic(fields[i].getModifiers());
if (instance != isStatic && fields[i].getType().equals(type)) {
- fields[i].setAccessible(true);
+ MultiplexingFactory.setAccessible(fields[i]);
return fields[i];
}
}
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/url/MultiplexingFactory.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/url/MultiplexingFactory.java
index edccf78a3..c78748c44 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/url/MultiplexingFactory.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/url/MultiplexingFactory.java
@@ -8,12 +8,13 @@
*******************************************************************************/
package org.eclipse.osgi.internal.url;
-import java.lang.reflect.Method;
-import java.util.LinkedList;
-import java.util.List;
+import java.lang.reflect.*;
+import java.net.URL;
+import java.util.*;
import org.eclipse.osgi.framework.log.FrameworkLogEntry;
import org.eclipse.osgi.internal.framework.EquinoxBundle;
import org.eclipse.osgi.internal.framework.EquinoxContainer;
+import org.eclipse.osgi.storage.StorageUtil;
import org.osgi.framework.*;
/*
@@ -21,6 +22,47 @@ import org.osgi.framework.*;
* handle environments running multiple osgi frameworks with the same VM.
*/
public abstract class MultiplexingFactory {
+ /**
+ * As a short-term (hopefully) solution we use a special class which is defined
+ * using the Unsafe class from the VM. This class is an implementation of
+ * Collection<AccessibleObject> simply to provide a method add(AccessibleObject)
+ * which turns around and calls AccessibleObject.setAccessible(true).
+ * <p>
+ * The reason this is needed is to hack into the VM to get deep reflective access to
+ * the java.net package for the various hacks we have to do to multiplex the
+ * URL and Content handlers. Note that on Java 9 deep reflection is not possible
+ * by default on the java.net package.
+ * <p>
+ * The setAccessible class will be defined in the java.base module which grants
+ * it the ability to call setAccessible(true) on other types from the java.base module
+ */
+ static final Collection<AccessibleObject> setAccessible;
+ static {
+ Collection<AccessibleObject> result = null;
+ try {
+ // Use reflection on Unsafe to avoid having to compile against it
+ Class<?> unsafeClass = Class.forName("sun.misc.Unsafe"); //$NON-NLS-1$
+ Field theUnsafe = unsafeClass.getDeclaredField("theUnsafe"); //$NON-NLS-1$
+
+ // NOTE: deep reflection is allowed on sun.misc package for java 9.
+ theUnsafe.setAccessible(true);
+ Object unsafe = theUnsafe.get(null);
+
+ // using defineAnonymousClass here because it seems more simple to get what we need
+ Method defineAnonymousClass = unsafeClass.getMethod("defineAnonymousClass", Class.class, byte[].class, Object[].class); //$NON-NLS-1$
+ // The SetAccessible bytes stored in a resource to avoid real loading of it (see SetAccessible.java.src for source).
+ String tResource = "SetAccessible.bytes"; //$NON-NLS-1$
+
+ byte[] bytes = StorageUtil.getBytes(MultiplexingFactory.class.getResource(tResource).openStream(), -1, 4000);
+ @SuppressWarnings("unchecked")
+ Class<Collection<AccessibleObject>> clazz = (Class<Collection<AccessibleObject>>) defineAnonymousClass.invoke(unsafe, URL.class, bytes, (Object[]) null);
+ result = clazz.getConstructor().newInstance();
+ } catch (Throwable t) {
+ t.printStackTrace();
+ // ingore as if there is no Unsafe
+ }
+ setAccessible = result;
+ }
protected EquinoxContainer container;
protected BundleContext context;
private List<Object> factories; // list of multiplexed factories
@@ -167,4 +209,12 @@ public abstract class MultiplexingFactory {
updated.remove(factory);
factories = updated.isEmpty() ? null : updated;
}
+
+ static void setAccessible(AccessibleObject o) {
+ if (setAccessible != null) {
+ setAccessible.add(o);
+ } else {
+ o.setAccessible(true);
+ }
+ }
}
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/url/MultiplexingURLStreamHandler.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/url/MultiplexingURLStreamHandler.java
index c82ab15ed..19f25b771 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/url/MultiplexingURLStreamHandler.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/url/MultiplexingURLStreamHandler.java
@@ -38,37 +38,37 @@ public class MultiplexingURLStreamHandler extends URLStreamHandler {
return;
try {
openConnectionMethod = URLStreamHandler.class.getDeclaredMethod("openConnection", new Class[] {URL.class}); //$NON-NLS-1$
- openConnectionMethod.setAccessible(true);
+ MultiplexingFactory.setAccessible(openConnectionMethod);
openConnectionProxyMethod = URLStreamHandler.class.getDeclaredMethod("openConnection", new Class[] {URL.class, Proxy.class}); //$NON-NLS-1$
- openConnectionProxyMethod.setAccessible(true);
+ MultiplexingFactory.setAccessible(openConnectionProxyMethod);
equalsMethod = URLStreamHandler.class.getDeclaredMethod("equals", new Class[] {URL.class, URL.class}); //$NON-NLS-1$
- equalsMethod.setAccessible(true);
+ MultiplexingFactory.setAccessible(equalsMethod);
getDefaultPortMethod = URLStreamHandler.class.getDeclaredMethod("getDefaultPort", (Class[]) null); //$NON-NLS-1$
- getDefaultPortMethod.setAccessible(true);
+ MultiplexingFactory.setAccessible(getDefaultPortMethod);
getHostAddressMethod = URLStreamHandler.class.getDeclaredMethod("getHostAddress", new Class[] {URL.class}); //$NON-NLS-1$
- getHostAddressMethod.setAccessible(true);
+ MultiplexingFactory.setAccessible(getHostAddressMethod);
hashCodeMethod = URLStreamHandler.class.getDeclaredMethod("hashCode", new Class[] {URL.class}); //$NON-NLS-1$
- hashCodeMethod.setAccessible(true);
+ MultiplexingFactory.setAccessible(hashCodeMethod);
hostsEqualMethod = URLStreamHandler.class.getDeclaredMethod("hostsEqual", new Class[] {URL.class, URL.class}); //$NON-NLS-1$
- hostsEqualMethod.setAccessible(true);
+ MultiplexingFactory.setAccessible(hostsEqualMethod);
parseURLMethod = URLStreamHandler.class.getDeclaredMethod("parseURL", new Class[] {URL.class, String.class, Integer.TYPE, Integer.TYPE}); //$NON-NLS-1$
- parseURLMethod.setAccessible(true);
+ MultiplexingFactory.setAccessible(parseURLMethod);
sameFileMethod = URLStreamHandler.class.getDeclaredMethod("sameFile", new Class[] {URL.class, URL.class}); //$NON-NLS-1$
- sameFileMethod.setAccessible(true);
+ MultiplexingFactory.setAccessible(sameFileMethod);
setURLMethod = URLStreamHandler.class.getDeclaredMethod("setURL", new Class[] {URL.class, String.class, String.class, Integer.TYPE, String.class, String.class, String.class, String.class, String.class}); //$NON-NLS-1$
- setURLMethod.setAccessible(true);
+ MultiplexingFactory.setAccessible(setURLMethod);
toExternalFormMethod = URLStreamHandler.class.getDeclaredMethod("toExternalForm", new Class[] {URL.class}); //$NON-NLS-1$
- toExternalFormMethod.setAccessible(true);
+ MultiplexingFactory.setAccessible(toExternalFormMethod);
try {
handlerField = URL.class.getDeclaredField("handler"); //$NON-NLS-1$
@@ -77,7 +77,7 @@ public class MultiplexingURLStreamHandler extends URLStreamHandler {
if (handlerField == null)
throw e;
}
- handlerField.setAccessible(true);
+ MultiplexingFactory.setAccessible(handlerField);
} catch (Exception e) {
factory.container.getLogServices().log(MultiplexingURLStreamHandler.class.getName(), FrameworkLogEntry.ERROR, "initializeMethods", e); //$NON-NLS-1$
throw new RuntimeException(e.getMessage(), e);
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/url/SetAccessible.bytes b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/url/SetAccessible.bytes
new file mode 100644
index 000000000..5752a1bee
--- /dev/null
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/url/SetAccessible.bytes
Binary files differ
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/url/SetAccessible.java.src b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/url/SetAccessible.java.src
new file mode 100644
index 000000000..0dbd62421
--- /dev/null
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/url/SetAccessible.java.src
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2016 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ *******************************************************************************/
+package java.net;
+
+import java.lang.reflect.AccessibleObject;
+import java.util.Collection;
+import java.util.Iterator;
+
+public class SetAccessible implements Collection<AccessibleObject> {
+ // playing tricks to get around reflecting in java.net package on java 9
+ @Override
+ public boolean add(AccessibleObject e) {
+ e.setAccessible(true);
+ return true;
+ }
+
+ @Override
+ public int size() {
+ return 0;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return false;
+ }
+
+ @Override
+ public boolean contains(Object o) {
+ return false;
+ }
+
+ @Override
+ public Iterator<AccessibleObject> iterator() {
+ return null;
+ }
+
+ @Override
+ public Object[] toArray() {
+ return null;
+ }
+
+ @Override
+ public <T> T[] toArray(T[] a) {
+ return null;
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ return false;
+ }
+
+ @Override
+ public boolean containsAll(Collection<?> c) {
+ return false;
+ }
+
+ @Override
+ public boolean addAll(Collection<? extends AccessibleObject> c) {
+ return false;
+ }
+
+ @Override
+ public boolean removeAll(Collection<?> c) {
+ return false;
+ }
+
+ @Override
+ public boolean retainAll(Collection<?> c) {
+ return false;
+ }
+
+ @Override
+ public void clear() {
+ // nothing
+ }
+
+}

Back to the top