Merge
This commit is contained in:
commit
d7509c02b3
@ -39,7 +39,6 @@ TOOL_GENGRAPHS := $(BUILD_JAVA) -esa -ea -cp $(TOOLS_CLASSES_DIR) \
|
||||
build.tools.jigsaw.GenGraphs
|
||||
|
||||
TOOL_MODULESUMMARY := $(BUILD_JAVA) -esa -ea -cp $(TOOLS_CLASSES_DIR) \
|
||||
--add-exports jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED \
|
||||
build.tools.jigsaw.ModuleSummary
|
||||
|
||||
TOOL_ADD_PACKAGES_ATTRIBUTE := $(BUILD_JAVA) $(JAVA_FLAGS_SMALL) \
|
||||
|
@ -508,8 +508,9 @@ public final class Class<T> implements java.io.Serializable,
|
||||
public T newInstance()
|
||||
throws InstantiationException, IllegalAccessException
|
||||
{
|
||||
if (System.getSecurityManager() != null) {
|
||||
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
checkMemberAccess(sm, Member.PUBLIC, Reflection.getCallerClass(), false);
|
||||
}
|
||||
|
||||
// NOTE: the following code may not be strictly correct under
|
||||
@ -1223,38 +1224,27 @@ public final class Class<T> implements java.io.Serializable,
|
||||
|
||||
// Perform access check
|
||||
final Class<?> enclosingCandidate = enclosingInfo.getEnclosingClass();
|
||||
enclosingCandidate.checkMemberAccess(Member.DECLARED,
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
enclosingCandidate.checkMemberAccess(sm, Member.DECLARED,
|
||||
Reflection.getCallerClass(), true);
|
||||
// Client is ok to access declared methods but j.l.Class might not be.
|
||||
Method[] candidates = AccessController.doPrivileged(
|
||||
new PrivilegedAction<>() {
|
||||
@Override
|
||||
public Method[] run() {
|
||||
return enclosingCandidate.getDeclaredMethods();
|
||||
}
|
||||
});
|
||||
Method[] candidates = enclosingCandidate.privateGetDeclaredMethods(false);
|
||||
|
||||
/*
|
||||
* Loop over all declared methods; match method name,
|
||||
* number of and type of parameters, *and* return
|
||||
* type. Matching return type is also necessary
|
||||
* because of covariant returns, etc.
|
||||
*/
|
||||
ReflectionFactory fact = getReflectionFactory();
|
||||
for (Method m : candidates) {
|
||||
if (m.getName().equals(enclosingInfo.getName()) ) {
|
||||
Class<?>[] candidateParamClasses = m.getParameterTypes();
|
||||
if (candidateParamClasses.length == parameterClasses.length) {
|
||||
boolean matches = true;
|
||||
for(int i = 0; i < candidateParamClasses.length; i++) {
|
||||
if (!candidateParamClasses[i].equals(parameterClasses[i])) {
|
||||
matches = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (matches) { // finally, check return type
|
||||
if (m.getReturnType().equals(returnType) )
|
||||
return m;
|
||||
}
|
||||
if (m.getName().equals(enclosingInfo.getName()) &&
|
||||
arrayContentsEq(parameterClasses,
|
||||
fact.getExecutableSharedParameterTypes(m))) {
|
||||
// finally, check return type
|
||||
if (m.getReturnType().equals(returnType)) {
|
||||
return fact.copyMethod(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1390,33 +1380,23 @@ public final class Class<T> implements java.io.Serializable,
|
||||
|
||||
// Perform access check
|
||||
final Class<?> enclosingCandidate = enclosingInfo.getEnclosingClass();
|
||||
enclosingCandidate.checkMemberAccess(Member.DECLARED,
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
enclosingCandidate.checkMemberAccess(sm, Member.DECLARED,
|
||||
Reflection.getCallerClass(), true);
|
||||
// Client is ok to access declared methods but j.l.Class might not be.
|
||||
Constructor<?>[] candidates = AccessController.doPrivileged(
|
||||
new PrivilegedAction<>() {
|
||||
@Override
|
||||
public Constructor<?>[] run() {
|
||||
return enclosingCandidate.getDeclaredConstructors();
|
||||
}
|
||||
});
|
||||
|
||||
Constructor<?>[] candidates = enclosingCandidate
|
||||
.privateGetDeclaredConstructors(false);
|
||||
/*
|
||||
* Loop over all declared constructors; match number
|
||||
* of and type of parameters.
|
||||
*/
|
||||
ReflectionFactory fact = getReflectionFactory();
|
||||
for (Constructor<?> c : candidates) {
|
||||
Class<?>[] candidateParamClasses = c.getParameterTypes();
|
||||
if (candidateParamClasses.length == parameterClasses.length) {
|
||||
boolean matches = true;
|
||||
for(int i = 0; i < candidateParamClasses.length; i++) {
|
||||
if (!candidateParamClasses[i].equals(parameterClasses[i])) {
|
||||
matches = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (matches)
|
||||
return c;
|
||||
if (arrayContentsEq(parameterClasses,
|
||||
fact.getExecutableSharedParameterTypes(c))) {
|
||||
return fact.copyConstructor(c);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1446,9 +1426,13 @@ public final class Class<T> implements java.io.Serializable,
|
||||
public Class<?> getDeclaringClass() throws SecurityException {
|
||||
final Class<?> candidate = getDeclaringClass0();
|
||||
|
||||
if (candidate != null)
|
||||
candidate.checkPackageAccess(
|
||||
if (candidate != null) {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
candidate.checkPackageAccess(sm,
|
||||
ClassLoader.getClassLoader(Reflection.getCallerClass()), true);
|
||||
}
|
||||
}
|
||||
return candidate;
|
||||
}
|
||||
|
||||
@ -1496,9 +1480,13 @@ public final class Class<T> implements java.io.Serializable,
|
||||
enclosingCandidate = enclosingClass;
|
||||
}
|
||||
|
||||
if (enclosingCandidate != null)
|
||||
enclosingCandidate.checkPackageAccess(
|
||||
if (enclosingCandidate != null) {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
enclosingCandidate.checkPackageAccess(sm,
|
||||
ClassLoader.getClassLoader(Reflection.getCallerClass()), true);
|
||||
}
|
||||
}
|
||||
return enclosingCandidate;
|
||||
}
|
||||
|
||||
@ -1688,7 +1676,10 @@ public final class Class<T> implements java.io.Serializable,
|
||||
*/
|
||||
@CallerSensitive
|
||||
public Class<?>[] getClasses() {
|
||||
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
checkMemberAccess(sm, Member.PUBLIC, Reflection.getCallerClass(), false);
|
||||
}
|
||||
|
||||
// Privileged so this implementation can look at DECLARED classes,
|
||||
// something the caller might not have privilege to do. The code here
|
||||
@ -1754,7 +1745,10 @@ public final class Class<T> implements java.io.Serializable,
|
||||
*/
|
||||
@CallerSensitive
|
||||
public Field[] getFields() throws SecurityException {
|
||||
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
checkMemberAccess(sm, Member.PUBLIC, Reflection.getCallerClass(), true);
|
||||
}
|
||||
return copyFields(privateGetPublicFields(null));
|
||||
}
|
||||
|
||||
@ -1841,7 +1835,10 @@ public final class Class<T> implements java.io.Serializable,
|
||||
*/
|
||||
@CallerSensitive
|
||||
public Method[] getMethods() throws SecurityException {
|
||||
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
checkMemberAccess(sm, Member.PUBLIC, Reflection.getCallerClass(), true);
|
||||
}
|
||||
return copyMethods(privateGetPublicMethods());
|
||||
}
|
||||
|
||||
@ -1877,7 +1874,10 @@ public final class Class<T> implements java.io.Serializable,
|
||||
*/
|
||||
@CallerSensitive
|
||||
public Constructor<?>[] getConstructors() throws SecurityException {
|
||||
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
checkMemberAccess(sm, Member.PUBLIC, Reflection.getCallerClass(), true);
|
||||
}
|
||||
return copyConstructors(privateGetDeclaredConstructors(true));
|
||||
}
|
||||
|
||||
@ -1928,7 +1928,10 @@ public final class Class<T> implements java.io.Serializable,
|
||||
public Field getField(String name)
|
||||
throws NoSuchFieldException, SecurityException {
|
||||
Objects.requireNonNull(name);
|
||||
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
checkMemberAccess(sm, Member.PUBLIC, Reflection.getCallerClass(), true);
|
||||
}
|
||||
Field field = getField0(name);
|
||||
if (field == null) {
|
||||
throw new NoSuchFieldException(name);
|
||||
@ -2034,10 +2037,13 @@ public final class Class<T> implements java.io.Serializable,
|
||||
public Method getMethod(String name, Class<?>... parameterTypes)
|
||||
throws NoSuchMethodException, SecurityException {
|
||||
Objects.requireNonNull(name);
|
||||
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
checkMemberAccess(sm, Member.PUBLIC, Reflection.getCallerClass(), true);
|
||||
}
|
||||
Method method = getMethod0(name, parameterTypes);
|
||||
if (method == null) {
|
||||
throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
|
||||
throw new NoSuchMethodException(methodToString(name, parameterTypes));
|
||||
}
|
||||
return getReflectionFactory().copyMethod(method);
|
||||
}
|
||||
@ -2092,8 +2098,12 @@ public final class Class<T> implements java.io.Serializable,
|
||||
*/
|
||||
@CallerSensitive
|
||||
public Constructor<T> getConstructor(Class<?>... parameterTypes)
|
||||
throws NoSuchMethodException, SecurityException {
|
||||
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
|
||||
throws NoSuchMethodException, SecurityException
|
||||
{
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
checkMemberAccess(sm, Member.PUBLIC, Reflection.getCallerClass(), true);
|
||||
}
|
||||
return getReflectionFactory().copyConstructor(
|
||||
getConstructor0(parameterTypes, Member.PUBLIC));
|
||||
}
|
||||
@ -2136,7 +2146,10 @@ public final class Class<T> implements java.io.Serializable,
|
||||
*/
|
||||
@CallerSensitive
|
||||
public Class<?>[] getDeclaredClasses() throws SecurityException {
|
||||
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), false);
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
checkMemberAccess(sm, Member.DECLARED, Reflection.getCallerClass(), false);
|
||||
}
|
||||
return getDeclaredClasses0();
|
||||
}
|
||||
|
||||
@ -2185,7 +2198,10 @@ public final class Class<T> implements java.io.Serializable,
|
||||
*/
|
||||
@CallerSensitive
|
||||
public Field[] getDeclaredFields() throws SecurityException {
|
||||
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
checkMemberAccess(sm, Member.DECLARED, Reflection.getCallerClass(), true);
|
||||
}
|
||||
return copyFields(privateGetDeclaredFields(false));
|
||||
}
|
||||
|
||||
@ -2244,7 +2260,10 @@ public final class Class<T> implements java.io.Serializable,
|
||||
*/
|
||||
@CallerSensitive
|
||||
public Method[] getDeclaredMethods() throws SecurityException {
|
||||
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
checkMemberAccess(sm, Member.DECLARED, Reflection.getCallerClass(), true);
|
||||
}
|
||||
return copyMethods(privateGetDeclaredMethods(false));
|
||||
}
|
||||
|
||||
@ -2289,7 +2308,10 @@ public final class Class<T> implements java.io.Serializable,
|
||||
*/
|
||||
@CallerSensitive
|
||||
public Constructor<?>[] getDeclaredConstructors() throws SecurityException {
|
||||
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
checkMemberAccess(sm, Member.DECLARED, Reflection.getCallerClass(), true);
|
||||
}
|
||||
return copyConstructors(privateGetDeclaredConstructors(false));
|
||||
}
|
||||
|
||||
@ -2338,7 +2360,10 @@ public final class Class<T> implements java.io.Serializable,
|
||||
public Field getDeclaredField(String name)
|
||||
throws NoSuchFieldException, SecurityException {
|
||||
Objects.requireNonNull(name);
|
||||
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
checkMemberAccess(sm, Member.DECLARED, Reflection.getCallerClass(), true);
|
||||
}
|
||||
Field field = searchFields(privateGetDeclaredFields(false), name);
|
||||
if (field == null) {
|
||||
throw new NoSuchFieldException(name);
|
||||
@ -2399,10 +2424,13 @@ public final class Class<T> implements java.io.Serializable,
|
||||
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
|
||||
throws NoSuchMethodException, SecurityException {
|
||||
Objects.requireNonNull(name);
|
||||
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
checkMemberAccess(sm, Member.DECLARED, Reflection.getCallerClass(), true);
|
||||
}
|
||||
Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes);
|
||||
if (method == null) {
|
||||
throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
|
||||
throw new NoSuchMethodException(methodToString(name, parameterTypes));
|
||||
}
|
||||
return getReflectionFactory().copyMethod(method);
|
||||
}
|
||||
@ -2448,8 +2476,13 @@ public final class Class<T> implements java.io.Serializable,
|
||||
*/
|
||||
@CallerSensitive
|
||||
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
|
||||
throws NoSuchMethodException, SecurityException {
|
||||
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
|
||||
throws NoSuchMethodException, SecurityException
|
||||
{
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
checkMemberAccess(sm, Member.DECLARED, Reflection.getCallerClass(), true);
|
||||
}
|
||||
|
||||
return getReflectionFactory().copyConstructor(
|
||||
getConstructor0(parameterTypes, Member.DECLARED));
|
||||
}
|
||||
@ -2697,44 +2730,43 @@ public final class Class<T> implements java.io.Serializable,
|
||||
*
|
||||
* <p> Default policy: allow all clients access with normal Java access
|
||||
* control.
|
||||
*
|
||||
* <p> NOTE: should only be called if a SecurityManager is installed
|
||||
*/
|
||||
private void checkMemberAccess(int which, Class<?> caller, boolean checkProxyInterfaces) {
|
||||
final SecurityManager s = System.getSecurityManager();
|
||||
if (s != null) {
|
||||
private void checkMemberAccess(SecurityManager sm, int which,
|
||||
Class<?> caller, boolean checkProxyInterfaces) {
|
||||
/* Default policy allows access to all {@link Member#PUBLIC} members,
|
||||
* as well as access to classes that have the same class loader as the caller.
|
||||
* In all other cases, it requires RuntimePermission("accessDeclaredMembers")
|
||||
* permission.
|
||||
*/
|
||||
final ClassLoader ccl = ClassLoader.getClassLoader(caller);
|
||||
final ClassLoader cl = getClassLoader0();
|
||||
final ClassLoader ccl = caller.getClassLoader0();
|
||||
if (which != Member.PUBLIC) {
|
||||
final ClassLoader cl = getClassLoader0();
|
||||
if (ccl != cl) {
|
||||
s.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);
|
||||
sm.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);
|
||||
}
|
||||
}
|
||||
this.checkPackageAccess(ccl, checkProxyInterfaces);
|
||||
}
|
||||
this.checkPackageAccess(sm, ccl, checkProxyInterfaces);
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if a client loaded in ClassLoader ccl is allowed to access this
|
||||
* class under the current package access policy. If access is denied,
|
||||
* throw a SecurityException.
|
||||
*
|
||||
* NOTE: this method should only be called if a SecurityManager is active
|
||||
*/
|
||||
private void checkPackageAccess(final ClassLoader ccl, boolean checkProxyInterfaces) {
|
||||
final SecurityManager s = System.getSecurityManager();
|
||||
if (s != null) {
|
||||
private void checkPackageAccess(SecurityManager sm, final ClassLoader ccl,
|
||||
boolean checkProxyInterfaces) {
|
||||
final ClassLoader cl = getClassLoader0();
|
||||
|
||||
if (ReflectUtil.needsPackageAccessCheck(ccl, cl)) {
|
||||
String name = this.getName();
|
||||
int i = name.lastIndexOf('.');
|
||||
if (i != -1) {
|
||||
String pkg = this.getPackageName();
|
||||
if (pkg != null && !pkg.isEmpty()) {
|
||||
// skip the package access check on a proxy class in default proxy package
|
||||
String pkg = name.substring(0, i);
|
||||
if (!Proxy.isProxyClass(this) || ReflectUtil.isNonPublicProxyClass(this)) {
|
||||
s.checkPackageAccess(pkg);
|
||||
sm.checkPackageAccess(pkg);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2743,7 +2775,6 @@ public final class Class<T> implements java.io.Serializable,
|
||||
ReflectUtil.checkProxyPackageAccess(ccl, this.getInterfaces());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a package name prefix if the name is not absolute Remove leading "/"
|
||||
@ -2755,11 +2786,9 @@ public final class Class<T> implements java.io.Serializable,
|
||||
while (c.isArray()) {
|
||||
c = c.getComponentType();
|
||||
}
|
||||
String baseName = c.getName();
|
||||
int index = baseName.lastIndexOf('.');
|
||||
if (index != -1) {
|
||||
name = baseName.substring(0, index).replace('.', '/')
|
||||
+"/"+name;
|
||||
String baseName = c.getPackageName();
|
||||
if (baseName != null && !baseName.isEmpty()) {
|
||||
name = baseName.replace('.', '/') + "/" + name;
|
||||
}
|
||||
} else {
|
||||
name = name.substring(1);
|
||||
@ -3233,7 +3262,7 @@ public final class Class<T> implements java.io.Serializable,
|
||||
return constructor;
|
||||
}
|
||||
}
|
||||
throw new NoSuchMethodException(getName() + ".<init>" + argumentTypesToString(parameterTypes));
|
||||
throw new NoSuchMethodException(methodToString("<init>", parameterTypes));
|
||||
}
|
||||
|
||||
//
|
||||
@ -3294,8 +3323,11 @@ public final class Class<T> implements java.io.Serializable,
|
||||
private native Constructor<T>[] getDeclaredConstructors0(boolean publicOnly);
|
||||
private native Class<?>[] getDeclaredClasses0();
|
||||
|
||||
private static String argumentTypesToString(Class<?>[] argTypes) {
|
||||
StringJoiner sj = new StringJoiner(", ", "(", ")");
|
||||
/**
|
||||
* Helper method to get the method name from arguments.
|
||||
*/
|
||||
private String methodToString(String name, Class<?>[] argTypes) {
|
||||
StringJoiner sj = new StringJoiner(", ", getName() + "." + name + "(", ")");
|
||||
if (argTypes != null) {
|
||||
for (int i = 0; i < argTypes.length; i++) {
|
||||
Class<?> c = argTypes[i];
|
||||
|
@ -28,6 +28,8 @@ package java.lang.invoke;
|
||||
import static java.lang.invoke.MethodHandleStatics.*;
|
||||
import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
|
||||
/**
|
||||
* A {@code CallSite} is a holder for a variable {@link MethodHandle},
|
||||
* which is called its {@code target}.
|
||||
@ -215,19 +217,36 @@ public class CallSite {
|
||||
public abstract MethodHandle dynamicInvoker();
|
||||
|
||||
/*non-public*/ MethodHandle makeDynamicInvoker() {
|
||||
MethodHandle getTarget = GET_TARGET.bindArgumentL(0, this);
|
||||
MethodHandle getTarget = getTargetHandle().bindArgumentL(0, this);
|
||||
MethodHandle invoker = MethodHandles.exactInvoker(this.type());
|
||||
return MethodHandles.foldArguments(invoker, getTarget);
|
||||
}
|
||||
|
||||
private static final MethodHandle GET_TARGET;
|
||||
private static final MethodHandle THROW_UCS;
|
||||
static {
|
||||
private static @Stable MethodHandle GET_TARGET;
|
||||
private static MethodHandle getTargetHandle() {
|
||||
MethodHandle handle = GET_TARGET;
|
||||
if (handle != null) {
|
||||
return handle;
|
||||
}
|
||||
try {
|
||||
GET_TARGET = IMPL_LOOKUP.
|
||||
findVirtual(CallSite.class, "getTarget", MethodType.methodType(MethodHandle.class));
|
||||
THROW_UCS = IMPL_LOOKUP.
|
||||
findStatic(CallSite.class, "uninitializedCallSite", MethodType.methodType(Object.class, Object[].class));
|
||||
return GET_TARGET = IMPL_LOOKUP.
|
||||
findVirtual(CallSite.class, "getTarget",
|
||||
MethodType.methodType(MethodHandle.class));
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw newInternalError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static @Stable MethodHandle THROW_UCS;
|
||||
private static MethodHandle uninitializedCallSiteHandle() {
|
||||
MethodHandle handle = THROW_UCS;
|
||||
if (handle != null) {
|
||||
return handle;
|
||||
}
|
||||
try {
|
||||
return THROW_UCS = IMPL_LOOKUP.
|
||||
findStatic(CallSite.class, "uninitializedCallSite",
|
||||
MethodType.methodType(Object.class, Object[].class));
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw newInternalError(e);
|
||||
}
|
||||
@ -242,7 +261,7 @@ public class CallSite {
|
||||
MethodType basicType = targetType.basicType();
|
||||
MethodHandle invoker = basicType.form().cachedMethodHandle(MethodTypeForm.MH_UNINIT_CS);
|
||||
if (invoker == null) {
|
||||
invoker = THROW_UCS.asType(basicType);
|
||||
invoker = uninitializedCallSiteHandle().asType(basicType);
|
||||
invoker = basicType.form().setCachedMethodHandle(MethodTypeForm.MH_UNINIT_CS, invoker);
|
||||
}
|
||||
// unchecked view is OK since no values will be received or returned
|
||||
@ -250,12 +269,16 @@ public class CallSite {
|
||||
}
|
||||
|
||||
// unsafe stuff:
|
||||
private static final long TARGET_OFFSET;
|
||||
private static final long CONTEXT_OFFSET;
|
||||
static {
|
||||
private static @Stable long TARGET_OFFSET;
|
||||
private static long getTargetOffset() {
|
||||
long offset = TARGET_OFFSET;
|
||||
if (offset > 0) {
|
||||
return offset;
|
||||
}
|
||||
try {
|
||||
TARGET_OFFSET = UNSAFE.objectFieldOffset(CallSite.class.getDeclaredField("target"));
|
||||
CONTEXT_OFFSET = UNSAFE.objectFieldOffset(CallSite.class.getDeclaredField("context"));
|
||||
offset = TARGET_OFFSET = UNSAFE.objectFieldOffset(CallSite.class.getDeclaredField("target"));
|
||||
assert(offset > 0);
|
||||
return offset;
|
||||
} catch (Exception ex) { throw newInternalError(ex); }
|
||||
}
|
||||
|
||||
@ -265,7 +288,7 @@ public class CallSite {
|
||||
}
|
||||
/*package-private*/
|
||||
MethodHandle getTargetVolatile() {
|
||||
return (MethodHandle) UNSAFE.getObjectVolatile(this, TARGET_OFFSET);
|
||||
return (MethodHandle) UNSAFE.getObjectVolatile(this, getTargetOffset());
|
||||
}
|
||||
/*package-private*/
|
||||
void setTargetVolatile(MethodHandle newTarget) {
|
||||
@ -324,7 +347,7 @@ public class CallSite {
|
||||
final int NON_SPREAD_ARG_COUNT = 3; // (caller, name, type)
|
||||
if (NON_SPREAD_ARG_COUNT + argv.length > MethodType.MAX_MH_ARITY)
|
||||
throw new BootstrapMethodError("too many bootstrap method arguments");
|
||||
MethodType bsmType = bootstrapMethod.type();
|
||||
|
||||
MethodType invocationType = MethodType.genericMethodType(NON_SPREAD_ARG_COUNT + argv.length);
|
||||
MethodHandle typedBSM = bootstrapMethod.asType(invocationType);
|
||||
MethodHandle spreader = invocationType.invokers().spreadInvoker(NON_SPREAD_ARG_COUNT);
|
||||
|
@ -1128,7 +1128,7 @@ class MethodType implements java.io.Serializable {
|
||||
public String toMethodDescriptorString() {
|
||||
String desc = methodDescriptor;
|
||||
if (desc == null) {
|
||||
desc = BytecodeDescriptor.unparse(this);
|
||||
desc = BytecodeDescriptor.unparseMethod(this.rtype, this.ptypes);
|
||||
methodDescriptor = desc;
|
||||
}
|
||||
return desc;
|
||||
@ -1256,7 +1256,7 @@ s.writeObject(this.parameterArray());
|
||||
private final ReferenceQueue<T> stale;
|
||||
|
||||
public ConcurrentWeakInternSet() {
|
||||
this.map = new ConcurrentHashMap<>();
|
||||
this.map = new ConcurrentHashMap<>(512);
|
||||
this.stale = new ReferenceQueue<>();
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -2134,7 +2134,7 @@ public abstract class ResourceBundle {
|
||||
|
||||
/**
|
||||
* Removes all resource bundles from the cache that have been loaded
|
||||
* by the caller's module using the caller's class loader.
|
||||
* by the caller's module.
|
||||
*
|
||||
* @since 1.6
|
||||
* @see ResourceBundle.Control#getTimeToLive(String,Locale)
|
||||
@ -2142,50 +2142,26 @@ public abstract class ResourceBundle {
|
||||
@CallerSensitive
|
||||
public static final void clearCache() {
|
||||
Class<?> caller = Reflection.getCallerClass();
|
||||
clearCacheImpl(caller.getModule(), caller.getClassLoader());
|
||||
cacheList.keySet().removeIf(
|
||||
key -> key.getCallerModule() == caller.getModule()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all resource bundles from the cache that have been loaded
|
||||
* by the caller's module using the given class loader.
|
||||
* by the given class loader.
|
||||
*
|
||||
* @param loader the class loader
|
||||
* @exception NullPointerException if <code>loader</code> is null
|
||||
* @since 1.6
|
||||
* @see ResourceBundle.Control#getTimeToLive(String,Locale)
|
||||
*/
|
||||
@CallerSensitive
|
||||
public static final void clearCache(ClassLoader loader) {
|
||||
Objects.requireNonNull(loader);
|
||||
Class<?> caller = Reflection.getCallerClass();
|
||||
clearCacheImpl(caller.getModule(), loader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all resource bundles from the cache that have been loaded by the
|
||||
* given {@code module}.
|
||||
*
|
||||
* @param module the module
|
||||
* @throws NullPointerException
|
||||
* if {@code module} is {@code null}
|
||||
* @throws SecurityException
|
||||
* if the caller doesn't have the permission to
|
||||
* {@linkplain Module#getClassLoader() get the class loader}
|
||||
* of the given {@code module}
|
||||
* @since 9
|
||||
* @see ResourceBundle.Control#getTimeToLive(String,Locale)
|
||||
*/
|
||||
public static final void clearCache(Module module) {
|
||||
Objects.requireNonNull(module);
|
||||
clearCacheImpl(module, module.getClassLoader());
|
||||
}
|
||||
|
||||
private static void clearCacheImpl(Module callerModule, ClassLoader loader) {
|
||||
cacheList.keySet().removeIf(
|
||||
key -> {
|
||||
Module m;
|
||||
return key.getCallerModule() == callerModule &&
|
||||
(m = key.getModule()) != null &&
|
||||
return (m = key.getModule()) != null &&
|
||||
getLoader(m) == loader;
|
||||
}
|
||||
);
|
||||
|
@ -96,7 +96,7 @@ public final class ReflectUtil {
|
||||
|
||||
final Class<?> declaringClass = m.getDeclaringClass();
|
||||
|
||||
checkPackageAccess(declaringClass);
|
||||
privateCheckPackageAccess(sm, declaringClass);
|
||||
|
||||
if (Modifier.isPublic(m.getModifiers()) &&
|
||||
Modifier.isPublic(declaringClass.getModifiers()))
|
||||
@ -114,9 +114,27 @@ public final class ReflectUtil {
|
||||
* also check the package access on the proxy interfaces.
|
||||
*/
|
||||
public static void checkPackageAccess(Class<?> clazz) {
|
||||
checkPackageAccess(clazz.getName());
|
||||
SecurityManager s = System.getSecurityManager();
|
||||
if (s != null) {
|
||||
privateCheckPackageAccess(s, clazz);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE: should only be called if a SecurityManager is installed
|
||||
*/
|
||||
private static void privateCheckPackageAccess(SecurityManager s, Class<?> clazz) {
|
||||
while (clazz.isArray()) {
|
||||
clazz = clazz.getComponentType();
|
||||
}
|
||||
|
||||
String pkg = clazz.getPackageName();
|
||||
if (pkg != null && !pkg.isEmpty()) {
|
||||
s.checkPackageAccess(pkg);
|
||||
}
|
||||
|
||||
if (isNonPublicProxyClass(clazz)) {
|
||||
checkProxyPackageAccess(clazz);
|
||||
privateCheckProxyPackageAccess(s, clazz);
|
||||
}
|
||||
}
|
||||
|
||||
@ -195,15 +213,21 @@ public final class ReflectUtil {
|
||||
public static void checkProxyPackageAccess(Class<?> clazz) {
|
||||
SecurityManager s = System.getSecurityManager();
|
||||
if (s != null) {
|
||||
// check proxy interfaces if the given class is a proxy class
|
||||
if (Proxy.isProxyClass(clazz)) {
|
||||
for (Class<?> intf : clazz.getInterfaces()) {
|
||||
checkPackageAccess(intf);
|
||||
}
|
||||
}
|
||||
privateCheckProxyPackageAccess(s, clazz);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE: should only be called if a SecurityManager is installed
|
||||
*/
|
||||
private static void privateCheckProxyPackageAccess(SecurityManager s, Class<?> clazz) {
|
||||
// check proxy interfaces if the given class is a proxy class
|
||||
if (Proxy.isProxyClass(clazz)) {
|
||||
for (Class<?> intf : clazz.getInterfaces()) {
|
||||
privateCheckPackageAccess(s, intf);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Access check on the interfaces that a proxy class implements and throw
|
||||
* {@code SecurityException} if it accesses a restricted package from
|
||||
@ -220,7 +244,7 @@ public final class ReflectUtil {
|
||||
for (Class<?> intf : interfaces) {
|
||||
ClassLoader cl = intf.getClassLoader();
|
||||
if (needsPackageAccessCheck(ccl, cl)) {
|
||||
checkPackageAccess(intf);
|
||||
privateCheckPackageAccess(sm, intf);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -236,10 +260,11 @@ public final class ReflectUtil {
|
||||
* package that bypasses checkPackageAccess.
|
||||
*/
|
||||
public static boolean isNonPublicProxyClass(Class<?> cls) {
|
||||
String name = cls.getName();
|
||||
int i = name.lastIndexOf('.');
|
||||
String pkg = (i != -1) ? name.substring(0, i) : "";
|
||||
return Proxy.isProxyClass(cls) && !pkg.startsWith(PROXY_PACKAGE);
|
||||
if (!Proxy.isProxyClass(cls)) {
|
||||
return false;
|
||||
}
|
||||
String pkg = cls.getPackageName();
|
||||
return pkg == null || !pkg.startsWith(PROXY_PACKAGE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -165,18 +165,9 @@ public final class DefaultImageBuilder implements ImageBuilder {
|
||||
throw new PluginException("TargetPlatform attribute is missing for java.base module");
|
||||
}
|
||||
|
||||
Path bin = root.resolve(BIN_DIRNAME);
|
||||
checkResourcePool(files);
|
||||
|
||||
// check any duplicated resource files
|
||||
Map<Path, Set<String>> duplicates = new HashMap<>();
|
||||
files.entries()
|
||||
.filter(f -> f.type() != ResourcePoolEntry.Type.CLASS_OR_RESOURCE)
|
||||
.collect(groupingBy(this::entryToImagePath,
|
||||
mapping(ResourcePoolEntry::moduleName, toSet())))
|
||||
.entrySet()
|
||||
.stream()
|
||||
.filter(e -> e.getValue().size() > 1)
|
||||
.forEach(e -> duplicates.put(e.getKey(), e.getValue()));
|
||||
Path bin = root.resolve(BIN_DIRNAME);
|
||||
|
||||
// write non-classes resource files to the image
|
||||
files.entries()
|
||||
@ -185,13 +176,8 @@ public final class DefaultImageBuilder implements ImageBuilder {
|
||||
try {
|
||||
accept(f);
|
||||
} catch (FileAlreadyExistsException e) {
|
||||
// error for duplicated entries
|
||||
Path path = entryToImagePath(f);
|
||||
UncheckedIOException x =
|
||||
new UncheckedIOException(path + " duplicated in " +
|
||||
duplicates.get(path), e);
|
||||
x.addSuppressed(e);
|
||||
throw x;
|
||||
// Should not happen! Duplicates checking already done!
|
||||
throw new AssertionError("Duplicate entry!", e);
|
||||
} catch (IOException ioExp) {
|
||||
throw new UncheckedIOException(ioExp);
|
||||
}
|
||||
@ -242,6 +228,27 @@ public final class DefaultImageBuilder implements ImageBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
private void checkResourcePool(ResourcePool pool) {
|
||||
// For now, only duplicate resources check. Add more checks here (if any)
|
||||
checkDuplicateResources(pool);
|
||||
}
|
||||
|
||||
private void checkDuplicateResources(ResourcePool pool) {
|
||||
// check any duplicated resources
|
||||
Map<Path, Set<String>> duplicates = new HashMap<>();
|
||||
pool.entries()
|
||||
.filter(f -> f.type() != ResourcePoolEntry.Type.CLASS_OR_RESOURCE)
|
||||
.collect(groupingBy(this::entryToImagePath,
|
||||
mapping(ResourcePoolEntry::moduleName, toSet())))
|
||||
.entrySet()
|
||||
.stream()
|
||||
.filter(e -> e.getValue().size() > 1)
|
||||
.forEach(e -> duplicates.put(e.getKey(), e.getValue()));
|
||||
if (!duplicates.isEmpty()) {
|
||||
throw new PluginException("Duplicate resources: " + duplicates);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates launcher scripts.
|
||||
*
|
||||
|
@ -24,8 +24,6 @@
|
||||
*/
|
||||
|
||||
module jdk.jlink {
|
||||
exports jdk.tools.jlink.plugin;
|
||||
|
||||
requires jdk.internal.opt;
|
||||
requires jdk.jdeps;
|
||||
|
||||
|
@ -135,7 +135,7 @@ class JarFileSystem extends ZipFileSystem {
|
||||
TreeMap<Integer,IndexNode> map = new TreeMap<>();
|
||||
IndexNode child = metaInfVersions.child;
|
||||
while (child != null) {
|
||||
Integer key = getVersion(child.name, metaInfVersions.name.length);
|
||||
Integer key = getVersion(child.name, metaInfVersions.name.length + 1);
|
||||
if (key != null && key <= version) {
|
||||
map.put(key, child);
|
||||
}
|
||||
@ -149,7 +149,7 @@ class JarFileSystem extends ZipFileSystem {
|
||||
*/
|
||||
private Integer getVersion(byte[] name, int offset) {
|
||||
try {
|
||||
return Integer.parseInt(getString(Arrays.copyOfRange(name, offset, name.length-1)));
|
||||
return Integer.parseInt(getString(Arrays.copyOfRange(name, offset, name.length)));
|
||||
} catch (NumberFormatException x) {
|
||||
// ignore this even though it might indicate issues with the JAR structure
|
||||
return null;
|
||||
@ -176,7 +176,7 @@ class JarFileSystem extends ZipFileSystem {
|
||||
* returns foo/bar.class
|
||||
*/
|
||||
private byte[] getRootName(IndexNode prefix, IndexNode inode) {
|
||||
int offset = prefix.name.length - 1;
|
||||
int offset = prefix.name.length;
|
||||
byte[] fullName = inode.name;
|
||||
return Arrays.copyOfRange(fullName, offset, fullName.length);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -34,21 +34,56 @@ import java.nio.charset.CoderResult;
|
||||
import java.nio.charset.CodingErrorAction;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static java.nio.charset.StandardCharsets.ISO_8859_1;
|
||||
|
||||
/**
|
||||
* Utility class for zipfile name and comment decoding and encoding
|
||||
*
|
||||
* @author Xueming Shen
|
||||
*/
|
||||
|
||||
final class ZipCoder {
|
||||
class ZipCoder {
|
||||
|
||||
String toString(byte[] ba, int length) {
|
||||
static class UTF8 extends ZipCoder {
|
||||
UTF8() {
|
||||
super(UTF_8);
|
||||
}
|
||||
|
||||
@Override
|
||||
byte[] getBytes(String s) { // fast pass for ascii
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
if (s.charAt(i) > 0x7f) return super.getBytes(s);
|
||||
}
|
||||
return s.getBytes(ISO_8859_1);
|
||||
}
|
||||
|
||||
@Override
|
||||
String toString(byte[] ba) {
|
||||
for (byte b : ba) {
|
||||
if (b < 0) return super.toString(ba);
|
||||
}
|
||||
return new String(ba, ISO_8859_1);
|
||||
}
|
||||
}
|
||||
|
||||
private static ZipCoder utf8 = new UTF8();
|
||||
|
||||
public static ZipCoder get(String csn) {
|
||||
Charset cs = Charset.forName(csn);
|
||||
if (cs.name().equals("UTF-8")) {
|
||||
return utf8;
|
||||
}
|
||||
return new ZipCoder(cs);
|
||||
}
|
||||
|
||||
String toString(byte[] ba) {
|
||||
CharsetDecoder cd = decoder().reset();
|
||||
int len = (int)(length * cd.maxCharsPerByte());
|
||||
char[] ca = new char[len];
|
||||
if (len == 0)
|
||||
int clen = (int)(ba.length * cd.maxCharsPerByte());
|
||||
char[] ca = new char[clen];
|
||||
if (clen == 0)
|
||||
return new String(ca);
|
||||
ByteBuffer bb = ByteBuffer.wrap(ba, 0, length);
|
||||
ByteBuffer bb = ByteBuffer.wrap(ba, 0, ba.length);
|
||||
CharBuffer cb = CharBuffer.wrap(ca);
|
||||
CoderResult cr = cd.decode(bb, cb, true);
|
||||
if (!cr.isUnderflow())
|
||||
@ -59,10 +94,6 @@ final class ZipCoder {
|
||||
return new String(ca, 0, cb.position());
|
||||
}
|
||||
|
||||
String toString(byte[] ba) {
|
||||
return toString(ba, ba.length);
|
||||
}
|
||||
|
||||
byte[] getBytes(String s) {
|
||||
CharsetEncoder ce = encoder().reset();
|
||||
char[] ca = s.toCharArray();
|
||||
@ -84,47 +115,14 @@ final class ZipCoder {
|
||||
return Arrays.copyOf(ba, bb.position());
|
||||
}
|
||||
|
||||
// assume invoked only if "this" is not utf8
|
||||
byte[] getBytesUTF8(String s) {
|
||||
if (isutf8)
|
||||
return getBytes(s);
|
||||
if (utf8 == null)
|
||||
utf8 = new ZipCoder(Charset.forName("UTF-8"));
|
||||
return utf8.getBytes(s);
|
||||
}
|
||||
|
||||
String toStringUTF8(byte[] ba, int len) {
|
||||
if (isutf8)
|
||||
return toString(ba, len);
|
||||
if (utf8 == null)
|
||||
utf8 = new ZipCoder(Charset.forName("UTF-8"));
|
||||
return utf8.toString(ba, len);
|
||||
}
|
||||
|
||||
boolean isUTF8() {
|
||||
return isutf8;
|
||||
return cs == UTF_8;
|
||||
}
|
||||
|
||||
private Charset cs;
|
||||
private boolean isutf8;
|
||||
private ZipCoder utf8;
|
||||
|
||||
private ZipCoder(Charset cs) {
|
||||
this.cs = cs;
|
||||
this.isutf8 = cs.name().equals("UTF-8");
|
||||
}
|
||||
|
||||
static ZipCoder get(Charset charset) {
|
||||
return new ZipCoder(charset);
|
||||
}
|
||||
|
||||
static ZipCoder get(String csn) {
|
||||
try {
|
||||
return new ZipCoder(Charset.forName(csn));
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
return new ZipCoder(Charset.defaultCharset());
|
||||
}
|
||||
|
||||
private final ThreadLocal<CharsetDecoder> decTL = new ThreadLocal<>();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -314,7 +314,7 @@ class ZipFileSystem extends FileSystem {
|
||||
IndexNode inode = getInode(path);
|
||||
if (inode == null)
|
||||
return null;
|
||||
e = new Entry(inode.name); // pseudo directory
|
||||
e = new Entry(inode.name, inode.isdir); // pseudo directory
|
||||
e.method = METHOD_STORED; // STORED for dir
|
||||
e.mtime = e.atime = e.ctime = zfsDefaultTimeStamp;
|
||||
}
|
||||
@ -400,7 +400,8 @@ class ZipFileSystem extends FileSystem {
|
||||
List<Path> list = new ArrayList<>();
|
||||
IndexNode child = inode.child;
|
||||
while (child != null) {
|
||||
ZipPath zp = new ZipPath(this, child.name);
|
||||
// assume all path from zip file itself is "normalized"
|
||||
ZipPath zp = new ZipPath(this, child.name, true);
|
||||
if (filter == null || filter.accept(zp))
|
||||
list.add(zp);
|
||||
child = child.sibling;
|
||||
@ -415,14 +416,14 @@ class ZipFileSystem extends FileSystem {
|
||||
throws IOException
|
||||
{
|
||||
checkWritable();
|
||||
dir = toDirectoryPath(dir);
|
||||
// dir = toDirectoryPath(dir);
|
||||
beginWrite();
|
||||
try {
|
||||
ensureOpen();
|
||||
if (dir.length == 0 || exists(dir)) // root dir, or exiting dir
|
||||
throw new FileAlreadyExistsException(getString(dir));
|
||||
checkParents(dir);
|
||||
Entry e = new Entry(dir, Entry.NEW);
|
||||
Entry e = new Entry(dir, Entry.NEW, true);
|
||||
e.method = METHOD_STORED; // STORED for dir
|
||||
update(e);
|
||||
} finally {
|
||||
@ -533,7 +534,7 @@ class ZipFileSystem extends FileSystem {
|
||||
if (!hasCreate && !hasCreateNew)
|
||||
throw new NoSuchFileException(getString(path));
|
||||
checkParents(path);
|
||||
return getOutputStream(new Entry(path, Entry.NEW));
|
||||
return getOutputStream(new Entry(path, Entry.NEW, false));
|
||||
}
|
||||
} finally {
|
||||
endRead();
|
||||
@ -887,7 +888,7 @@ class ZipFileSystem extends FileSystem {
|
||||
int off = getParentOff(path);
|
||||
if (off <= 1)
|
||||
return ROOTPATH;
|
||||
return Arrays.copyOf(path, off + 1);
|
||||
return Arrays.copyOf(path, off);
|
||||
}
|
||||
|
||||
private static int getParentOff(byte[] path) {
|
||||
@ -1075,11 +1076,9 @@ class ZipFileSystem extends FileSystem {
|
||||
if (pos + CENHDR + nlen > limit) {
|
||||
zerror("invalid CEN header (bad header size)");
|
||||
}
|
||||
byte[] name = new byte[nlen + 1];
|
||||
System.arraycopy(cen, pos + CENHDR, name, 1, nlen);
|
||||
name[0] = '/';
|
||||
IndexNode inode = new IndexNode(name, pos);
|
||||
IndexNode inode = new IndexNode(cen, pos + CENHDR, nlen, pos);
|
||||
inodes.put(inode, inode);
|
||||
|
||||
// skip ext and comment
|
||||
pos += (CENHDR + nlen + elen + clen);
|
||||
}
|
||||
@ -1112,7 +1111,7 @@ class ZipFileSystem extends FileSystem {
|
||||
private boolean hasUpdate = false;
|
||||
|
||||
// shared key. consumer guarantees the "writeLock" before use it.
|
||||
private final IndexNode LOOKUPKEY = IndexNode.keyOf(null);
|
||||
private final IndexNode LOOKUPKEY = new IndexNode(null, -1);
|
||||
|
||||
private void updateDelete(IndexNode inode) {
|
||||
beginWrite();
|
||||
@ -1312,16 +1311,7 @@ class ZipFileSystem extends FileSystem {
|
||||
IndexNode getInode(byte[] path) {
|
||||
if (path == null)
|
||||
throw new NullPointerException("path");
|
||||
IndexNode key = IndexNode.keyOf(path);
|
||||
IndexNode inode = inodes.get(key);
|
||||
if (inode == null &&
|
||||
(path.length == 0 || path[path.length -1] != '/')) {
|
||||
// if does not ends with a slash
|
||||
path = Arrays.copyOf(path, path.length + 1);
|
||||
path[path.length - 1] = '/';
|
||||
inode = inodes.get(key.as(path));
|
||||
}
|
||||
return inode;
|
||||
return inodes.get(IndexNode.keyOf(path));
|
||||
}
|
||||
|
||||
Entry getEntry(byte[] path) throws IOException {
|
||||
@ -1782,8 +1772,11 @@ class ZipFileSystem extends FileSystem {
|
||||
int hashcode; // node is hashable/hashed by its name
|
||||
int pos = -1; // position in cen table, -1 menas the
|
||||
// entry does not exists in zip file
|
||||
IndexNode(byte[] name) {
|
||||
boolean isdir;
|
||||
|
||||
IndexNode(byte[] name, boolean isdir) {
|
||||
name(name);
|
||||
this.isdir = isdir;
|
||||
this.pos = -1;
|
||||
}
|
||||
|
||||
@ -1792,8 +1785,28 @@ class ZipFileSystem extends FileSystem {
|
||||
this.pos = pos;
|
||||
}
|
||||
|
||||
// constructor for cenInit()
|
||||
IndexNode(byte[] cen, int noff, int nlen, int pos) {
|
||||
if (cen[noff + nlen - 1] == '/') {
|
||||
isdir = true;
|
||||
nlen--;
|
||||
}
|
||||
name = new byte[nlen + 1];
|
||||
System.arraycopy(cen, pos + CENHDR, name, 1, nlen);
|
||||
name[0] = '/';
|
||||
name(name);
|
||||
this.pos = pos;
|
||||
}
|
||||
|
||||
private static final ThreadLocal<IndexNode> cachedKey = new ThreadLocal<>();
|
||||
|
||||
final static IndexNode keyOf(byte[] name) { // get a lookup key;
|
||||
return new IndexNode(name, -1);
|
||||
IndexNode key = cachedKey.get();
|
||||
if (key == null) {
|
||||
key = new IndexNode(name, -1);
|
||||
cachedKey.set(key);
|
||||
}
|
||||
return key.as(name);
|
||||
}
|
||||
|
||||
final void name(byte[] name) {
|
||||
@ -1807,8 +1820,7 @@ class ZipFileSystem extends FileSystem {
|
||||
}
|
||||
|
||||
boolean isDir() {
|
||||
return name != null &&
|
||||
(name.length == 0 || name[name.length - 1] == '/');
|
||||
return isdir;
|
||||
}
|
||||
|
||||
public boolean equals(Object other) {
|
||||
@ -1865,8 +1877,9 @@ class ZipFileSystem extends FileSystem {
|
||||
|
||||
Entry() {}
|
||||
|
||||
Entry(byte[] name) {
|
||||
Entry(byte[] name, boolean isdir) {
|
||||
name(name);
|
||||
this.isdir = isdir;
|
||||
this.mtime = this.ctime = this.atime = System.currentTimeMillis();
|
||||
this.crc = 0;
|
||||
this.size = 0;
|
||||
@ -1874,13 +1887,14 @@ class ZipFileSystem extends FileSystem {
|
||||
this.method = METHOD_DEFLATED;
|
||||
}
|
||||
|
||||
Entry(byte[] name, int type) {
|
||||
this(name);
|
||||
Entry(byte[] name, int type, boolean isdir) {
|
||||
this(name, isdir);
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
Entry (Entry e, int type) {
|
||||
name(e.name);
|
||||
this.isdir = e.isdir;
|
||||
this.version = e.version;
|
||||
this.ctime = e.ctime;
|
||||
this.atime = e.atime;
|
||||
@ -1902,7 +1916,7 @@ class ZipFileSystem extends FileSystem {
|
||||
}
|
||||
|
||||
Entry (byte[] name, Path file, int type) {
|
||||
this(name, type);
|
||||
this(name, type, false);
|
||||
this.file = file;
|
||||
this.method = METHOD_STORED;
|
||||
}
|
||||
@ -1948,6 +1962,7 @@ class ZipFileSystem extends FileSystem {
|
||||
locoff = CENOFF(cen, pos);
|
||||
pos += CENHDR;
|
||||
this.name = inode.name;
|
||||
this.isdir = inode.isdir;
|
||||
this.hashcode = inode.hashcode;
|
||||
|
||||
pos += nlen;
|
||||
@ -1974,9 +1989,10 @@ class ZipFileSystem extends FileSystem {
|
||||
int elenEXTT = 0; // extra for Extended Timestamp
|
||||
boolean foundExtraTime = false; // if time stamp NTFS, EXTT present
|
||||
|
||||
// confirm size/length
|
||||
byte[] zname = isdir ? toDirectoryPath(name) : name;
|
||||
|
||||
int nlen = (name != null) ? name.length - 1 : 0; // name has [0] as "slash"
|
||||
// confirm size/length
|
||||
int nlen = (zname != null) ? zname.length - 1 : 0; // name has [0] as "slash"
|
||||
int elen = (extra != null) ? extra.length : 0;
|
||||
int eoff = 0;
|
||||
int clen = (comment != null) ? comment.length : 0;
|
||||
@ -2037,7 +2053,7 @@ class ZipFileSystem extends FileSystem {
|
||||
writeShort(os, 0); // internal file attributes (unused)
|
||||
writeInt(os, 0); // external file attributes (unused)
|
||||
writeInt(os, locoff0); // relative offset of local header
|
||||
writeBytes(os, name, 1, nlen);
|
||||
writeBytes(os, zname, 1, nlen);
|
||||
if (elen64 != 0) {
|
||||
writeShort(os, EXTID_ZIP64);// Zip64 extra
|
||||
writeShort(os, elen64 - 4); // size of "this" extra block
|
||||
@ -2075,87 +2091,13 @@ class ZipFileSystem extends FileSystem {
|
||||
}
|
||||
|
||||
///////////////////// LOC //////////////////////
|
||||
static Entry readLOC(ZipFileSystem zipfs, long pos)
|
||||
throws IOException
|
||||
{
|
||||
return readLOC(zipfs, pos, new byte[1024]);
|
||||
}
|
||||
|
||||
static Entry readLOC(ZipFileSystem zipfs, long pos, byte[] buf)
|
||||
throws IOException
|
||||
{
|
||||
return new Entry().loc(zipfs, pos, buf);
|
||||
}
|
||||
|
||||
Entry loc(ZipFileSystem zipfs, long pos, byte[] buf)
|
||||
throws IOException
|
||||
{
|
||||
assert (buf.length >= LOCHDR);
|
||||
if (zipfs.readFullyAt(buf, 0, LOCHDR , pos) != LOCHDR)
|
||||
throw new ZipException("loc: reading failed");
|
||||
if (!locSigAt(buf, 0))
|
||||
throw new ZipException("loc: wrong sig ->"
|
||||
+ Long.toString(getSig(buf, 0), 16));
|
||||
//startPos = pos;
|
||||
version = LOCVER(buf);
|
||||
flag = LOCFLG(buf);
|
||||
method = LOCHOW(buf);
|
||||
mtime = dosToJavaTime(LOCTIM(buf));
|
||||
crc = LOCCRC(buf);
|
||||
csize = LOCSIZ(buf);
|
||||
size = LOCLEN(buf);
|
||||
int nlen = LOCNAM(buf);
|
||||
int elen = LOCEXT(buf);
|
||||
|
||||
name = new byte[nlen + 1];
|
||||
name[0] = '/';
|
||||
if (zipfs.readFullyAt(name, 1, nlen, pos + LOCHDR) != nlen) {
|
||||
throw new ZipException("loc: name reading failed");
|
||||
}
|
||||
if (elen > 0) {
|
||||
extra = new byte[elen];
|
||||
if (zipfs.readFullyAt(extra, 0, elen, pos + LOCHDR + nlen)
|
||||
!= elen) {
|
||||
throw new ZipException("loc: ext reading failed");
|
||||
}
|
||||
}
|
||||
pos += (LOCHDR + nlen + elen);
|
||||
if ((flag & FLAG_DATADESCR) != 0) {
|
||||
// Data Descriptor
|
||||
Entry e = zipfs.getEntry(name); // get the size/csize from cen
|
||||
if (e == null)
|
||||
throw new ZipException("loc: name not found in cen");
|
||||
size = e.size;
|
||||
csize = e.csize;
|
||||
pos += (method == METHOD_STORED ? size : csize);
|
||||
if (size >= ZIP64_MINVAL || csize >= ZIP64_MINVAL)
|
||||
pos += 24;
|
||||
else
|
||||
pos += 16;
|
||||
} else {
|
||||
if (extra != null &&
|
||||
(size == ZIP64_MINVAL || csize == ZIP64_MINVAL)) {
|
||||
// zip64 ext: must include both size and csize
|
||||
int off = 0;
|
||||
while (off + 20 < elen) { // HeaderID+DataSize+Data
|
||||
int sz = SH(extra, off + 2);
|
||||
if (SH(extra, off) == EXTID_ZIP64 && sz == 16) {
|
||||
size = LL(extra, off + 4);
|
||||
csize = LL(extra, off + 12);
|
||||
break;
|
||||
}
|
||||
off += (sz + 4);
|
||||
}
|
||||
}
|
||||
pos += (method == METHOD_STORED ? size : csize);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
int writeLOC(OutputStream os) throws IOException {
|
||||
writeInt(os, LOCSIG); // LOC header signature
|
||||
int version = version();
|
||||
int nlen = (name != null) ? name.length - 1 : 0; // [0] is slash
|
||||
|
||||
byte[] zname = isdir ? toDirectoryPath(name) : name;
|
||||
int nlen = (zname != null) ? zname.length - 1 : 0; // [0] is slash
|
||||
int elen = (extra != null) ? extra.length : 0;
|
||||
boolean foundExtraTime = false; // if extra timestamp present
|
||||
int eoff = 0;
|
||||
@ -2214,7 +2156,7 @@ class ZipFileSystem extends FileSystem {
|
||||
}
|
||||
writeShort(os, nlen);
|
||||
writeShort(os, elen + elen64 + elenNTFS + elenEXTT);
|
||||
writeBytes(os, name, 1, nlen);
|
||||
writeBytes(os, zname, 1, nlen);
|
||||
if (elen64 != 0) {
|
||||
writeShort(os, EXTID_ZIP64);
|
||||
writeShort(os, 16);
|
||||
@ -2551,7 +2493,7 @@ class ZipFileSystem extends FileSystem {
|
||||
private void buildNodeTree() throws IOException {
|
||||
beginWrite();
|
||||
try {
|
||||
IndexNode root = new IndexNode(ROOTPATH);
|
||||
IndexNode root = new IndexNode(ROOTPATH, true);
|
||||
IndexNode[] nodes = inodes.keySet().toArray(new IndexNode[0]);
|
||||
inodes.put(root, root);
|
||||
ParentLookup lookup = new ParentLookup();
|
||||
@ -2564,7 +2506,7 @@ class ZipFileSystem extends FileSystem {
|
||||
root.child = node;
|
||||
break;
|
||||
}
|
||||
lookup = lookup.as(node.name, off + 1);
|
||||
lookup = lookup.as(node.name, off);
|
||||
if (inodes.containsKey(lookup)) {
|
||||
parent = inodes.get(lookup);
|
||||
node.sibling = parent.child;
|
||||
@ -2572,7 +2514,7 @@ class ZipFileSystem extends FileSystem {
|
||||
break;
|
||||
}
|
||||
// add new pseudo directory entry
|
||||
parent = new IndexNode(Arrays.copyOf(node.name, off + 1));
|
||||
parent = new IndexNode(Arrays.copyOf(node.name, off), true);
|
||||
inodes.put(parent, parent);
|
||||
node.sibling = parent.child;
|
||||
parent.child = node;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -59,8 +59,7 @@ final class ZipPath implements Path {
|
||||
} else {
|
||||
if (zfs.zc.isUTF8()) {
|
||||
this.path = normalize(path);
|
||||
} else {
|
||||
// see normalize(String);
|
||||
} else { // see normalize(String);
|
||||
this.path = normalize(zfs.getString(path));
|
||||
}
|
||||
}
|
||||
@ -68,13 +67,8 @@ final class ZipPath implements Path {
|
||||
|
||||
ZipPath(ZipFileSystem zfs, String path) {
|
||||
this.zfs = zfs;
|
||||
if (zfs.zc.isUTF8()) {
|
||||
this.path = normalize(zfs.getBytes(path));
|
||||
} else {
|
||||
// see normalize(String);
|
||||
this.path = normalize(path);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZipPath getRoot() {
|
||||
@ -86,31 +80,29 @@ final class ZipPath implements Path {
|
||||
|
||||
@Override
|
||||
public Path getFileName() {
|
||||
initOffsets();
|
||||
int count = offsets.length;
|
||||
if (count == 0)
|
||||
return null; // no elements so no name
|
||||
if (count == 1 && path[0] != '/')
|
||||
int off = path.length;
|
||||
if (off == 0 || off == 1 && path[0] == '/')
|
||||
return null;
|
||||
while (--off >= 0 && path[off] != '/') {}
|
||||
if (off < 0)
|
||||
return this;
|
||||
int lastOffset = offsets[count-1];
|
||||
int len = path.length - lastOffset;
|
||||
byte[] result = new byte[len];
|
||||
System.arraycopy(path, lastOffset, result, 0, len);
|
||||
return new ZipPath(zfs, result);
|
||||
off++;
|
||||
byte[] result = new byte[path.length - off];
|
||||
System.arraycopy(path, off, result, 0, result.length);
|
||||
return new ZipPath(getFileSystem(), result, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZipPath getParent() {
|
||||
initOffsets();
|
||||
int count = offsets.length;
|
||||
if (count == 0) // no elements so no parent
|
||||
int off = path.length;
|
||||
if (off == 0 || off == 1 && path[0] == '/')
|
||||
return null;
|
||||
int len = offsets[count-1] - 1;
|
||||
if (len <= 0) // parent is root only (may be null)
|
||||
while (--off >= 0 && path[off] != '/') {}
|
||||
if (off <= 0)
|
||||
return getRoot();
|
||||
byte[] result = new byte[len];
|
||||
System.arraycopy(path, 0, result, 0, len);
|
||||
return new ZipPath(zfs, result);
|
||||
byte[] result = new byte[off];
|
||||
System.arraycopy(path, 0, result, 0, off);
|
||||
return new ZipPath(getFileSystem(), result, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -277,30 +269,36 @@ final class ZipPath implements Path {
|
||||
|
||||
@Override
|
||||
public boolean isAbsolute() {
|
||||
return (this.path.length > 0 && path[0] == '/');
|
||||
return path.length > 0 && path[0] == '/';
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZipPath resolve(Path other) {
|
||||
final ZipPath o = checkPath(other);
|
||||
int tlen = this.path.length;
|
||||
if (tlen == 0 || o.isAbsolute())
|
||||
return o;
|
||||
int olen = o.path.length;
|
||||
if (olen == 0)
|
||||
ZipPath o = checkPath(other);
|
||||
if (o.path.length == 0)
|
||||
return this;
|
||||
if (o.isAbsolute() || this.path.length == 0)
|
||||
return o;
|
||||
return resolve(o.path);
|
||||
}
|
||||
|
||||
// opath is normalized, just concat
|
||||
private ZipPath resolve(byte[] opath) {
|
||||
byte[] resolved = null;
|
||||
if (this.path[tlen - 1] == '/') {
|
||||
byte[] tpath = this.path;
|
||||
int tlen = tpath.length;
|
||||
int olen = opath.length;
|
||||
if (path[tlen - 1] == '/') {
|
||||
resolved = new byte[tlen + olen];
|
||||
System.arraycopy(path, 0, resolved, 0, tlen);
|
||||
System.arraycopy(o.path, 0, resolved, tlen, olen);
|
||||
System.arraycopy(tpath, 0, resolved, 0, tlen);
|
||||
System.arraycopy(opath, 0, resolved, tlen, olen);
|
||||
} else {
|
||||
resolved = new byte[tlen + 1 + olen];
|
||||
System.arraycopy(path, 0, resolved, 0, tlen);
|
||||
System.arraycopy(tpath, 0, resolved, 0, tlen);
|
||||
resolved[tlen] = '/';
|
||||
System.arraycopy(o.path, 0, resolved, tlen + 1, olen);
|
||||
System.arraycopy(opath, 0, resolved, tlen + 1, olen);
|
||||
}
|
||||
return new ZipPath(zfs, resolved);
|
||||
return new ZipPath(zfs, resolved, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -351,7 +349,12 @@ final class ZipPath implements Path {
|
||||
|
||||
@Override
|
||||
public ZipPath resolve(String other) {
|
||||
return resolve(zfs.getPath(other));
|
||||
byte[] opath = normalize(other);
|
||||
if (opath.length == 0)
|
||||
return this;
|
||||
if (opath[0] == '/' || this.path.length == 0)
|
||||
return new ZipPath(zfs, opath, true);
|
||||
return resolve(opath);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -455,8 +458,9 @@ final class ZipPath implements Path {
|
||||
return normalize(path, i - 1);
|
||||
prevC = c;
|
||||
}
|
||||
if (len > 1 && prevC == '/')
|
||||
if (len > 1 && prevC == '/') {
|
||||
return Arrays.copyOf(path, len - 1);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
@ -490,6 +494,8 @@ final class ZipPath implements Path {
|
||||
// to avoid incorrectly normalizing byte '0x5c' (as '\')
|
||||
// to '/'.
|
||||
private byte[] normalize(String path) {
|
||||
if (zfs.zc.isUTF8())
|
||||
return normalize(zfs.getBytes(path));
|
||||
int len = path.length();
|
||||
if (len == 0)
|
||||
return new byte[0];
|
||||
@ -533,7 +539,8 @@ final class ZipPath implements Path {
|
||||
// Remove DotSlash(./) and resolve DotDot (..) components
|
||||
private byte[] getResolved() {
|
||||
for (int i = 0; i < path.length; i++) {
|
||||
if (path[i] == (byte)'.') {
|
||||
if (path[i] == (byte)'.' &&
|
||||
(i + 1 == path.length || path[i + 1] == '/')) {
|
||||
return resolve0();
|
||||
}
|
||||
}
|
||||
@ -976,5 +983,4 @@ final class ZipPath implements Path {
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -258,6 +258,8 @@ tools/jimage/JImageVerifyTest.java 8169713 generic-
|
||||
|
||||
tools/jlink/multireleasejar/JLinkMultiReleaseJarTest.java 8169971 windows-x64
|
||||
|
||||
tools/jlink/CustomPluginTest.java 8172864 generic-all
|
||||
|
||||
############################################################################
|
||||
|
||||
# jdk_jdi
|
||||
|
@ -26,8 +26,8 @@ groups=TEST.groups [closed/TEST.groups]
|
||||
# Allow querying of various System properties in @requires clauses
|
||||
requires.properties=sun.arch.data.model java.runtime.name
|
||||
|
||||
# Tests using jtreg 4.2 b04 features
|
||||
requiredVersion=4.2 b04
|
||||
# Tests using jtreg 4.2 b05 features
|
||||
requiredVersion=4.2 b05
|
||||
|
||||
# Path to libraries in the topmost test directory. This is needed so @library
|
||||
# does not need ../../ notation to reach them
|
||||
|
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import java.util.logging.Handler;
|
||||
import java.util.logging.LogManager;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8172886
|
||||
* @summary Verifies that a custom LogManager or custom Handler can be
|
||||
* instantiated by the logging system if they are in a package
|
||||
* that is exported to java.logging by a module.
|
||||
* @build test.logmanager/test.logmanager.TestLogManager
|
||||
* test.handlers/test.handlers.TestHandler
|
||||
* test.config/test.config.LogConfig
|
||||
* LogManagerInModuleTest
|
||||
* @run main/othervm --add-modules test.logmanager,test.handlers
|
||||
* -Djava.util.logging.manager=test.logmanager.TestLogManager
|
||||
* LogManagerInModuleTest
|
||||
* @run main/othervm --add-modules test.logmanager,test.handlers,test.config
|
||||
* -Djava.util.logging.manager=test.logmanager.TestLogManager
|
||||
* -Djava.util.logging.config.class=test.config.LogConfig
|
||||
* LogManagerInModuleTest
|
||||
*
|
||||
* @author danielfuchs
|
||||
*/
|
||||
public class LogManagerInModuleTest {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (System.getProperty("java.util.logging.config.class", null) == null) {
|
||||
System.setProperty("java.util.logging.config.file",
|
||||
Paths.get(System.getProperty("test.src", "src"),
|
||||
"logging.properties").toString());
|
||||
}
|
||||
// sanity check
|
||||
if (LogManagerInModuleTest.class.getModule().isNamed()) {
|
||||
throw new RuntimeException("Unexpected named module for "
|
||||
+ LogManagerInModuleTest.class + ": "
|
||||
+ LogManagerInModuleTest.class.getModule().getName());
|
||||
}
|
||||
|
||||
// now check that the LogManager was correctly instantiated.
|
||||
LogManager manager = LogManager.getLogManager();
|
||||
System.out.println("LogManager: " + manager);
|
||||
Class<?> logManagerClass = manager.getClass();
|
||||
if (!"test.logmanager".equals(logManagerClass.getModule().getName())) {
|
||||
throw new RuntimeException("Bad module for log manager: "
|
||||
+ logManagerClass.getModule() + "; class is: "
|
||||
+ logManagerClass.getName());
|
||||
}
|
||||
|
||||
Logger logger = Logger.getLogger("com.xyz.foo");
|
||||
Handler[] handlers = logger.getHandlers();
|
||||
if (handlers.length != 1) {
|
||||
throw new RuntimeException("Expected 1 handler, found " + handlers.length);
|
||||
}
|
||||
Class<?> handlerClass = handlers[0].getClass();
|
||||
if (!"test.handlers".equals(handlerClass.getModule().getName())) {
|
||||
throw new RuntimeException("Bad module for handler: "
|
||||
+ handlerClass.getModule() + "; class is: "
|
||||
+ handlerClass.getName());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
############################################################
|
||||
# Global properties
|
||||
############################################################
|
||||
|
||||
# "handlers" specifies a comma separated list of log Handler
|
||||
# classes. These handlers will be installed during VM startup.
|
||||
# Note that these classes must be on the system classpath.
|
||||
# By default we only configure a ConsoleHandler, which will only
|
||||
# show messages at the INFO and above levels.
|
||||
handlers= java.util.logging.ConsoleHandler
|
||||
|
||||
# To also add the FileHandler, use the following line instead.
|
||||
#handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler
|
||||
|
||||
# Default global logging level.
|
||||
# This specifies which kinds of events are logged across
|
||||
# all loggers. For any given facility this global level
|
||||
# can be overriden by a facility specific level
|
||||
# Note that the ConsoleHandler also has a separate level
|
||||
# setting to limit messages printed to the console.
|
||||
.level= INFO
|
||||
|
||||
############################################################
|
||||
# Handler specific properties.
|
||||
# Describes specific configuration info for Handlers.
|
||||
############################################################
|
||||
|
||||
# default file output is in user's home directory.
|
||||
java.util.logging.FileHandler.pattern = %h/java%u.log
|
||||
java.util.logging.FileHandler.limit = 50000
|
||||
java.util.logging.FileHandler.count = 1
|
||||
# Default number of locks FileHandler can obtain synchronously.
|
||||
# This specifies maximum number of attempts to obtain lock file by FileHandler
|
||||
# implemented by incrementing the unique field %u as per FileHandler API documentation.
|
||||
java.util.logging.FileHandler.maxLocks = 100
|
||||
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter
|
||||
|
||||
# Limit the message that are printed on the console to INFO and above.
|
||||
java.util.logging.ConsoleHandler.level = INFO
|
||||
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
|
||||
|
||||
# Example to customize the SimpleFormatter output format
|
||||
# to print one-line log message like this:
|
||||
# <level>: <log message> [<date/time>]
|
||||
#
|
||||
# java.util.logging.SimpleFormatter.format=%4$s: %5$s [%1$tc]%n
|
||||
|
||||
############################################################
|
||||
# Facility specific properties.
|
||||
# Provides extra control for each logger.
|
||||
############################################################
|
||||
|
||||
# For example, set the com.xyz.foo logger to only log SEVERE
|
||||
# messages:
|
||||
com.xyz.foo.level = SEVERE
|
||||
com.xyz.foo.handlers = test.handlers.TestHandler
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
module test.config {
|
||||
requires java.logging;
|
||||
requires test.handlers;
|
||||
// makes it possible for java.logging to instantiate test.config.LogConfig;
|
||||
// this doesn't need to be a qualified export, but making it so will prevent
|
||||
// any other module from being able to instantiate the provided classes.
|
||||
exports test.config to java.logging;
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package test.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.LogManager;
|
||||
import java.util.logging.Logger;
|
||||
import test.handlers.TestHandler;
|
||||
|
||||
/**
|
||||
* A dummy class that configures the logging system.
|
||||
* @author danielfuchs
|
||||
*/
|
||||
public class LogConfig {
|
||||
private static final List<Logger> LOGGERS = new ArrayList<>();
|
||||
public LogConfig() {
|
||||
LogManager manager = LogManager.getLogManager();
|
||||
Logger logger = Logger.getLogger("com.xyz.foo");
|
||||
if (logger.getHandlers().length > 0) {
|
||||
System.err.println(this.getClass().getName() + ": "
|
||||
+ "Unexpected handlers: "
|
||||
+ List.of(logger.getHandlers()));
|
||||
throw new RuntimeException("Unexpected handlers: "
|
||||
+ List.of(logger.getHandlers()));
|
||||
}
|
||||
logger.addHandler(new TestHandler());
|
||||
LOGGERS.add(logger);
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
module test.handlers {
|
||||
requires transitive java.logging;
|
||||
// makes it possible for java.logging and test.config to instantiate
|
||||
// test.handlers.TestHandler;
|
||||
// this doesn't need to be a qualified export, but making it so will prevent
|
||||
// any other module from being able to instantiate the provided classes.
|
||||
exports test.handlers to java.logging, test.config;
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package test.handlers;
|
||||
|
||||
import java.util.logging.Handler;
|
||||
import java.util.logging.LogRecord;
|
||||
|
||||
/**
|
||||
* A dummy Handler that does nothing.
|
||||
* @author danielfuchs
|
||||
*/
|
||||
public class TestHandler extends Handler {
|
||||
|
||||
@Override
|
||||
public void publish(LogRecord record) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws SecurityException {
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
module test.logmanager {
|
||||
requires java.logging;
|
||||
// makes it possible for java.logging to instantiate
|
||||
// test.logmanager.TestLogManager;
|
||||
// this doesn't need to be a qualified export, but making it so will prevent
|
||||
// any other module from being able to instantiate the provided classes.
|
||||
exports test.logmanager to java.logging;
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package test.logmanager;
|
||||
|
||||
import java.util.logging.LogManager;
|
||||
|
||||
/**
|
||||
* A dummy LogManager that simply extends the standard class.
|
||||
* @author danielfuchs
|
||||
*/
|
||||
public class TestLogManager extends LogManager {
|
||||
|
||||
}
|
@ -31,7 +31,7 @@ import java.nio.file.Path;
|
||||
/**
|
||||
*
|
||||
* @test
|
||||
* @bug 8038500 8040059 8139956 8146754
|
||||
* @bug 8038500 8040059 8139956 8146754 8172921
|
||||
* @summary Tests path operations for zip provider.
|
||||
*
|
||||
* @run main PathOps
|
||||
@ -180,6 +180,13 @@ public class PathOps {
|
||||
return this;
|
||||
}
|
||||
|
||||
PathOps resolvePath(String other, String expected) {
|
||||
out.format("test resolve %s\n", other);
|
||||
checkPath();
|
||||
check(path.resolve(fs.getPath(other)), expected);
|
||||
return this;
|
||||
}
|
||||
|
||||
PathOps resolveSibling(String other, String expected) {
|
||||
out.format("test resolveSibling %s\n", other);
|
||||
checkPath();
|
||||
@ -384,6 +391,30 @@ public class PathOps {
|
||||
.resolve("", "")
|
||||
.resolve("foo", "foo")
|
||||
.resolve("/foo", "/foo");
|
||||
test("/")
|
||||
.resolve("", "/")
|
||||
.resolve("foo", "/foo")
|
||||
.resolve("/foo", "/foo")
|
||||
.resolve("/foo/", "/foo");
|
||||
|
||||
// resolve(Path)
|
||||
test("/tmp")
|
||||
.resolvePath("foo", "/tmp/foo")
|
||||
.resolvePath("/foo", "/foo")
|
||||
.resolvePath("", "/tmp");
|
||||
test("tmp")
|
||||
.resolvePath("foo", "tmp/foo")
|
||||
.resolvePath("/foo", "/foo")
|
||||
.resolvePath("", "tmp");
|
||||
test("")
|
||||
.resolvePath("", "")
|
||||
.resolvePath("foo", "foo")
|
||||
.resolvePath("/foo", "/foo");
|
||||
test("/")
|
||||
.resolvePath("", "/")
|
||||
.resolvePath("foo", "/foo")
|
||||
.resolvePath("/foo", "/foo")
|
||||
.resolvePath("/foo/", "/foo");
|
||||
|
||||
// resolveSibling
|
||||
test("foo")
|
||||
|
193
jdk/test/tools/jar/multiRelease/ApiValidatorTest.java
Normal file
193
jdk/test/tools/jar/multiRelease/ApiValidatorTest.java
Normal file
@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @summary Tests for API validator.
|
||||
* @library /test/lib /lib/testlibrary
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* jdk.compiler
|
||||
* jdk.jartool
|
||||
* @build jdk.test.lib.JDKToolFinder jdk.test.lib.Utils jdk.test.lib.process.*
|
||||
* @build jdk.testlibrary.FileUtils
|
||||
* @build MRTestBase
|
||||
* @run testng ApiValidatorTest
|
||||
*/
|
||||
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.testlibrary.FileUtils;
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
public class ApiValidatorTest extends MRTestBase {
|
||||
|
||||
@Test(dataProvider = "signatureChange")
|
||||
public void changeMethodSignature(String sigBase, String sigV10,
|
||||
boolean isAcceptable,
|
||||
Method method) throws Throwable {
|
||||
Path root = Paths.get(method.getName());
|
||||
Path classes = root.resolve("classes");
|
||||
|
||||
String METHOD_SIG = "#SIG";
|
||||
String classTemplate =
|
||||
"public class C { \n" +
|
||||
" " + METHOD_SIG + "{ throw new RuntimeException(); };\n" +
|
||||
"}\n";
|
||||
String base = classTemplate.replace(METHOD_SIG, sigBase);
|
||||
String v10 = classTemplate.replace(METHOD_SIG, sigV10);
|
||||
|
||||
compileTemplate(classes.resolve("base"), base);
|
||||
compileTemplate(classes.resolve("v10"), v10);
|
||||
|
||||
String jarfile = root.resolve("test.jar").toString();
|
||||
OutputAnalyzer result = jar("cf", jarfile,
|
||||
"-C", classes.resolve("base").toString(), ".",
|
||||
"--release", "10", "-C", classes.resolve("v10").toString(),
|
||||
".");
|
||||
if (isAcceptable) {
|
||||
result.shouldHaveExitValue(SUCCESS)
|
||||
.shouldBeEmpty();
|
||||
} else {
|
||||
result.shouldNotHaveExitValue(SUCCESS)
|
||||
.shouldContain("contains a class with different api from earlier version");
|
||||
}
|
||||
|
||||
FileUtils.deleteFileTreeWithRetry(root);
|
||||
}
|
||||
|
||||
@DataProvider
|
||||
Object[][] signatureChange() {
|
||||
return new Object[][]{
|
||||
{"public int m()", "protected int m()", false},
|
||||
{"protected int m()", "public int m()", false},
|
||||
{"public int m()", "int m()", false},
|
||||
{"protected int m()", "private int m()", false},
|
||||
{"private int m()", "int m()", true},
|
||||
{"int m()", "private int m()", true},
|
||||
{"int m()", "private int m(boolean b)", true},
|
||||
{"public int m()", "public int m(int i)", false},
|
||||
{"public int m()", "public int k()", false},
|
||||
{"public int m()", "private int k()", false},
|
||||
// @ignore JDK-8172147 {"public int m()", "public boolean m()", false},
|
||||
// @ignore JDK-8172147 {"public boolean", "public Boolean", false},
|
||||
// @ignore JDK-8172147 {"public <T> T", "public <T extends String> T", false},
|
||||
};
|
||||
}
|
||||
|
||||
@Test(dataProvider = "publicAPI")
|
||||
public void introducingPublicMembers(String publicAPI,
|
||||
Method method) throws Throwable {
|
||||
Path root = Paths.get(method.getName());
|
||||
Path classes = root.resolve("classes");
|
||||
|
||||
String API = "#API";
|
||||
String classTemplate =
|
||||
"public class C { \n" +
|
||||
" " + API + "\n" +
|
||||
" public void method(){ };\n" +
|
||||
"}\n";
|
||||
String base = classTemplate.replace(API, "");
|
||||
String v10 = classTemplate.replace(API, publicAPI);
|
||||
|
||||
compileTemplate(classes.resolve("base"), base);
|
||||
compileTemplate(classes.resolve("v10"), v10);
|
||||
|
||||
String jarfile = root.resolve("test.jar").toString();
|
||||
jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
|
||||
"--release", "10", "-C", classes.resolve("v10").toString(), ".")
|
||||
.shouldNotHaveExitValue(SUCCESS)
|
||||
.shouldContain("contains a class with different api from earlier version");
|
||||
|
||||
FileUtils.deleteFileTreeWithRetry(root);
|
||||
}
|
||||
|
||||
@DataProvider
|
||||
Object[][] publicAPI() {
|
||||
return new Object[][]{
|
||||
// @ignore JDK-8172148 {"protected class Inner { public void m(){ } } "}, // protected inner class
|
||||
// @ignore JDK-8172148 {"public class Inner { public void m(){ } }"}, // public inner class
|
||||
// @ignore JDK-8172148 {"public enum E { A; }"}, // public enum
|
||||
{"public void m(){ }"}, // public method
|
||||
{"protected void m(){ }"}, // protected method
|
||||
};
|
||||
}
|
||||
|
||||
@Test(dataProvider = "privateAPI")
|
||||
public void introducingPrivateMembers(String privateAPI,
|
||||
Method method) throws Throwable {
|
||||
Path root = Paths.get(method.getName());
|
||||
Path classes = root.resolve("classes");
|
||||
|
||||
String API = "#API";
|
||||
String classTemplate =
|
||||
"public class C { \n" +
|
||||
" " + API + "\n" +
|
||||
" public void method(){ };\n" +
|
||||
"}\n";
|
||||
String base = classTemplate.replace(API, "");
|
||||
String v10 = classTemplate.replace(API, privateAPI);
|
||||
|
||||
compileTemplate(classes.resolve("base"), base);
|
||||
compileTemplate(classes.resolve("v10"), v10);
|
||||
|
||||
String jarfile = root.resolve("test.jar").toString();
|
||||
jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
|
||||
"--release", "10", "-C", classes.resolve("v10").toString(), ".")
|
||||
.shouldHaveExitValue(SUCCESS);
|
||||
// add release
|
||||
jar("uf", jarfile,
|
||||
"--release", "11", "-C", classes.resolve("v10").toString(), ".")
|
||||
.shouldHaveExitValue(SUCCESS);
|
||||
// replace release
|
||||
jar("uf", jarfile,
|
||||
"--release", "11", "-C", classes.resolve("v10").toString(), ".")
|
||||
.shouldHaveExitValue(SUCCESS);
|
||||
|
||||
FileUtils.deleteFileTreeWithRetry(root);
|
||||
}
|
||||
|
||||
@DataProvider
|
||||
Object[][] privateAPI() {
|
||||
return new Object[][]{
|
||||
{"private class Inner { public void m(){ } } "}, // private inner class
|
||||
{"class Inner { public void m(){ } }"}, // package private inner class
|
||||
{"enum E { A; }"}, // package private enum
|
||||
// Local class and private method
|
||||
{"private void m(){ class Inner { public void m(){} } Inner i = null; }"},
|
||||
{"void m(){ }"}, // package private method
|
||||
};
|
||||
}
|
||||
|
||||
private void compileTemplate(Path classes, String template) throws Throwable {
|
||||
Path classSourceFile = Files.createDirectories(
|
||||
classes.getParent().resolve("src").resolve(classes.getFileName()))
|
||||
.resolve("C.java");
|
||||
Files.write(classSourceFile, template.getBytes());
|
||||
javac(classes, classSourceFile);
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -23,49 +23,39 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @library /test/lib
|
||||
* @library /test/lib /lib/testlibrary
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* jdk.compiler
|
||||
* jdk.jartool
|
||||
* @build jdk.test.lib.JDKToolFinder jdk.test.lib.Utils
|
||||
* @build jdk.test.lib.JDKToolFinder jdk.test.lib.Utils jdk.test.lib.process.*
|
||||
* @build jdk.testlibrary.FileUtils
|
||||
* @build MRTestBase
|
||||
* @run testng Basic
|
||||
*/
|
||||
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
import jdk.testlibrary.FileUtils;
|
||||
import org.testng.annotations.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.File;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.*;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.jar.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.*;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import jdk.test.lib.JDKToolFinder;
|
||||
import jdk.test.lib.Utils;
|
||||
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static java.lang.System.out;
|
||||
|
||||
public class Basic {
|
||||
private final String src = System.getProperty("test.src", ".");
|
||||
private final String usr = System.getProperty("user.dir", ".");
|
||||
public class Basic extends MRTestBase {
|
||||
|
||||
@Test
|
||||
// create a regular, non-multi-release jar
|
||||
public void test00() throws IOException {
|
||||
public void test00() throws Throwable {
|
||||
String jarfile = "test.jar";
|
||||
|
||||
compile("test01"); //use same data as test01
|
||||
|
||||
Path classes = Paths.get("classes");
|
||||
jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".")
|
||||
.assertSuccess();
|
||||
.shouldHaveExitValue(SUCCESS);
|
||||
|
||||
checkMultiRelease(jarfile, false);
|
||||
|
||||
@ -79,13 +69,13 @@ public class Basic {
|
||||
|
||||
compare(jarfile, names);
|
||||
|
||||
delete(jarfile);
|
||||
deleteDir(Paths.get(usr, "classes"));
|
||||
FileUtils.deleteFileIfExistsWithRetry(Paths.get(jarfile));
|
||||
FileUtils.deleteFileTreeWithRetry(Paths.get(usr, "classes"));
|
||||
}
|
||||
|
||||
@Test
|
||||
// create a multi-release jar
|
||||
public void test01() throws IOException {
|
||||
public void test01() throws Throwable {
|
||||
String jarfile = "test.jar";
|
||||
|
||||
compile("test01");
|
||||
@ -94,7 +84,7 @@ public class Basic {
|
||||
jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
|
||||
"--release", "9", "-C", classes.resolve("v9").toString(), ".",
|
||||
"--release", "10", "-C", classes.resolve("v10").toString(), ".")
|
||||
.assertSuccess();
|
||||
.shouldHaveExitValue(SUCCESS);
|
||||
|
||||
checkMultiRelease(jarfile, true);
|
||||
|
||||
@ -114,25 +104,53 @@ public class Basic {
|
||||
|
||||
compare(jarfile, names);
|
||||
|
||||
delete(jarfile);
|
||||
deleteDir(Paths.get(usr, "classes"));
|
||||
FileUtils.deleteFileIfExistsWithRetry(Paths.get(jarfile));
|
||||
FileUtils.deleteFileTreeWithRetry(Paths.get(usr, "classes"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void versionFormat() throws Throwable {
|
||||
String jarfile = "test.jar";
|
||||
|
||||
compile("test01");
|
||||
|
||||
Path classes = Paths.get("classes");
|
||||
|
||||
// valid
|
||||
for (String release : List.of("10000", "09", "00010", "10")) {
|
||||
jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
|
||||
"--release", release, "-C", classes.resolve("v10").toString(), ".")
|
||||
.shouldHaveExitValue(SUCCESS)
|
||||
.shouldBeEmpty();
|
||||
}
|
||||
// invalid
|
||||
for (String release : List.of("9.0", "8", "v9",
|
||||
"9v", "0", "-10")) {
|
||||
jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
|
||||
"--release", release, "-C", classes.resolve("v10").toString(), ".")
|
||||
.shouldNotHaveExitValue(SUCCESS)
|
||||
.shouldContain("release " + release + " not valid");
|
||||
}
|
||||
FileUtils.deleteFileIfExistsWithRetry(Paths.get(jarfile));
|
||||
FileUtils.deleteFileTreeWithRetry(Paths.get(usr, "classes"));
|
||||
}
|
||||
|
||||
@Test
|
||||
// update a regular jar to a multi-release jar
|
||||
public void test02() throws IOException {
|
||||
public void test02() throws Throwable {
|
||||
String jarfile = "test.jar";
|
||||
|
||||
compile("test01"); //use same data as test01
|
||||
|
||||
Path classes = Paths.get("classes");
|
||||
jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".")
|
||||
.assertSuccess();
|
||||
.shouldHaveExitValue(SUCCESS);
|
||||
|
||||
checkMultiRelease(jarfile, false);
|
||||
|
||||
jar("uf", jarfile, "--release", "9", "-C", classes.resolve("v9").toString(), ".")
|
||||
.assertSuccess();
|
||||
jar("uf", jarfile,
|
||||
"--release", "9", "-C", classes.resolve("v9").toString(), ".")
|
||||
.shouldHaveExitValue(SUCCESS);
|
||||
|
||||
checkMultiRelease(jarfile, true);
|
||||
|
||||
@ -149,13 +167,13 @@ public class Basic {
|
||||
|
||||
compare(jarfile, names);
|
||||
|
||||
delete(jarfile);
|
||||
deleteDir(Paths.get(usr, "classes"));
|
||||
FileUtils.deleteFileIfExistsWithRetry(Paths.get(jarfile));
|
||||
FileUtils.deleteFileTreeWithRetry(Paths.get(usr, "classes"));
|
||||
}
|
||||
|
||||
@Test
|
||||
// replace a base entry and a versioned entry
|
||||
public void test03() throws IOException {
|
||||
public void test03() throws Throwable {
|
||||
String jarfile = "test.jar";
|
||||
|
||||
compile("test01"); //use same data as test01
|
||||
@ -163,7 +181,7 @@ public class Basic {
|
||||
Path classes = Paths.get("classes");
|
||||
jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
|
||||
"--release", "9", "-C", classes.resolve("v9").toString(), ".")
|
||||
.assertSuccess();
|
||||
.shouldHaveExitValue(SUCCESS);
|
||||
|
||||
checkMultiRelease(jarfile, true);
|
||||
|
||||
@ -184,7 +202,7 @@ public class Basic {
|
||||
// version/Version.class entry in versions/9 section
|
||||
jar("uf", jarfile, "-C", classes.resolve("v9").toString(), "version",
|
||||
"--release", "9", "-C", classes.resolve("v10").toString(), ".")
|
||||
.assertSuccess();
|
||||
.shouldHaveExitValue(SUCCESS);
|
||||
|
||||
checkMultiRelease(jarfile, true);
|
||||
|
||||
@ -201,8 +219,8 @@ public class Basic {
|
||||
|
||||
compare(jarfile, names);
|
||||
|
||||
delete(jarfile);
|
||||
deleteDir(Paths.get(usr, "classes"));
|
||||
FileUtils.deleteFileIfExistsWithRetry(Paths.get(jarfile));
|
||||
FileUtils.deleteFileTreeWithRetry(Paths.get(usr, "classes"));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -211,7 +229,7 @@ public class Basic {
|
||||
|
||||
@Test
|
||||
// META-INF/versions/9 class has different api than base class
|
||||
public void test04() throws IOException {
|
||||
public void test04() throws Throwable {
|
||||
String jarfile = "test.jar";
|
||||
|
||||
compile("test01"); //use same data as test01
|
||||
@ -224,18 +242,16 @@ public class Basic {
|
||||
|
||||
jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
|
||||
"--release", "9", "-C", classes.resolve("v9").toString(), ".")
|
||||
.assertFailure()
|
||||
.resultChecker(r ->
|
||||
assertTrue(r.output.contains("different api from earlier"), r.output)
|
||||
);
|
||||
.shouldNotHaveExitValue(SUCCESS)
|
||||
.shouldContain("different api from earlier");
|
||||
|
||||
delete(jarfile);
|
||||
deleteDir(Paths.get(usr, "classes"));
|
||||
FileUtils.deleteFileIfExistsWithRetry(Paths.get(jarfile));
|
||||
FileUtils.deleteFileTreeWithRetry(Paths.get(usr, "classes"));
|
||||
}
|
||||
|
||||
@Test
|
||||
// META-INF/versions/9 contains an extra public class
|
||||
public void test05() throws IOException {
|
||||
public void test05() throws Throwable {
|
||||
String jarfile = "test.jar";
|
||||
|
||||
compile("test01"); //use same data as test01
|
||||
@ -248,18 +264,16 @@ public class Basic {
|
||||
|
||||
jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
|
||||
"--release", "9", "-C", classes.resolve("v9").toString(), ".")
|
||||
.assertFailure()
|
||||
.resultChecker(r ->
|
||||
assertTrue(r.output.contains("contains a new public class"), r.output)
|
||||
);
|
||||
.shouldNotHaveExitValue(SUCCESS)
|
||||
.shouldContain("contains a new public class");
|
||||
|
||||
delete(jarfile);
|
||||
deleteDir(Paths.get(usr, "classes"));
|
||||
FileUtils.deleteFileIfExistsWithRetry(Paths.get(jarfile));
|
||||
FileUtils.deleteFileTreeWithRetry(Paths.get(usr, "classes"));
|
||||
}
|
||||
|
||||
@Test
|
||||
// META-INF/versions/9 contains an extra package private class -- this is okay
|
||||
public void test06() throws IOException {
|
||||
public void test06() throws Throwable {
|
||||
String jarfile = "test.jar";
|
||||
|
||||
compile("test01"); //use same data as test01
|
||||
@ -272,16 +286,16 @@ public class Basic {
|
||||
|
||||
jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
|
||||
"--release", "9", "-C", classes.resolve("v9").toString(), ".")
|
||||
.assertSuccess();
|
||||
.shouldHaveExitValue(SUCCESS);
|
||||
|
||||
delete(jarfile);
|
||||
deleteDir(Paths.get(usr, "classes"));
|
||||
FileUtils.deleteFileIfExistsWithRetry(Paths.get(jarfile));
|
||||
FileUtils.deleteFileTreeWithRetry(Paths.get(usr, "classes"));
|
||||
}
|
||||
|
||||
@Test
|
||||
// META-INF/versions/9 contains an identical class to base entry class
|
||||
// this is okay but produces warning
|
||||
public void test07() throws IOException {
|
||||
public void test07() throws Throwable {
|
||||
String jarfile = "test.jar";
|
||||
|
||||
compile("test01"); //use same data as test01
|
||||
@ -294,19 +308,42 @@ public class Basic {
|
||||
|
||||
jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
|
||||
"--release", "9", "-C", classes.resolve("v9").toString(), ".")
|
||||
.assertSuccess()
|
||||
.resultChecker(r ->
|
||||
assertTrue(r.outputContains("contains a class that is identical"), r.output)
|
||||
);
|
||||
.shouldHaveExitValue(SUCCESS)
|
||||
.shouldContain("contains a class that")
|
||||
.shouldContain("is identical");
|
||||
|
||||
delete(jarfile);
|
||||
deleteDir(Paths.get(usr, "classes"));
|
||||
FileUtils.deleteFileIfExistsWithRetry(Paths.get(jarfile));
|
||||
FileUtils.deleteFileTreeWithRetry(Paths.get(usr, "classes"));
|
||||
}
|
||||
|
||||
@Test
|
||||
// META-INF/versions/9 contains an identical class to previous version entry class
|
||||
// this is okay but produces warning
|
||||
public void identicalClassToPreviousVersion() throws Throwable {
|
||||
String jarfile = "test.jar";
|
||||
|
||||
compile("test01"); //use same data as test01
|
||||
|
||||
Path classes = Paths.get("classes");
|
||||
|
||||
jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
|
||||
"--release", "9", "-C", classes.resolve("v9").toString(), ".")
|
||||
.shouldHaveExitValue(SUCCESS)
|
||||
.shouldBeEmpty();
|
||||
jar("uf", jarfile,
|
||||
"--release", "10", "-C", classes.resolve("v9").toString(), ".")
|
||||
.shouldHaveExitValue(SUCCESS)
|
||||
.shouldContain("contains a class that")
|
||||
.shouldContain("is identical");
|
||||
|
||||
FileUtils.deleteFileIfExistsWithRetry(Paths.get(jarfile));
|
||||
FileUtils.deleteFileTreeWithRetry(Paths.get(usr, "classes"));
|
||||
}
|
||||
|
||||
@Test
|
||||
// resources with same name in different versions
|
||||
// this is okay but produces warning
|
||||
public void test08() throws IOException {
|
||||
public void test08() throws Throwable {
|
||||
String jarfile = "test.jar";
|
||||
|
||||
compile("test01"); //use same data as test01
|
||||
@ -320,10 +357,8 @@ public class Basic {
|
||||
|
||||
jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
|
||||
"--release", "9", "-C", classes.resolve("v9").toString(), ".")
|
||||
.assertSuccess()
|
||||
.resultChecker(r ->
|
||||
assertTrue(r.output.isEmpty(), r.output)
|
||||
);
|
||||
.shouldHaveExitValue(SUCCESS)
|
||||
.shouldBeEmpty();
|
||||
|
||||
// now add a different resource with same name to META-INF/version/9
|
||||
Files.copy(source.resolve("Main.java"), classes.resolve("v9")
|
||||
@ -331,18 +366,16 @@ public class Basic {
|
||||
|
||||
jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
|
||||
"--release", "9", "-C", classes.resolve("v9").toString(), ".")
|
||||
.assertSuccess()
|
||||
.resultChecker(r ->
|
||||
assertTrue(r.output.contains("multiple resources with same name"), r.output)
|
||||
);
|
||||
.shouldHaveExitValue(SUCCESS)
|
||||
.shouldContain("multiple resources with same name");
|
||||
|
||||
delete(jarfile);
|
||||
deleteDir(Paths.get(usr, "classes"));
|
||||
FileUtils.deleteFileIfExistsWithRetry(Paths.get(jarfile));
|
||||
FileUtils.deleteFileTreeWithRetry(Paths.get(usr, "classes"));
|
||||
}
|
||||
|
||||
@Test
|
||||
// a class with an internal name different from the external name
|
||||
public void test09() throws IOException {
|
||||
public void test09() throws Throwable {
|
||||
String jarfile = "test.jar";
|
||||
|
||||
compile("test01"); //use same data as test01
|
||||
@ -355,18 +388,16 @@ public class Basic {
|
||||
|
||||
jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
|
||||
"--release", "9", "-C", classes.resolve("v9").toString(), ".")
|
||||
.assertFailure()
|
||||
.resultChecker(r ->
|
||||
assertTrue(r.output.contains("names do not match"), r.output)
|
||||
);
|
||||
.shouldNotHaveExitValue(SUCCESS)
|
||||
.shouldContain("names do not match");
|
||||
|
||||
delete(jarfile);
|
||||
deleteDir(Paths.get(usr, "classes"));
|
||||
FileUtils.deleteFileIfExistsWithRetry(Paths.get(jarfile));
|
||||
FileUtils.deleteFileTreeWithRetry(Paths.get(usr, "classes"));
|
||||
}
|
||||
|
||||
@Test
|
||||
// assure that basic nested classes are acceptable
|
||||
public void test10() throws IOException {
|
||||
public void test10() throws Throwable {
|
||||
String jarfile = "test.jar";
|
||||
|
||||
compile("test01"); //use same data as test01
|
||||
@ -383,15 +414,15 @@ public class Basic {
|
||||
|
||||
jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
|
||||
"--release", "9", "-C", classes.resolve("v9").toString(), ".")
|
||||
.assertSuccess();
|
||||
.shouldHaveExitValue(SUCCESS);
|
||||
|
||||
delete(jarfile);
|
||||
deleteDir(Paths.get(usr, "classes"));
|
||||
FileUtils.deleteFileIfExistsWithRetry(Paths.get(jarfile));
|
||||
FileUtils.deleteFileTreeWithRetry(Paths.get(usr, "classes"));
|
||||
}
|
||||
|
||||
@Test
|
||||
// a base entry contains a nested class that doesn't have a matching top level class
|
||||
public void test11() throws IOException {
|
||||
public void test11() throws Throwable {
|
||||
String jarfile = "test.jar";
|
||||
|
||||
compile("test01"); //use same data as test01
|
||||
@ -409,30 +440,29 @@ public class Basic {
|
||||
source = Paths.get(src, "data", "test10", "v9", "version");
|
||||
javac(classes.resolve("v9"), source.resolve("Nested.java"));
|
||||
|
||||
jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
|
||||
List<String> output = jar("cf", jarfile,
|
||||
"-C", classes.resolve("base").toString(), ".",
|
||||
"--release", "9", "-C", classes.resolve("v9").toString(), ".")
|
||||
.assertFailure()
|
||||
.resultChecker(r -> {
|
||||
String[] msg = r.output.split("\\R");
|
||||
// There should be 3 error messages, cascading from the first. Once we
|
||||
// remove the base top level class, the base nested class becomes isolated,
|
||||
// also the versioned top level class becomes a new public class, thus ignored
|
||||
// for subsequent checks, leading to the associated versioned nested class
|
||||
// becoming an isolated nested class
|
||||
assertTrue(msg.length == 4);
|
||||
assertTrue(msg[0].contains("an isolated nested class"), msg[0]);
|
||||
assertTrue(msg[1].contains("contains a new public class"), msg[1]);
|
||||
assertTrue(msg[2].contains("an isolated nested class"), msg[2]);
|
||||
assertTrue(msg[3].contains("invalid multi-release jar file"), msg[3]);
|
||||
});
|
||||
.shouldNotHaveExitValue(SUCCESS)
|
||||
.asLines();
|
||||
|
||||
delete(jarfile);
|
||||
deleteDir(Paths.get(usr, "classes"));
|
||||
assertTrue(output.size() == 4);
|
||||
assertTrue(output.get(0).contains("an isolated nested class"),
|
||||
output.get(0));
|
||||
assertTrue(output.get(1).contains("contains a new public class"),
|
||||
output.get(1));
|
||||
assertTrue(output.get(2).contains("an isolated nested class"),
|
||||
output.get(2));
|
||||
assertTrue(output.get(3).contains("invalid multi-release jar file"),
|
||||
output.get(3));
|
||||
|
||||
FileUtils.deleteFileIfExistsWithRetry(Paths.get(jarfile));
|
||||
FileUtils.deleteFileTreeWithRetry(Paths.get(usr, "classes"));
|
||||
}
|
||||
|
||||
@Test
|
||||
// a versioned entry contains a nested class that doesn't have a matching top level class
|
||||
public void test12() throws IOException {
|
||||
public void test12() throws Throwable {
|
||||
String jarfile = "test.jar";
|
||||
|
||||
compile("test01"); //use same data as test01
|
||||
@ -452,178 +482,59 @@ public class Basic {
|
||||
|
||||
jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
|
||||
"--release", "9", "-C", classes.resolve("v9").toString(), ".")
|
||||
.assertFailure()
|
||||
.resultChecker(r ->
|
||||
assertTrue(r.outputContains("an isolated nested class"), r.output)
|
||||
);
|
||||
.shouldNotHaveExitValue(SUCCESS)
|
||||
.shouldContain("an isolated nested class");
|
||||
|
||||
delete(jarfile);
|
||||
deleteDir(Paths.get(usr, "classes"));
|
||||
FileUtils.deleteFileIfExistsWithRetry(Paths.get(jarfile));
|
||||
FileUtils.deleteFileTreeWithRetry(Paths.get(usr, "classes"));
|
||||
}
|
||||
|
||||
/*
|
||||
* Test Infrastructure
|
||||
*/
|
||||
private void compile(String test) throws IOException {
|
||||
Path classes = Paths.get(usr, "classes", "base");
|
||||
Files.createDirectories(classes);
|
||||
Path source = Paths.get(src, "data", test, "base", "version");
|
||||
javac(classes, source.resolve("Main.java"), source.resolve("Version.java"));
|
||||
@Test
|
||||
public void testCustomManifest() throws Throwable {
|
||||
String jarfile = "test.jar";
|
||||
|
||||
classes = Paths.get(usr, "classes", "v9");
|
||||
Files.createDirectories(classes);
|
||||
source = Paths.get(src, "data", test, "v9", "version");
|
||||
javac(classes, source.resolve("Version.java"));
|
||||
compile("test01");
|
||||
|
||||
classes = Paths.get(usr, "classes", "v10");
|
||||
Files.createDirectories(classes);
|
||||
source = Paths.get(src, "data", test, "v10", "version");
|
||||
javac(classes, source.resolve("Version.java"));
|
||||
Path classes = Paths.get("classes");
|
||||
Path manifest = Paths.get("Manifest.txt");
|
||||
|
||||
// create
|
||||
Files.write(manifest, "Class-Path: MyUtils.jar\n".getBytes());
|
||||
|
||||
jar("cfm", jarfile, manifest.toString(),
|
||||
"-C", classes.resolve("base").toString(), ".",
|
||||
"--release", "10", "-C", classes.resolve("v10").toString(), ".")
|
||||
.shouldHaveExitValue(SUCCESS)
|
||||
.shouldBeEmpty();
|
||||
|
||||
try (JarFile jf = new JarFile(new File(jarfile), true,
|
||||
ZipFile.OPEN_READ, JarFile.runtimeVersion())) {
|
||||
assertTrue(jf.isMultiRelease(), "Not multi-release jar");
|
||||
assertEquals(jf.getManifest()
|
||||
.getMainAttributes()
|
||||
.getValue("Class-Path"),
|
||||
"MyUtils.jar");
|
||||
}
|
||||
|
||||
private void checkMultiRelease(String jarFile, boolean expected) throws IOException {
|
||||
try (JarFile jf = new JarFile(new File(jarFile), true, ZipFile.OPEN_READ,
|
||||
JarFile.runtimeVersion())) {
|
||||
assertEquals(jf.isMultiRelease(), expected);
|
||||
}
|
||||
// update
|
||||
Files.write(manifest, "Multi-release: false\n".getBytes());
|
||||
|
||||
jar("ufm", jarfile, manifest.toString(),
|
||||
"-C", classes.resolve("base").toString(), ".",
|
||||
"--release", "9", "-C", classes.resolve("v10").toString(), ".")
|
||||
.shouldHaveExitValue(SUCCESS)
|
||||
.shouldContain("WARNING: Duplicate name in Manifest: Multi-release.");
|
||||
|
||||
try (JarFile jf = new JarFile(new File(jarfile), true,
|
||||
ZipFile.OPEN_READ, JarFile.runtimeVersion())) {
|
||||
assertTrue(jf.isMultiRelease(), "Not multi-release jar");
|
||||
assertEquals(jf.getManifest()
|
||||
.getMainAttributes()
|
||||
.getValue("Class-Path"),
|
||||
"MyUtils.jar");
|
||||
}
|
||||
|
||||
// compares the bytes found in the jar entries with the bytes found in the
|
||||
// corresponding data files used to create the entries
|
||||
private void compare(String jarfile, Map<String,String[]> names) throws IOException {
|
||||
try (JarFile jf = new JarFile(jarfile)) {
|
||||
for (String name : names.keySet()) {
|
||||
Path path = Paths.get("classes", names.get(name));
|
||||
byte[] b1 = Files.readAllBytes(path);
|
||||
byte[] b2;
|
||||
JarEntry je = jf.getJarEntry(name);
|
||||
try (InputStream is = jf.getInputStream(je)) {
|
||||
b2 = is.readAllBytes();
|
||||
}
|
||||
assertEquals(b1,b2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void delete(String name) throws IOException {
|
||||
Files.deleteIfExists(Paths.get(usr, name));
|
||||
}
|
||||
|
||||
private void deleteDir(Path dir) throws IOException {
|
||||
Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
Files.delete(file);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
|
||||
Files.delete(dir);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* The following methods were taken from modular jar and other jar tests
|
||||
*/
|
||||
|
||||
void javac(Path dest, Path... sourceFiles) throws IOException {
|
||||
String javac = JDKToolFinder.getJDKTool("javac");
|
||||
|
||||
List<String> commands = new ArrayList<>();
|
||||
commands.add(javac);
|
||||
String opts = System.getProperty("test.compiler.opts");
|
||||
if (!opts.isEmpty()) {
|
||||
commands.addAll(Arrays.asList(opts.split(" +")));
|
||||
}
|
||||
commands.add("-d");
|
||||
commands.add(dest.toString());
|
||||
Stream.of(sourceFiles).map(Object::toString).forEach(x -> commands.add(x));
|
||||
|
||||
quickFail(run(new ProcessBuilder(commands)));
|
||||
}
|
||||
|
||||
Result jarWithStdin(File stdinSource, String... args) {
|
||||
String jar = JDKToolFinder.getJDKTool("jar");
|
||||
List<String> commands = new ArrayList<>();
|
||||
commands.add(jar);
|
||||
commands.addAll(Utils.getForwardVmOptions());
|
||||
Stream.of(args).forEach(x -> commands.add(x));
|
||||
ProcessBuilder p = new ProcessBuilder(commands);
|
||||
if (stdinSource != null)
|
||||
p.redirectInput(stdinSource);
|
||||
return run(p);
|
||||
}
|
||||
|
||||
Result jar(String... args) {
|
||||
return jarWithStdin(null, args);
|
||||
}
|
||||
|
||||
void quickFail(Result r) {
|
||||
if (r.ec != 0)
|
||||
throw new RuntimeException(r.output);
|
||||
}
|
||||
|
||||
Result run(ProcessBuilder pb) {
|
||||
Process p;
|
||||
out.printf("Running: %s%n", pb.command());
|
||||
try {
|
||||
p = pb.start();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(
|
||||
format("Couldn't start process '%s'", pb.command()), e);
|
||||
}
|
||||
|
||||
String output;
|
||||
try {
|
||||
output = toString(p.getInputStream(), p.getErrorStream());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(
|
||||
format("Couldn't read process output '%s'", pb.command()), e);
|
||||
}
|
||||
|
||||
try {
|
||||
p.waitFor();
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(
|
||||
format("Process hasn't finished '%s'", pb.command()), e);
|
||||
}
|
||||
return new Result(p.exitValue(), output);
|
||||
}
|
||||
|
||||
String toString(InputStream in1, InputStream in2) throws IOException {
|
||||
try (ByteArrayOutputStream dst = new ByteArrayOutputStream();
|
||||
InputStream concatenated = new SequenceInputStream(in1, in2)) {
|
||||
concatenated.transferTo(dst);
|
||||
return new String(dst.toByteArray(), "UTF-8");
|
||||
}
|
||||
}
|
||||
|
||||
static class Result {
|
||||
final int ec;
|
||||
final String output;
|
||||
|
||||
private Result(int ec, String output) {
|
||||
this.ec = ec;
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
boolean outputContains(String msg) {
|
||||
return Arrays.stream(output.split("\\R"))
|
||||
.collect(Collectors.joining(" "))
|
||||
.contains(msg);
|
||||
}
|
||||
|
||||
Result assertSuccess() {
|
||||
assertTrue(ec == 0, format("ec: %d, output: %s", ec, output));
|
||||
return this;
|
||||
}
|
||||
Result assertFailure() {
|
||||
assertTrue(ec != 0, format("ec: %d, output: %s", ec, output));
|
||||
return this;
|
||||
}
|
||||
Result resultChecker(Consumer<Result> r) { r.accept(this); return this; }
|
||||
FileUtils.deleteFileIfExistsWithRetry(Paths.get(jarfile));
|
||||
FileUtils.deleteFileTreeWithRetry(Paths.get(usr, "classes"));
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -28,76 +28,65 @@
|
||||
* jdk.compiler
|
||||
* jdk.jartool
|
||||
* @build jdk.test.lib.JDKToolFinder jdk.test.lib.Utils
|
||||
* @build MRTestBase
|
||||
* @run testng Basic1
|
||||
*/
|
||||
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
import org.testng.annotations.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.*;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.jar.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.*;
|
||||
|
||||
import jdk.test.lib.JDKToolFinder;
|
||||
import jdk.test.lib.Utils;
|
||||
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static java.lang.System.out;
|
||||
|
||||
public class Basic1 {
|
||||
private final String src = System.getProperty("test.src", ".");
|
||||
public class Basic1 extends MRTestBase {
|
||||
|
||||
@BeforeTest
|
||||
public void setup() throws IOException {
|
||||
public void setup() throws Throwable {
|
||||
String test = "test01";
|
||||
Path classes = Paths.get("classes", "base");
|
||||
Files.createDirectories(classes);
|
||||
Path source = Paths.get(src, "data", test, "base", "version");
|
||||
javac(classes, source.resolve("Main.java"), source.resolve("Version.java"));
|
||||
Path classes = Paths.get("classes");
|
||||
|
||||
Path v9 = Paths.get("v9");
|
||||
Path base = classes.resolve("base");
|
||||
Files.createDirectories(base);
|
||||
Path source = Paths.get(src, "data", test, "base", "version");
|
||||
javac(base, source.resolve("Main.java"), source.resolve("Version.java"));
|
||||
|
||||
Path v9 = classes.resolve("v9");
|
||||
Files.createDirectories(v9);
|
||||
source = Paths.get(src, "data", test, "v9", "version");
|
||||
javac(v9, source.resolve("Version.java"));
|
||||
|
||||
Path v10 = Paths.get("v10");
|
||||
Path v10 = classes.resolve("v10");
|
||||
Files.createDirectories(v10);
|
||||
source = Paths.get(src, "data", test, "v10", "version");
|
||||
javac(v10, source.resolve("Version.java"));
|
||||
|
||||
Path v10_1 = Paths.get("v10_1").resolve("META-INF").resolve("versions").resolve("v10");
|
||||
Path v10_1 = classes.resolve("v10_1").resolve("META-INF").resolve("versions").resolve("v10");
|
||||
Files.createDirectories(v10_1);
|
||||
source = Paths.get(src, "data", test, "v10", "version");
|
||||
javac(v10_1, source.resolve("Version.java"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() throws IOException {
|
||||
public void test() throws Throwable {
|
||||
String jarfile = "test.jar";
|
||||
Path classes = Paths.get("classes");
|
||||
Path v9 = Paths.get("v9");
|
||||
Path v10 = Paths.get("v10");
|
||||
|
||||
jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
|
||||
Path base = classes.resolve("base");
|
||||
Path v9 = classes.resolve("v9");
|
||||
Path v10 = classes.resolve("v10");
|
||||
|
||||
jar("cf", jarfile, "-C", base.toString(), ".",
|
||||
"--release", "9", "-C", v9.toString(), ".",
|
||||
"--release", "10", "-C", v10.toString(), ".")
|
||||
.assertSuccess();
|
||||
.shouldHaveExitValue(SUCCESS);
|
||||
|
||||
checkMultiRelease(jarfile, true);
|
||||
|
||||
Map<String, String[]> names = Map.of(
|
||||
"version/Main.class",
|
||||
new String[] {"classes", "base", "version", "Main.class"},
|
||||
new String[]{"base", "version", "Main.class"},
|
||||
|
||||
"version/Version.class",
|
||||
new String[] {"classes", "base", "version", "Version.class"},
|
||||
new String[]{"base", "version", "Version.class"},
|
||||
|
||||
"META-INF/versions/9/version/Version.class",
|
||||
new String[] {"v9", "version", "Version.class"},
|
||||
@ -109,144 +98,16 @@ public class Basic1 {
|
||||
compare(jarfile, names);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testFail() throws IOException {
|
||||
public void testFail() throws Throwable {
|
||||
String jarfile = "test.jar";
|
||||
Path classes = Paths.get("classes");
|
||||
Path v10 = Paths.get("v10_1");
|
||||
Path base = classes.resolve("base");
|
||||
Path v10 = classes.resolve("v10_1");
|
||||
|
||||
jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
|
||||
jar("cf", jarfile, "-C", base.toString(), ".",
|
||||
"--release", "10", "-C", v10.toString(), ".")
|
||||
.assertFailure()
|
||||
.outputContains("unexpected versioned entry META-INF/versions/");
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void checkMultiRelease(String jarFile, boolean expected) throws IOException {
|
||||
try (JarFile jf = new JarFile(new File(jarFile), true, ZipFile.OPEN_READ,
|
||||
JarFile.runtimeVersion())) {
|
||||
assertEquals(jf.isMultiRelease(), expected);
|
||||
}
|
||||
}
|
||||
|
||||
// compares the bytes found in the jar entries with the bytes found in the
|
||||
// corresponding data files used to create the entries
|
||||
private void compare(String jarfile, Map<String,String[]> names) throws IOException {
|
||||
try (JarFile jf = new JarFile(jarfile)) {
|
||||
for (String name : names.keySet()) {
|
||||
Path path = Paths.get("", names.get(name));
|
||||
byte[] b1 = Files.readAllBytes(path);
|
||||
byte[] b2;
|
||||
JarEntry je = jf.getJarEntry(name);
|
||||
try (InputStream is = jf.getInputStream(je)) {
|
||||
b2 = is.readAllBytes();
|
||||
}
|
||||
assertEquals(b1,b2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The following methods were taken from modular jar and other jar tests
|
||||
*/
|
||||
|
||||
void javac(Path dest, Path... sourceFiles) throws IOException {
|
||||
String javac = JDKToolFinder.getJDKTool("javac");
|
||||
|
||||
List<String> commands = new ArrayList<>();
|
||||
commands.add(javac);
|
||||
String opts = System.getProperty("test.compiler.opts");
|
||||
if (!opts.isEmpty()) {
|
||||
commands.addAll(Arrays.asList(opts.split(" +")));
|
||||
}
|
||||
commands.add("-d");
|
||||
commands.add(dest.toString());
|
||||
Stream.of(sourceFiles).map(Object::toString).forEach(x -> commands.add(x));
|
||||
|
||||
quickFail(run(new ProcessBuilder(commands)));
|
||||
}
|
||||
|
||||
Result jarWithStdin(File stdinSource, String... args) {
|
||||
String jar = JDKToolFinder.getJDKTool("jar");
|
||||
List<String> commands = new ArrayList<>();
|
||||
commands.add(jar);
|
||||
commands.addAll(Utils.getForwardVmOptions());
|
||||
Stream.of(args).forEach(x -> commands.add(x));
|
||||
ProcessBuilder p = new ProcessBuilder(commands);
|
||||
if (stdinSource != null)
|
||||
p.redirectInput(stdinSource);
|
||||
return run(p);
|
||||
}
|
||||
|
||||
Result jar(String... args) {
|
||||
return jarWithStdin(null, args);
|
||||
}
|
||||
|
||||
void quickFail(Result r) {
|
||||
if (r.ec != 0)
|
||||
throw new RuntimeException(r.output);
|
||||
}
|
||||
|
||||
Result run(ProcessBuilder pb) {
|
||||
Process p;
|
||||
out.printf("Running: %s%n", pb.command());
|
||||
try {
|
||||
p = pb.start();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(
|
||||
format("Couldn't start process '%s'", pb.command()), e);
|
||||
}
|
||||
|
||||
String output;
|
||||
try {
|
||||
output = toString(p.getInputStream(), p.getErrorStream());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(
|
||||
format("Couldn't read process output '%s'", pb.command()), e);
|
||||
}
|
||||
|
||||
try {
|
||||
p.waitFor();
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(
|
||||
format("Process hasn't finished '%s'", pb.command()), e);
|
||||
}
|
||||
return new Result(p.exitValue(), output);
|
||||
}
|
||||
|
||||
String toString(InputStream in1, InputStream in2) throws IOException {
|
||||
try (ByteArrayOutputStream dst = new ByteArrayOutputStream();
|
||||
InputStream concatenated = new SequenceInputStream(in1, in2)) {
|
||||
concatenated.transferTo(dst);
|
||||
return new String(dst.toByteArray(), "UTF-8");
|
||||
}
|
||||
}
|
||||
|
||||
static class Result {
|
||||
final int ec;
|
||||
final String output;
|
||||
|
||||
private Result(int ec, String output) {
|
||||
this.ec = ec;
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
boolean outputContains(String msg) {
|
||||
return Arrays.stream(output.split("\\R"))
|
||||
.collect(Collectors.joining(" "))
|
||||
.contains(msg);
|
||||
}
|
||||
|
||||
Result assertSuccess() {
|
||||
assertTrue(ec == 0, format("ec: %d, output: %s", ec, output));
|
||||
return this;
|
||||
}
|
||||
Result assertFailure() {
|
||||
assertTrue(ec != 0, format("ec: %d, output: %s", ec, output));
|
||||
return this;
|
||||
}
|
||||
Result resultChecker(Consumer<Result> r) { r.accept(this); return this; }
|
||||
.shouldNotHaveExitValue(SUCCESS)
|
||||
.shouldContain("unexpected versioned entry META-INF/versions/");
|
||||
}
|
||||
}
|
||||
|
130
jdk/test/tools/jar/multiRelease/MRTestBase.java
Normal file
130
jdk/test/tools/jar/multiRelease/MRTestBase.java
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import jdk.test.lib.JDKToolFinder;
|
||||
import jdk.test.lib.Utils;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
public class MRTestBase {
|
||||
|
||||
public static final int SUCCESS = 0;
|
||||
|
||||
protected final String src = System.getProperty("test.src", ".");
|
||||
protected final String usr = System.getProperty("user.dir", ".");
|
||||
|
||||
protected void compile(String test) throws Throwable {
|
||||
Path classes = Paths.get(usr, "classes", "base");
|
||||
Files.createDirectories(classes);
|
||||
Path source = Paths.get(src, "data", test, "base", "version");
|
||||
javac(classes, source.resolve("Main.java"), source.resolve("Version.java"));
|
||||
|
||||
classes = Paths.get(usr, "classes", "v9");
|
||||
Files.createDirectories(classes);
|
||||
source = Paths.get(src, "data", test, "v9", "version");
|
||||
javac(classes, source.resolve("Version.java"));
|
||||
|
||||
classes = Paths.get(usr, "classes", "v10");
|
||||
Files.createDirectories(classes);
|
||||
source = Paths.get(src, "data", test, "v10", "version");
|
||||
javac(classes, source.resolve("Version.java"));
|
||||
}
|
||||
|
||||
protected void checkMultiRelease(String jarFile,
|
||||
boolean expected) throws IOException {
|
||||
try (JarFile jf = new JarFile(new File(jarFile), true,
|
||||
ZipFile.OPEN_READ, JarFile.runtimeVersion())) {
|
||||
assertEquals(jf.isMultiRelease(), expected);
|
||||
}
|
||||
}
|
||||
|
||||
// compares the bytes found in the jar entries with the bytes found in the
|
||||
// corresponding data files used to create the entries
|
||||
protected void compare(String jarfile,
|
||||
Map<String, String[]> names) throws IOException {
|
||||
try (JarFile jf = new JarFile(jarfile)) {
|
||||
for (String name : names.keySet()) {
|
||||
Path path = Paths.get("classes", names.get(name));
|
||||
byte[] b1 = Files.readAllBytes(path);
|
||||
byte[] b2;
|
||||
JarEntry je = jf.getJarEntry(name);
|
||||
try (InputStream is = jf.getInputStream(je)) {
|
||||
b2 = is.readAllBytes();
|
||||
}
|
||||
assertEquals(b1, b2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void javac(Path dest, Path... sourceFiles) throws Throwable {
|
||||
String javac = JDKToolFinder.getJDKTool("javac");
|
||||
|
||||
List<String> commands = new ArrayList<>();
|
||||
commands.add(javac);
|
||||
String opts = System.getProperty("test.compiler.opts");
|
||||
if (!opts.isEmpty()) {
|
||||
commands.addAll(Arrays.asList(opts.split(" +")));
|
||||
}
|
||||
commands.addAll(Utils.getForwardVmOptions());
|
||||
commands.add("-d");
|
||||
commands.add(dest.toString());
|
||||
Stream.of(sourceFiles)
|
||||
.map(Object::toString)
|
||||
.forEach(x -> commands.add(x));
|
||||
|
||||
ProcessTools.executeCommand(new ProcessBuilder(commands))
|
||||
.shouldHaveExitValue(SUCCESS);
|
||||
}
|
||||
|
||||
OutputAnalyzer jarWithStdin(File stdinSource,
|
||||
String... args) throws Throwable {
|
||||
|
||||
String jar = JDKToolFinder.getJDKTool("jar");
|
||||
List<String> commands = new ArrayList<>();
|
||||
commands.add(jar);
|
||||
commands.addAll(Utils.getForwardVmOptions());
|
||||
Stream.of(args).forEach(x -> commands.add(x));
|
||||
ProcessBuilder p = new ProcessBuilder(commands);
|
||||
if (stdinSource != null)
|
||||
p.redirectInput(stdinSource);
|
||||
return ProcessTools.executeCommand(p);
|
||||
}
|
||||
|
||||
OutputAnalyzer jar(String... args) throws Throwable {
|
||||
return jarWithStdin(null, args);
|
||||
}
|
||||
}
|
@ -8,7 +8,7 @@ public class Version {
|
||||
protected void doNothing() {
|
||||
}
|
||||
|
||||
// extra publc method
|
||||
// extra public method
|
||||
public void anyName() {
|
||||
}
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ import tests.Helper;
|
||||
* @modules java.base/jdk.internal.jimage
|
||||
* jdk.jdeps/com.sun.tools.classfile
|
||||
* jdk.jlink/jdk.tools.jlink.internal
|
||||
* jdk.jlink/jdk.tools.jlink.plugin
|
||||
* jdk.jlink/jdk.tools.jmod
|
||||
* jdk.jlink/jdk.tools.jimage
|
||||
* jdk.compiler
|
||||
|
@ -48,6 +48,7 @@ import jdk.tools.jlink.plugin.ResourcePool;
|
||||
* @author Jean-Francois Denise
|
||||
* @modules jdk.jlink/jdk.tools.jlink.internal
|
||||
* jdk.jlink/jdk.tools.jlink.builder
|
||||
* jdk.jlink/jdk.tools.jlink.plugin
|
||||
* java.base/jdk.internal.jimage
|
||||
* @run main/othervm -verbose:gc -Xmx1g ImageFileCreatorTest
|
||||
*/
|
||||
|
@ -26,6 +26,7 @@
|
||||
* @summary Test a pool containing external files.
|
||||
* @author Andrei Eremeev
|
||||
* @modules jdk.jlink/jdk.tools.jlink.internal
|
||||
* jdk.jlink/jdk.tools.jlink.plugin
|
||||
* @run build ImageFilePoolTest
|
||||
* @run main ImageFilePoolTest
|
||||
*/
|
||||
|
@ -62,6 +62,7 @@ import tests.JImageGenerator;
|
||||
* jdk.jlink/jdk.tools.jlink.builder
|
||||
* jdk.jlink/jdk.tools.jlink.internal
|
||||
* jdk.jlink/jdk.tools.jlink.internal.plugins
|
||||
* jdk.jlink/jdk.tools.jlink.plugin
|
||||
* jdk.jlink/jdk.tools.jmod
|
||||
* jdk.jlink/jdk.tools.jimage
|
||||
* jdk.compiler
|
||||
|
@ -29,6 +29,7 @@
|
||||
* @modules java.base/jdk.internal.jimage
|
||||
* jdk.jdeps/com.sun.tools.classfile
|
||||
* jdk.jlink/jdk.tools.jlink.internal
|
||||
* jdk.jlink/jdk.tools.jlink.plugin
|
||||
* jdk.jlink/jdk.tools.jmod
|
||||
* jdk.jlink/jdk.tools.jimage
|
||||
* jdk.compiler
|
||||
|
@ -39,6 +39,7 @@ import tests.Helper;
|
||||
* @modules java.base/jdk.internal.jimage
|
||||
* jdk.jdeps/com.sun.tools.classfile
|
||||
* jdk.jlink/jdk.tools.jlink.internal
|
||||
* jdk.jlink/jdk.tools.jlink.plugin
|
||||
* jdk.jlink/jdk.tools.jmod
|
||||
* jdk.jlink/jdk.tools.jimage
|
||||
* jdk.compiler
|
||||
|
@ -46,6 +46,7 @@ import tests.Helper;
|
||||
* @modules java.base/jdk.internal.jimage
|
||||
* jdk.jdeps/com.sun.tools.classfile
|
||||
* jdk.jlink/jdk.tools.jlink.internal
|
||||
* jdk.jlink/jdk.tools.jlink.plugin
|
||||
* jdk.jlink/jdk.tools.jmod
|
||||
* jdk.jlink/jdk.tools.jimage
|
||||
* jdk.compiler
|
||||
|
@ -48,6 +48,7 @@ import tests.JImageGenerator;
|
||||
* @modules java.base/jdk.internal.jimage
|
||||
* jdk.jdeps/com.sun.tools.classfile
|
||||
* jdk.jlink/jdk.tools.jlink.internal
|
||||
* jdk.jlink/jdk.tools.jlink.plugin
|
||||
* jdk.jlink/jdk.tools.jimage
|
||||
* jdk.compiler
|
||||
* @build tests.*
|
||||
|
85
jdk/test/tools/jlink/ResourceDuplicateCheckTest.java
Normal file
85
jdk/test/tools/jlink/ResourceDuplicateCheckTest.java
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8168254
|
||||
* @summary Detect duplicated resources in packaged modules
|
||||
* @modules jdk.jlink/jdk.tools.jlink.builder
|
||||
* jdk.jlink/jdk.tools.jlink.internal
|
||||
* jdk.jlink/jdk.tools.jlink.plugin
|
||||
* @run build ResourceDuplicateCheckTest
|
||||
* @run main ResourceDuplicateCheckTest
|
||||
*/
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Collections;
|
||||
import jdk.tools.jlink.builder.DefaultImageBuilder;
|
||||
import jdk.tools.jlink.internal.ResourcePoolEntryFactory;
|
||||
import jdk.tools.jlink.internal.ResourcePoolManager;
|
||||
import jdk.tools.jlink.plugin.PluginException;
|
||||
import jdk.tools.jlink.plugin.ResourcePoolEntry;
|
||||
|
||||
public class ResourceDuplicateCheckTest {
|
||||
public static void main(String[] args) throws Exception {
|
||||
new ResourceDuplicateCheckTest().test();
|
||||
}
|
||||
|
||||
public void test() throws Exception {
|
||||
ResourcePoolManager input = new ResourcePoolManager();
|
||||
// need java.base module info because OS name is retrieved from it from storeFiles
|
||||
input.add(ResourcePoolEntryFactory.create("/java.base/module-info.class",
|
||||
ResourcePoolEntry.Type.CLASS_OR_RESOURCE, getJavaBaseModuleInfo()));
|
||||
|
||||
// same NATIVE_CMD from two different modules
|
||||
input.add(newInMemoryImageFile("/com.acme/bin/myexec",
|
||||
ResourcePoolEntry.Type.NATIVE_CMD, "mylib"));
|
||||
input.add(newInMemoryImageFile("/com.foo/bin/myexec",
|
||||
ResourcePoolEntry.Type.NATIVE_CMD, "mylib"));
|
||||
Path root = Paths.get(System.getProperty("test.classes"));
|
||||
DefaultImageBuilder writer = new DefaultImageBuilder(root, Collections.emptyMap());
|
||||
try {
|
||||
writer.storeFiles(input.resourcePool());
|
||||
} catch (PluginException pe) {
|
||||
if (! pe.getMessage().contains("Duplicate resources:")) {
|
||||
throw new AssertionError("expected duplicate resources message");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] getJavaBaseModuleInfo() throws Exception {
|
||||
Path path = FileSystems.
|
||||
getFileSystem(URI.create("jrt:/")).
|
||||
getPath("/modules/java.base/module-info.class");
|
||||
return Files.readAllBytes(path);
|
||||
}
|
||||
|
||||
private static ResourcePoolEntry newInMemoryImageFile(String path,
|
||||
ResourcePoolEntry.Type type, String content) {
|
||||
return ResourcePoolEntryFactory.create(path, type, content.getBytes());
|
||||
}
|
||||
}
|
@ -26,6 +26,7 @@
|
||||
* @summary Test a pool containing jimage resources and classes.
|
||||
* @author Jean-Francois Denise
|
||||
* @modules jdk.jlink/jdk.tools.jlink.internal
|
||||
* jdk.jlink/jdk.tools.jlink.plugin
|
||||
* @run build ResourcePoolTest
|
||||
* @run main ResourcePoolTest
|
||||
*/
|
||||
|
@ -28,6 +28,7 @@
|
||||
* @modules java.base/jdk.internal.jimage.decompressor
|
||||
* jdk.jlink/jdk.tools.jlink.internal
|
||||
* jdk.jlink/jdk.tools.jlink.internal.plugins
|
||||
* jdk.jlink/jdk.tools.jlink.plugin
|
||||
* @run main CompressorPluginTest
|
||||
*/
|
||||
import java.net.URI;
|
||||
|
@ -27,6 +27,7 @@
|
||||
* @author Jean-Francois Denise
|
||||
* @modules jdk.jlink/jdk.tools.jlink.internal
|
||||
* jdk.jlink/jdk.tools.jlink.internal.plugins
|
||||
* jdk.jlink/jdk.tools.jlink.plugin
|
||||
* @run main ExcludeFilesPluginTest
|
||||
*/
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
* @author Jean-Francois Denise
|
||||
* @modules jdk.jlink/jdk.tools.jlink.internal
|
||||
* jdk.jlink/jdk.tools.jlink.internal.plugins
|
||||
* jdk.jlink/jdk.tools.jlink.plugin
|
||||
* @run main ExcludePluginTest
|
||||
*/
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
* @author Jean-Francois Denise
|
||||
* @modules jdk.jlink/jdk.tools.jlink.internal
|
||||
* jdk.jlink/jdk.tools.jlink.internal.plugins
|
||||
* jdk.jlink/jdk.tools.jlink.plugin
|
||||
* @run main ExcludeVMPluginTest
|
||||
*/
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
@ -48,6 +48,7 @@ import tests.Result;
|
||||
* jdk.jdeps/com.sun.tools.classfile
|
||||
* jdk.jlink/jdk.tools.jlink.internal
|
||||
* jdk.jlink/jdk.tools.jlink.internal.plugins
|
||||
* jdk.jlink/jdk.tools.jlink.plugin
|
||||
* jdk.jlink/jdk.tools.jmod
|
||||
* jdk.jlink/jdk.tools.jimage
|
||||
* jdk.compiler
|
||||
|
@ -25,8 +25,9 @@
|
||||
* @test
|
||||
* @summary Test last sorter property
|
||||
* @author Jean-Francois Denise
|
||||
* @modules jdk.jlink/jdk.tools.jlink.internal
|
||||
* jdk.jlink/jdk.tools.jlink
|
||||
* @modules jdk.jlink/jdk.tools.jlink
|
||||
* jdk.jlink/jdk.tools.jlink.internal
|
||||
* jdk.jlink/jdk.tools.jlink.plugin
|
||||
* @run main/othervm LastSorterTest
|
||||
*/
|
||||
|
||||
|
@ -25,8 +25,9 @@
|
||||
* @test
|
||||
* @summary Negative test for ImagePluginStack.
|
||||
* @author Andrei Eremeev
|
||||
* @modules jdk.jlink/jdk.tools.jlink.internal
|
||||
* jdk.jlink/jdk.tools.jlink
|
||||
* @modules jdk.jlink/jdk.tools.jlink
|
||||
* jdk.jlink/jdk.tools.jlink.internal
|
||||
* jdk.jlink/jdk.tools.jlink.plugin
|
||||
* @run main/othervm PluginsNegativeTest
|
||||
*/
|
||||
import java.lang.reflect.Layer;
|
||||
|
@ -25,8 +25,9 @@
|
||||
* @test
|
||||
* @summary Test previsitor
|
||||
* @author Andrei Eremeev
|
||||
* @modules jdk.jlink/jdk.tools.jlink.internal
|
||||
* jdk.jlink/jdk.tools.jlink
|
||||
* @modules jdk.jlink/jdk.tools.jlink
|
||||
* jdk.jlink/jdk.tools.jlink.internal
|
||||
* jdk.jlink/jdk.tools.jlink.plugin
|
||||
* @run main/othervm PrevisitorTest
|
||||
*/
|
||||
import java.nio.ByteOrder;
|
||||
|
@ -30,6 +30,7 @@
|
||||
* java.base/jdk.internal.jimage.decompressor
|
||||
* jdk.jlink/jdk.tools.jlink.internal
|
||||
* jdk.jlink/jdk.tools.jlink.internal.plugins
|
||||
* jdk.jlink/jdk.tools.jlink.plugin
|
||||
* jdk.jlink/jdk.tools.jmod
|
||||
* jdk.jlink/jdk.tools.jimage
|
||||
* jdk.jdeps/com.sun.tools.classfile
|
||||
|
@ -30,6 +30,7 @@
|
||||
* @modules java.base/jdk.internal.jimage
|
||||
* jdk.jlink/jdk.tools.jlink.internal
|
||||
* jdk.jlink/jdk.tools.jlink.internal.plugins
|
||||
* jdk.jlink/jdk.tools.jlink.plugin
|
||||
* jdk.jlink/jdk.tools.jimage
|
||||
* jdk.jlink/jdk.tools.jmod
|
||||
* jdk.jdeps/com.sun.tools.classfile
|
||||
|
@ -29,7 +29,7 @@
|
||||
* @modules jdk.compiler
|
||||
* jdk.jlink
|
||||
* @build jdk.testlibrary.FileUtils CompilerUtils
|
||||
* @run testng JmodTest
|
||||
* @run testng/othervm -Djava.io.tmpdir=. JmodTest
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
@ -40,8 +40,10 @@ import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.spi.ToolProvider;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import jdk.testlibrary.FileUtils;
|
||||
import jdk.testlibrary.JDKToolFinder;
|
||||
import org.testng.annotations.BeforeTest;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
@ -593,9 +595,7 @@ public class JmodTest {
|
||||
findTmpFiles(filename).forEach(tmp -> {
|
||||
try {
|
||||
FileUtils.deleteFileIfExistsWithRetry(tmp);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
} catch (IOException e) {}
|
||||
});
|
||||
|
||||
String cp = EXPLODED_DIR.resolve("foo").resolve("classes") + File.pathSeparator +
|
||||
@ -608,17 +608,25 @@ public class JmodTest {
|
||||
.assertFailure()
|
||||
.resultChecker(r -> {
|
||||
assertContains(r.output, "unnamed package");
|
||||
Set<Path> tmpfiles = findTmpFiles(filename).collect(toSet());
|
||||
List<Path> tmpfiles = findTmpFiles(filename);
|
||||
assertTrue(tmpfiles.isEmpty(), "Unexpected tmp file:" + tmpfiles);
|
||||
});
|
||||
}
|
||||
|
||||
private Stream<Path> findTmpFiles(String prefix) {
|
||||
try {
|
||||
/*
|
||||
* Returns the list of writeable tmp files with the given prefix.
|
||||
*
|
||||
* Ignore the non-writeable tmp files because this test is possibly
|
||||
* running by another user.
|
||||
*/
|
||||
private List<Path> findTmpFiles(String prefix) {
|
||||
Path tmpdir = Paths.get(System.getProperty("java.io.tmpdir"));
|
||||
return Files.find(tmpdir, 1, (p, attrs) ->
|
||||
p.getFileName().toString().startsWith(prefix)
|
||||
&& p.getFileName().toString().endsWith(".tmp"));
|
||||
try (Stream<Path> stream = Files.list(tmpdir)) {
|
||||
return stream.filter(p -> {
|
||||
String fn = p.getFileName().toString();
|
||||
return Files.isWritable(p)
|
||||
&& fn.startsWith(prefix) && fn.endsWith(".tmp");
|
||||
}).collect(Collectors.toList());
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
|
@ -111,6 +111,7 @@ class Utils {
|
||||
|
||||
compiler("-d",
|
||||
XCLASSES.getName(),
|
||||
"--add-modules=jdk.jdeps",
|
||||
"--add-exports=jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED",
|
||||
"@" + tmpFile.getAbsolutePath());
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user