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