This commit is contained in:
Henry Jen 2017-01-19 07:02:33 -08:00
commit d7509c02b3
50 changed files with 1520 additions and 905 deletions

View File

@ -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) \

View File

@ -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,
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();
}
});
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
enclosingCandidate.checkMemberAccess(sm, Member.DECLARED,
Reflection.getCallerClass(), true);
}
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.
*/
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;
}
ReflectionFactory fact = getReflectionFactory();
for (Method m : candidates) {
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,
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();
}
});
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
enclosingCandidate.checkMemberAccess(sm, Member.DECLARED,
Reflection.getCallerClass(), true);
}
Constructor<?>[] candidates = enclosingCandidate
.privateGetDeclaredConstructors(false);
/*
* Loop over all declared constructors; match number
* of and type of parameters.
*/
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;
ReflectionFactory fact = getReflectionFactory();
for (Constructor<?> c : candidates) {
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,51 +2730,49 @@ 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) {
/* 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);
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 = caller.getClassLoader0();
if (which != Member.PUBLIC) {
final ClassLoader cl = getClassLoader0();
if (which != Member.PUBLIC) {
if (ccl != cl) {
s.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);
}
if (ccl != cl) {
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) {
final ClassLoader cl = getClassLoader0();
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) {
// 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);
}
if (ReflectUtil.needsPackageAccessCheck(ccl, cl)) {
String pkg = this.getPackageName();
if (pkg != null && !pkg.isEmpty()) {
// skip the package access check on a proxy class in default proxy package
if (!Proxy.isProxyClass(this) || ReflectUtil.isNonPublicProxyClass(this)) {
sm.checkPackageAccess(pkg);
}
}
// check package access on the proxy interfaces
if (checkProxyInterfaces && Proxy.isProxyClass(this)) {
ReflectUtil.checkProxyPackageAccess(ccl, this.getInterfaces());
}
}
// check package access on the proxy interfaces
if (checkProxyInterfaces && Proxy.isProxyClass(this)) {
ReflectUtil.checkProxyPackageAccess(ccl, this.getInterfaces());
}
}
@ -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];

View File

@ -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);

View File

@ -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<>();
}

View File

@ -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;
}
);

View File

@ -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);
}
/**
@ -255,7 +280,7 @@ public final class ReflectUtil {
// check if it is a valid proxy instance
if (proxy == null || !Proxy.isProxyClass(proxy.getClass())) {
throw new IllegalArgumentException("Not a Proxy instance");
}
}
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalArgumentException("Can't handle static method");
}

View File

@ -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.
*

View File

@ -24,8 +24,6 @@
*/
module jdk.jlink {
exports jdk.tools.jlink.plugin;
requires jdk.internal.opt;
requires jdk.jdeps;

View File

@ -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);
}

View File

@ -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,33 +34,64 @@ 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) {
CharsetDecoder cd = decoder().reset();
int len = (int)(length * cd.maxCharsPerByte());
char[] ca = new char[len];
if (len == 0)
return new String(ca);
ByteBuffer bb = ByteBuffer.wrap(ba, 0, length);
CharBuffer cb = CharBuffer.wrap(ca);
CoderResult cr = cd.decode(bb, cb, true);
if (!cr.isUnderflow())
throw new IllegalArgumentException(cr.toString());
cr = cd.flush(cb);
if (!cr.isUnderflow())
throw new IllegalArgumentException(cr.toString());
return new String(ca, 0, cb.position());
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) {
return toString(ba, ba.length);
CharsetDecoder cd = decoder().reset();
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, ba.length);
CharBuffer cb = CharBuffer.wrap(ca);
CoderResult cr = cd.decode(bb, cb, true);
if (!cr.isUnderflow())
throw new IllegalArgumentException(cr.toString());
cr = cd.flush(cb);
if (!cr.isUnderflow())
throw new IllegalArgumentException(cr.toString());
return new String(ca, 0, cb.position());
}
byte[] getBytes(String s) {
@ -69,62 +100,29 @@ final class ZipCoder {
int len = (int)(ca.length * ce.maxBytesPerChar());
byte[] ba = new byte[len];
if (len == 0)
return ba;
return ba;
ByteBuffer bb = ByteBuffer.wrap(ba);
CharBuffer cb = CharBuffer.wrap(ca);
CoderResult cr = ce.encode(cb, bb, true);
if (!cr.isUnderflow())
throw new IllegalArgumentException(cr.toString());
throw new IllegalArgumentException(cr.toString());
cr = ce.flush(bb);
if (!cr.isUnderflow())
throw new IllegalArgumentException(cr.toString());
throw new IllegalArgumentException(cr.toString());
if (bb.position() == ba.length) // defensive copy?
return ba;
return ba;
else
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);
return Arrays.copyOf(ba, bb.position());
}
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<>();
@ -133,10 +131,10 @@ final class ZipCoder {
private CharsetDecoder decoder() {
CharsetDecoder dec = decTL.get();
if (dec == null) {
dec = cs.newDecoder()
.onMalformedInput(CodingErrorAction.REPORT)
.onUnmappableCharacter(CodingErrorAction.REPORT);
decTL.set(dec);
dec = cs.newDecoder()
.onMalformedInput(CodingErrorAction.REPORT)
.onUnmappableCharacter(CodingErrorAction.REPORT);
decTL.set(dec);
}
return dec;
}
@ -144,10 +142,10 @@ final class ZipCoder {
private CharsetEncoder encoder() {
CharsetEncoder enc = encTL.get();
if (enc == null) {
enc = cs.newEncoder()
.onMalformedInput(CodingErrorAction.REPORT)
.onUnmappableCharacter(CodingErrorAction.REPORT);
encTL.set(enc);
enc = cs.newEncoder()
.onMalformedInput(CodingErrorAction.REPORT)
.onUnmappableCharacter(CodingErrorAction.REPORT);
encTL.set(enc);
}
return enc;
}

View File

@ -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,8 +314,8 @@ class ZipFileSystem extends FileSystem {
IndexNode inode = getInode(path);
if (inode == null)
return null;
e = new Entry(inode.name); // pseudo directory
e.method = METHOD_STORED; // STORED for dir
e = new Entry(inode.name, inode.isdir); // pseudo directory
e.method = METHOD_STORED; // STORED for dir
e.mtime = e.atime = e.ctime = zfsDefaultTimeStamp;
}
} finally {
@ -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 {
@ -463,7 +464,7 @@ class ZipFileSystem extends FileSystem {
} else {
checkParents(dst);
}
Entry u = new Entry(eSrc, Entry.COPY); // copy eSrc entry
Entry u = new Entry(eSrc, Entry.COPY); // copy eSrc entry
u.name(dst); // change name
if (eSrc.type == Entry.NEW || eSrc.type == Entry.FILECH)
{
@ -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;

View File

@ -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,12 +67,7 @@ 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);
}
this.path = normalize(path);
}
@Override
@ -84,33 +78,31 @@ final class ZipPath implements Path {
return null;
}
@Override
@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();
}
}

View File

@ -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

View File

@ -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

View File

@ -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());
}
}
}

View File

@ -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

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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 {
}
}

View File

@ -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;
}

View File

@ -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 {
}

View File

@ -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")

View 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);
}
}

View File

@ -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,69 +23,59 @@
/*
* @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);
Map<String,String[]> names = Map.of(
Map<String, String[]> names = Map.of(
"version/Main.class",
new String[] {"base", "version", "Main.class"},
new String[]{"base", "version", "Main.class"},
"version/Version.class",
new String[] {"base", "version", "Version.class"}
new String[]{"base", "version", "Version.class"}
);
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,68 +84,96 @@ 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);
Map<String,String[]> names = Map.of(
Map<String, String[]> names = Map.of(
"version/Main.class",
new String[] {"base", "version", "Main.class"},
new String[]{"base", "version", "Main.class"},
"version/Version.class",
new String[] {"base", "version", "Version.class"},
new String[]{"base", "version", "Version.class"},
"META-INF/versions/9/version/Version.class",
new String[] {"v9", "version", "Version.class"},
new String[]{"v9", "version", "Version.class"},
"META-INF/versions/10/version/Version.class",
new String[] {"v10", "version", "Version.class"}
new String[]{"v10", "version", "Version.class"}
);
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);
Map<String,String[]> names = Map.of(
Map<String, String[]> names = Map.of(
"version/Main.class",
new String[] {"base", "version", "Main.class"},
new String[]{"base", "version", "Main.class"},
"version/Version.class",
new String[] {"base", "version", "Version.class"},
new String[]{"base", "version", "Version.class"},
"META-INF/versions/9/version/Version.class",
new String[] {"v9", "version", "Version.class"}
new String[]{"v9", "version", "Version.class"}
);
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,19 +181,19 @@ 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);
Map<String,String[]> names = Map.of(
Map<String, String[]> names = Map.of(
"version/Main.class",
new String[] {"base", "version", "Main.class"},
new String[]{"base", "version", "Main.class"},
"version/Version.class",
new String[] {"base", "version", "Version.class"},
new String[]{"base", "version", "Version.class"},
"META-INF/versions/9/version/Version.class",
new String[] {"v9", "version", "Version.class"}
new String[]{"v9", "version", "Version.class"}
);
compare(jarfile, names);
@ -184,25 +202,25 @@ 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);
names = Map.of(
"version/Main.class",
new String[] {"base", "version", "Main.class"},
new String[]{"base", "version", "Main.class"},
"version/Version.class",
new String[] {"v9", "version", "Version.class"},
new String[]{"v9", "version", "Version.class"},
"META-INF/versions/9/version/Version.class",
new String[] {"v10", "version", "Version.class"}
new String[]{"v10", "version", "Version.class"}
);
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");
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);
}
}
// create
Files.write(manifest, "Class-Path: MyUtils.jar\n".getBytes());
// 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);
}
}
}
jar("cfm", jarfile, manifest.toString(),
"-C", classes.resolve("base").toString(), ".",
"--release", "10", "-C", classes.resolve("v10").toString(), ".")
.shouldHaveExitValue(SUCCESS)
.shouldBeEmpty();
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);
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");
}
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);
// 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");
}
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"));
}
}

View File

@ -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(), ".",
"--release", "9", "-C", v9.toString(), ".",
"--release", "10", "-C", v10.toString(), ".")
.assertSuccess();
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(), ".")
.shouldHaveExitValue(SUCCESS);
checkMultiRelease(jarfile, true);
Map<String,String[]> names = Map.of(
"version/Main.class",
new String[] {"classes", "base", "version", "Main.class"},
Map<String, String[]> names = Map.of(
"version/Main.class",
new String[]{"base", "version", "Main.class"},
"version/Version.class",
new String[] {"classes", "base", "version", "Version.class"},
"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(), ".",
"--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; }
jar("cf", jarfile, "-C", base.toString(), ".",
"--release", "10", "-C", v10.toString(), ".")
.shouldNotHaveExitValue(SUCCESS)
.shouldContain("unexpected versioned entry META-INF/versions/");
}
}

View 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);
}
}

View File

@ -8,7 +8,7 @@ public class Version {
protected void doNothing() {
}
// extra publc method
// extra public method
public void anyName() {
}
}

View File

@ -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

View File

@ -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
*/

View File

@ -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
*/

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.*

View 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());
}
}

View File

@ -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
*/

View File

@ -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;

View File

@ -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
*/

View File

@ -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
*/

View File

@ -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;

View File

@ -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

View File

@ -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
*/

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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 {
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"));
/*
* 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"));
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);
}

View File

@ -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());