From f85705002ec44bc67ce0dcbbc9b50763e8dd1a74 Mon Sep 17 00:00:00 2001
From: Mandy Chung
Date: Fri, 28 Dec 2012 22:21:40 -0800
Subject: [PATCH 01/53] 8003562: Provide a CLI tool to analyze class
dependencies
Reviewed-by: jjg, alanb, ulfzibis, erikj
---
jdk/make/common/Release.gmk | 3 +++
jdk/make/docs/NON_CORE_PKGS.gmk | 2 +-
jdk/make/launchers/Makefile | 1 +
jdk/make/launchers/Makefile.launcher | 4 ++++
jdk/makefiles/CompileLaunchers.gmk | 5 +++++
jdk/makefiles/CreateJars.gmk | 1 +
jdk/makefiles/Images.gmk | 1 +
7 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/jdk/make/common/Release.gmk b/jdk/make/common/Release.gmk
index dc43ecf95ea..367eab8fa7e 100644
--- a/jdk/make/common/Release.gmk
+++ b/jdk/make/common/Release.gmk
@@ -375,6 +375,7 @@ TOOLS = \
com/sun/tools/javadoc \
com/sun/tools/javah \
com/sun/tools/javap \
+ com/sun/tools/jdeps \
com/sun/tools/corba \
com/sun/tools/internal/xjc \
com/sun/tools/internal/ws \
@@ -457,6 +458,7 @@ NOTJRETOOLS = \
javadoc$(EXE_SUFFIX) \
javah$(EXE_SUFFIX) \
javap$(EXE_SUFFIX) \
+ jdeps$(EXE_SUFFIX) \
jcmd$(EXE_SUFFIX) \
jdb$(EXE_SUFFIX) \
jps$(EXE_SUFFIX) \
@@ -564,6 +566,7 @@ $(NOT_RT_JAR_LIST): FRC
$(ECHO) "sun/tools/javac/" >> $@
$(ECHO) "com/sun/tools/classfile/" >> $@
$(ECHO) "com/sun/tools/javap/" >> $@
+ $(ECHO) "com/sun/tools/jdeps/" >> $@
$(ECHO) "sun/tools/jcmd/" >> $@
$(ECHO) "sun/tools/jconsole/" >> $@
$(ECHO) "sun/tools/jps/" >> $@
diff --git a/jdk/make/docs/NON_CORE_PKGS.gmk b/jdk/make/docs/NON_CORE_PKGS.gmk
index b299938e844..949637cfeda 100644
--- a/jdk/make/docs/NON_CORE_PKGS.gmk
+++ b/jdk/make/docs/NON_CORE_PKGS.gmk
@@ -76,7 +76,7 @@ ATTACH_PKGS = com.sun.tools.attach \
JCONSOLE_PKGS = com.sun.tools.jconsole
-TREEAPI_PKGS = com.sunsource.doctree \
+TREEAPI_PKGS = com.sun.source.doctree \
com.sun.source.tree \
com.sun.source.util
diff --git a/jdk/make/launchers/Makefile b/jdk/make/launchers/Makefile
index 3d9511408b0..be16512e478 100644
--- a/jdk/make/launchers/Makefile
+++ b/jdk/make/launchers/Makefile
@@ -63,6 +63,7 @@ $(call make-launcher, javac, com.sun.tools.javac.Main, , )
$(call make-launcher, javadoc, com.sun.tools.javadoc.Main, , )
$(call make-launcher, javah, com.sun.tools.javah.Main, , )
$(call make-launcher, javap, com.sun.tools.javap.Main, , )
+$(call make-launcher, jdeps, com.sun.tools.jdeps.Main, , )
$(call make-launcher, jcmd, sun.tools.jcmd.JCmd, , )
$(call make-launcher, jconsole, sun.tools.jconsole.JConsole, \
-J-Djconsole.showOutputViewer, )
diff --git a/jdk/make/launchers/Makefile.launcher b/jdk/make/launchers/Makefile.launcher
index 1b3e51b6de8..bb06f80f7cc 100644
--- a/jdk/make/launchers/Makefile.launcher
+++ b/jdk/make/launchers/Makefile.launcher
@@ -62,6 +62,10 @@ ifeq ($(PROGRAM),javap)
WILDCARDS=true
NEVER_ACT_AS_SERVER_CLASS_MACHINE=true
endif
+ifeq ($(PROGRAM),jdeps)
+ WILDCARDS=true
+ NEVER_ACT_AS_SERVER_CLASS_MACHINE=true
+endif
ifeq ($(PROGRAM),javah)
WILDCARDS=true
NEVER_ACT_AS_SERVER_CLASS_MACHINE=true
diff --git a/jdk/makefiles/CompileLaunchers.gmk b/jdk/makefiles/CompileLaunchers.gmk
index 102a2e7831f..f97578aa087 100644
--- a/jdk/makefiles/CompileLaunchers.gmk
+++ b/jdk/makefiles/CompileLaunchers.gmk
@@ -267,6 +267,11 @@ $(eval $(call SetupLauncher,javap,\
-DNEVER_ACT_AS_SERVER_CLASS_MACHINE \
-DJAVA_ARGS='{ "-J-ms8m"$(COMMA) "com.sun.tools.javap.Main"$(COMMA) }'))
+$(eval $(call SetupLauncher,jdeps,\
+ -DEXPAND_CLASSPATH_WILDCARDS \
+ -DNEVER_ACT_AS_SERVER_CLASS_MACHINE \
+ -DJAVA_ARGS='{ "-J-ms8m"$(COMMA) "com.sun.tools.jdeps.Main"$(COMMA) }'))
+
BUILD_LAUNCHER_jconsole_CFLAGS_windows:=-DJAVAW
BUILD_LAUNCHER_jconsole_LDFLAGS_windows:=user32.lib
diff --git a/jdk/makefiles/CreateJars.gmk b/jdk/makefiles/CreateJars.gmk
index 748aac94a2d..77269bd2b90 100644
--- a/jdk/makefiles/CreateJars.gmk
+++ b/jdk/makefiles/CreateJars.gmk
@@ -738,6 +738,7 @@ TOOLS_JAR_INCLUDES := \
com/sun/tools/javadoc \
com/sun/tools/javah \
com/sun/tools/javap \
+ com/sun/tools/jdeps \
com/sun/tools/corba \
com/sun/tools/internal/xjc \
com/sun/tools/internal/ws \
diff --git a/jdk/makefiles/Images.gmk b/jdk/makefiles/Images.gmk
index 5a85e6c37f3..8d8368dbf08 100644
--- a/jdk/makefiles/Images.gmk
+++ b/jdk/makefiles/Images.gmk
@@ -100,6 +100,7 @@ NOT_JRE_BIN_FILES := \
javadoc$(EXE_SUFFIX) \
javah$(EXE_SUFFIX) \
javap$(EXE_SUFFIX) \
+ jdeps$(EXE_SUFFIX) \
jcmd$(EXE_SUFFIX) \
jdb$(EXE_SUFFIX) \
jps$(EXE_SUFFIX) \
From c2f4000a6f8f276ce45496d7237b098a9d364861 Mon Sep 17 00:00:00 2001
From: Chris Hegarty
Date: Sat, 29 Dec 2012 11:00:15 +0000
Subject: [PATCH 02/53] 8005556: java/net/Socks/SocksV4Test.java is missing
@run tag
Reviewed-by: alanb
---
jdk/test/java/net/Socks/SocksV4Test.java | 1 +
1 file changed, 1 insertion(+)
diff --git a/jdk/test/java/net/Socks/SocksV4Test.java b/jdk/test/java/net/Socks/SocksV4Test.java
index b61d658a78a..cc0452e5ea4 100644
--- a/jdk/test/java/net/Socks/SocksV4Test.java
+++ b/jdk/test/java/net/Socks/SocksV4Test.java
@@ -26,6 +26,7 @@
* @bug 4727547
* @summary SocksSocketImpl throws NullPointerException
* @build SocksServer
+ * @run main SocksV4Test
*/
import java.net.*;
From 2fc01efdd8af2fd8aa85c18ca6c4c6b596addb77 Mon Sep 17 00:00:00 2001
From: Jim Gish
Date: Fri, 28 Dec 2012 16:56:54 -0500
Subject: [PATCH 03/53] 8005118: Javadoc styles are inconsistent
Use a common javadoc style in the String classes
Reviewed-by: darcy
---
.../java/lang/AbstractStringBuilder.java | 10 +-
jdk/src/share/classes/java/lang/String.java | 170 +++++++++---------
.../share/classes/java/lang/StringBuffer.java | 22 +--
.../classes/java/lang/StringBuilder.java | 76 ++++----
.../lang/StringIndexOutOfBoundsException.java | 10 +-
5 files changed, 147 insertions(+), 141 deletions(-)
diff --git a/jdk/src/share/classes/java/lang/AbstractStringBuilder.java b/jdk/src/share/classes/java/lang/AbstractStringBuilder.java
index fc513f55efe..03999c445a5 100644
--- a/jdk/src/share/classes/java/lang/AbstractStringBuilder.java
+++ b/jdk/src/share/classes/java/lang/AbstractStringBuilder.java
@@ -860,9 +860,9 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* @return the specified subsequence.
*
* @throws IndexOutOfBoundsException
- * if start or end are negative,
- * if end is greater than length(),
- * or if start is greater than end
+ * if {@code start} or {@code end} are negative,
+ * if {@code end} is greater than {@code length()},
+ * or if {@code start} is greater than {@code end}
* @spec JSR-51
*/
@Override
@@ -1292,7 +1292,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* Returns the index within this string of the first occurrence of the
* specified substring, starting at the specified index. The integer
- * returned is the smallest value k for which:
+ * returned is the smallest value {@code k} for which:
*
* k >= Math.min(fromIndex, str.length()) &&
* this.toString().startsWith(str, k)
@@ -1418,7 +1418,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
public abstract String toString();
/**
- * Needed by String for the contentEquals method.
+ * Needed by {@code String} for the contentEquals method.
*/
final char[] getValue() {
return value;
diff --git a/jdk/src/share/classes/java/lang/String.java b/jdk/src/share/classes/java/lang/String.java
index d73a2f7c2e9..a9bc2f37648 100644
--- a/jdk/src/share/classes/java/lang/String.java
+++ b/jdk/src/share/classes/java/lang/String.java
@@ -615,10 +615,10 @@ public final class String
}
/**
- * Returns true if, and only if, {@link #length()} is 0.
+ * Returns {@code true} if, and only if, {@link #length()} is {@code 0}.
*
- * @return true if {@link #length()} is 0, otherwise
- * false
+ * @return {@code true} if {@link #length()} is {@code 0}, otherwise
+ * {@code false}
*
* @since 1.6
*/
@@ -1229,23 +1229,23 @@ public final class String
/**
* Tests if two string regions are equal.
*
- * A substring of this String object is compared to a substring
+ * A substring of this {@code String} object is compared to a substring
* of the argument other. The result is true if these substrings
* represent identical character sequences. The substring of this
- * String object to be compared begins at index toffset
- * and has length len. The substring of other to be compared
- * begins at index ooffset and has length len. The
- * result is false if and only if at least one of the following
+ * {@code String} object to be compared begins at index {@code toffset}
+ * and has length {@code len}. The substring of other to be compared
+ * begins at index {@code ooffset} and has length {@code len}. The
+ * result is {@code false} if and only if at least one of the following
* is true:
- *
- toffset is negative.
- *
- ooffset is negative.
- *
- toffset+len is greater than the length of this
- * String object.
- *
- ooffset+len is greater than the length of the other
+ *
- {@code toffset} is negative.
+ *
- {@code ooffset} is negative.
+ *
- {@code toffset+len} is greater than the length of this
+ * {@code String} object.
+ *
- {@code ooffset+len} is greater than the length of the other
* argument.
- *
- There is some nonnegative integer k less than len
+ *
- There is some nonnegative integer k less than {@code len}
* such that:
- * this.charAt(toffset+k) != other.charAt(ooffset+k)
+ *
this.charAt(toffset+k) != other.charAt(ooffset+k)
*
*
* @param toffset the starting offset of the subregion in this string.
@@ -1280,28 +1280,28 @@ public final class String
/**
* Tests if two string regions are equal.
*
- * A substring of this String object is compared to a substring
- * of the argument other. The result is true if these
+ * A substring of this {@code String} object is compared to a substring
+ * of the argument {@code other}. The result is {@code true} if these
* substrings represent character sequences that are the same, ignoring
- * case if and only if ignoreCase is true. The substring of
- * this String object to be compared begins at index
- * toffset and has length len. The substring of
- * other to be compared begins at index ooffset and
- * has length len. The result is false if and only if
+ * case if and only if {@code ignoreCase} is true. The substring of
+ * this {@code String} object to be compared begins at index
+ * {@code toffset} and has length {@code len}. The substring of
+ * {@code other} to be compared begins at index {@code ooffset} and
+ * has length {@code len}. The result is {@code false} if and only if
* at least one of the following is true:
- *
- toffset is negative.
- *
- ooffset is negative.
- *
- toffset+len is greater than the length of this
- * String object.
- *
- ooffset+len is greater than the length of the other
+ *
- {@code toffset} is negative.
+ *
- {@code ooffset} is negative.
+ *
- {@code toffset+len} is greater than the length of this
+ * {@code String} object.
+ *
- {@code ooffset+len} is greater than the length of the other
* argument.
- *
- ignoreCase is false and there is some nonnegative
- * integer k less than len such that:
+ *
- {@code ignoreCase} is {@code false} and there is some nonnegative
+ * integer k less than {@code len} such that:
*
* this.charAt(toffset+k) != other.charAt(ooffset+k)
*
- * - ignoreCase is true and there is some nonnegative
- * integer k less than len such that:
+ *
- {@code ignoreCase} is {@code true} and there is some nonnegative
+ * integer k less than {@code len} such that:
*
* Character.toLowerCase(this.charAt(toffset+k)) !=
Character.toLowerCase(other.charAt(ooffset+k))
@@ -1500,12 +1500,12 @@ public final class String
* of {@code ch} in the range from 0 to 0xFFFF (inclusive),
* this is the smallest value k such that:
*
- * (this.charAt(k) == ch) && (k >= fromIndex)
+ * (this.charAt(k) == ch) {@code &&} (k >= fromIndex)
*
* is true. For other values of {@code ch}, it is the
* smallest value k such that:
*
- * (this.codePointAt(k) == ch) && (k >= fromIndex)
+ * (this.codePointAt(k) == ch) {@code &&} (k >= fromIndex)
*
* is true. In either case, if no such character occurs in this
* string at or after position {@code fromIndex}, then
@@ -1604,12 +1604,12 @@ public final class String
* from 0 to 0xFFFF (inclusive), the index returned is the largest
* value k such that:
*
- * (this.charAt(k) == ch) && (k <= fromIndex)
+ * (this.charAt(k) == ch) {@code &&} (k <= fromIndex)
*
* is true. For other values of {@code ch}, it is the
* largest value k such that:
*
- * (this.codePointAt(k) == ch) && (k <= fromIndex)
+ * (this.codePointAt(k) == ch) {@code &&} (k <= fromIndex)
*
* is true. In either case, if no such character occurs in this
* string at or before position {@code fromIndex}, then
@@ -1690,7 +1690,7 @@ public final class String
*
* The returned index is the smallest value k for which:
*
- * k >= fromIndex && this.startsWith(str, k)
+ * k >= fromIndex {@code &&} this.startsWith(str, k)
*
* If no such value of k exists, then {@code -1} is returned.
*
@@ -1799,7 +1799,7 @@ public final class String
*
* The returned index is the largest value k for which:
*
- * k <= fromIndex && this.startsWith(str, k)
+ * k {@code <=} fromIndex {@code &&} this.startsWith(str, k)
*
* If no such value of k exists, then {@code -1} is returned.
*
@@ -2080,17 +2080,18 @@ public final class String
* href="../util/regex/Pattern.html#sum">regular expression.
*
* An invocation of this method of the form
- * str.matches(regex) yields exactly the
+ * str{@code .matches(}regex{@code )} yields exactly the
* same result as the expression
*
- *
{@link java.util.regex.Pattern}.{@link
- * java.util.regex.Pattern#matches(String,CharSequence)
- * matches}(regex, str)
+ *
+ * {@link java.util.regex.Pattern}.{@link java.util.regex.Pattern#matches(String,CharSequence)
+ * matches(regex, str)}
+ *
*
* @param regex
* the regular expression to which this string is to be matched
*
- * @return true if, and only if, this string matches the
+ * @return {@code true} if, and only if, this string matches the
* given regular expression
*
* @throws PatternSyntaxException
@@ -2124,18 +2125,20 @@ public final class String
* given replacement.
*
* An invocation of this method of the form
- * str.replaceFirst(regex, repl)
+ * str{@code .replaceFirst(}regex{@code ,} repl{@code )}
* yields exactly the same result as the expression
*
- *
- * {@link java.util.regex.Pattern}.{@link java.util.regex.Pattern#compile
- * compile}(regex).{@link
- * java.util.regex.Pattern#matcher(java.lang.CharSequence)
- * matcher}(str).{@link java.util.regex.Matcher#replaceFirst
- * replaceFirst}(repl)
+ *
+ *
+ * {@link java.util.regex.Pattern}.{@link
+ * java.util.regex.Pattern#compile compile}(regex).{@link
+ * java.util.regex.Pattern#matcher(java.lang.CharSequence) matcher}(str).{@link
+ * java.util.regex.Matcher#replaceFirst replaceFirst}(repl)
+ *
+ *
*
*
- * Note that backslashes (\) and dollar signs ($) in the
+ * Note that backslashes ({@code \}) and dollar signs ({@code $}) in the
* replacement string may cause the results to be different than if it were
* being treated as a literal replacement string; see
* {@link java.util.regex.Matcher#replaceFirst}.
@@ -2147,7 +2150,7 @@ public final class String
* @param replacement
* the string to be substituted for the first match
*
- * @return The resulting String
+ * @return The resulting {@code String}
*
* @throws PatternSyntaxException
* if the regular expression's syntax is invalid
@@ -2167,18 +2170,20 @@ public final class String
* given replacement.
*
*
An invocation of this method of the form
- * str.replaceAll(regex, repl)
+ * str{@code .replaceAll(}regex{@code ,} repl{@code )}
* yields exactly the same result as the expression
*
- *
- * {@link java.util.regex.Pattern}.{@link java.util.regex.Pattern#compile
- * compile}(regex).{@link
- * java.util.regex.Pattern#matcher(java.lang.CharSequence)
- * matcher}(str).{@link java.util.regex.Matcher#replaceAll
- * replaceAll}(repl)
+ *
+ *
+ * {@link java.util.regex.Pattern}.{@link
+ * java.util.regex.Pattern#compile compile}(regex).{@link
+ * java.util.regex.Pattern#matcher(java.lang.CharSequence) matcher}(str).{@link
+ * java.util.regex.Matcher#replaceAll replaceAll}(repl)
+ *
+ *
*
*
- * Note that backslashes (\) and dollar signs ($) in the
+ * Note that backslashes ({@code \}) and dollar signs ({@code $}) in the
* replacement string may cause the results to be different than if it were
* being treated as a literal replacement string; see
* {@link java.util.regex.Matcher#replaceAll Matcher.replaceAll}.
@@ -2190,7 +2195,7 @@ public final class String
* @param replacement
* the string to be substituted for each match
*
- * @return The resulting String
+ * @return The resulting {@code String}
*
* @throws PatternSyntaxException
* if the regular expression's syntax is invalid
@@ -2234,7 +2239,7 @@ public final class String
* expression does not match any part of the input then the resulting array
* has just one element, namely this string.
*
- *
The limit parameter controls the number of times the
+ *
The {@code limit} parameter controls the number of times the
* pattern is applied and therefore affects the length of the resulting
* array. If the limit n is greater than zero then the pattern
* will be applied at most n - 1 times, the array's
@@ -2245,7 +2250,7 @@ public final class String
* the pattern will be applied as many times as possible, the array can
* have any length, and trailing empty strings will be discarded.
*
- *
The string "boo:and:foo", for example, yields the
+ *
The string {@code "boo:and:foo"}, for example, yields the
* following results with these parameters:
*
*
@@ -2256,33 +2261,34 @@ public final class String
*
* | : |
* 2 |
- * { "boo", "and:foo" } |
+ * {@code { "boo", "and:foo" }} |
* | : |
* 5 |
- * { "boo", "and", "foo" } |
+ * {@code { "boo", "and", "foo" }} |
* | : |
* -2 |
- * { "boo", "and", "foo" } |
+ * {@code { "boo", "and", "foo" }} |
* | o |
* 5 |
- * { "b", "", ":and:f", "", "" } |
+ * {@code { "b", "", ":and:f", "", "" }} |
* | o |
* -2 |
- * { "b", "", ":and:f", "", "" } |
+ * {@code { "b", "", ":and:f", "", "" }} |
* | o |
* 0 |
- * { "b", "", ":and:f" } |
+ * {@code { "b", "", ":and:f" }} |
*
*
* An invocation of this method of the form
- * str.split(regex, n)
+ * str.{@code split(}regex{@code ,} n{@code )}
* yields the same result as the expression
*
*
- * {@link java.util.regex.Pattern}.{@link java.util.regex.Pattern#compile
- * compile}(regex).{@link
- * java.util.regex.Pattern#split(java.lang.CharSequence,int)
- * split}(str, n)
+ *
+ * {@link java.util.regex.Pattern}.{@link
+ * java.util.regex.Pattern#compile compile}(regex).{@link
+ * java.util.regex.Pattern#split(java.lang.CharSequence,int) split}(str, n)
+ *
*
*
*
@@ -2364,7 +2370,7 @@ public final class String
* argument of zero. Trailing empty strings are therefore not included in
* the resulting array.
*
- * The string "boo:and:foo", for example, yields the following
+ *
The string {@code "boo:and:foo"}, for example, yields the following
* results with these expressions:
*
*
@@ -2373,9 +2379,9 @@ public final class String
* | Result |
*
* | : |
- * { "boo", "and", "foo" } |
+ * {@code { "boo", "and", "foo" }} |
* | o |
- * { "b", "", ":and:f" } |
+ * {@code { "b", "", ":and:f" }} |
*
*
*
@@ -2815,7 +2821,7 @@ public final class String
* limited by the maximum dimension of a Java array as defined by
* The Java™ Virtual Machine Specification.
* The behaviour on a
- * null argument depends on the conversion.
*
* @throws java.util.IllegalFormatException
@@ -2828,7 +2834,7 @@ public final class String
* formatter class specification.
*
* @throws NullPointerException
- * If the format is null
+ * If the {@code format} is {@code null}
*
* @return A formatted string
*
@@ -2845,7 +2851,7 @@ public final class String
*
* @param l
* The {@linkplain java.util.Locale locale} to apply during
- * formatting. If l is null then no localization
+ * formatting. If {@code l} is {@code null} then no localization
* is applied.
*
* @param format
@@ -2859,7 +2865,7 @@ public final class String
* limited by the maximum dimension of a Java array as defined by
* The Java™ Virtual Machine Specification.
* The behaviour on a
- * null argument depends on the conversion.
*
* @throws java.util.IllegalFormatException
@@ -2872,7 +2878,7 @@ public final class String
* formatter class specification
*
* @throws NullPointerException
- * If the format is null
+ * If the {@code format} is {@code null}
*
* @return A formatted string
*
@@ -3143,7 +3149,7 @@ public final class String
* programmer should be aware that producing distinct integer results
* for unequal objects may improve the performance of hash tables.
*
- *
+ *
* The hash value will never be zero.
*
* @return a hash code value for this object.
diff --git a/jdk/src/share/classes/java/lang/StringBuffer.java b/jdk/src/share/classes/java/lang/StringBuffer.java
index 9fabad48d68..5d7754a0cc7 100644
--- a/jdk/src/share/classes/java/lang/StringBuffer.java
+++ b/jdk/src/share/classes/java/lang/StringBuffer.java
@@ -57,7 +57,7 @@ package java.lang;
*
* In general, if sb refers to an instance of a {@code StringBuffer},
* then {@code sb.append(x)} has the same effect as
- * {@code sb.insert(sb.length(), x)}.
+ * {@code sb.insert(sb.length(), x)}.
*
* Whenever an operation occurs involving a source sequence (such as
* appending or inserting from a source sequence), this class synchronizes
@@ -80,7 +80,7 @@ package java.lang;
*
* As of release JDK 5, this class has been supplemented with an equivalent
* class designed for use by a single thread, {@link StringBuilder}. The
- * StringBuilder class should generally be used in preference to
+ * {@code StringBuilder} class should generally be used in preference to
* this one, as it supports all of the same operations but it is faster, as
* it performs no synchronization.
*
@@ -262,17 +262,17 @@ package java.lang;
}
/**
- * Appends the specified StringBuffer to this sequence.
+ * Appends the specified {@code StringBuffer} to this sequence.
*
- * The characters of the StringBuffer argument are appended,
- * in order, to the contents of this StringBuffer, increasing the
- * length of this StringBuffer by the length of the argument.
- * If sb is null, then the four characters
- * "null" are appended to this StringBuffer.
+ * The characters of the {@code StringBuffer} argument are appended,
+ * in order, to the contents of this {@code StringBuffer}, increasing the
+ * length of this {@code StringBuffer} by the length of the argument.
+ * If {@code sb} is {@code null}, then the four characters
+ * {@code "null"} are appended to this {@code StringBuffer}.
*
* Let n be the length of the old character sequence, the one
- * contained in the StringBuffer just prior to execution of the
- * append method. Then the character at index k in
+ * contained in the {@code StringBuffer} just prior to execution of the
+ * {@code append} method. Then the character at index k in
* the new character sequence is equal to the character at index k
* in the old character sequence, if k is less than n;
* otherwise, it is equal to the character at index k-n in the
@@ -281,7 +281,7 @@ package java.lang;
* This method synchronizes on {@code this}, the destination
* object, but does not synchronize on the source ({@code sb}).
*
- * @param sb the StringBuffer to append.
+ * @param sb the {@code StringBuffer} to append.
* @return a reference to this object.
* @since 1.4
*/
diff --git a/jdk/src/share/classes/java/lang/StringBuilder.java b/jdk/src/share/classes/java/lang/StringBuilder.java
index acddd83a8a3..e9defe23f6f 100644
--- a/jdk/src/share/classes/java/lang/StringBuilder.java
+++ b/jdk/src/share/classes/java/lang/StringBuilder.java
@@ -28,39 +28,39 @@ package java.lang;
/**
* A mutable sequence of characters. This class provides an API compatible
- * with StringBuffer, but with no guarantee of synchronization.
+ * with {@code StringBuffer}, but with no guarantee of synchronization.
* This class is designed for use as a drop-in replacement for
- * StringBuffer in places where the string buffer was being
+ * {@code StringBuffer} in places where the string buffer was being
* used by a single thread (as is generally the case). Where possible,
* it is recommended that this class be used in preference to
- * StringBuffer as it will be faster under most implementations.
+ * {@code StringBuffer} as it will be faster under most implementations.
*
- *
The principal operations on a StringBuilder are the
- * append and insert methods, which are
+ *
The principal operations on a {@code StringBuilder} are the
+ * {@code append} and {@code insert} methods, which are
* overloaded so as to accept data of any type. Each effectively
* converts a given datum to a string and then appends or inserts the
* characters of that string to the string builder. The
- * append method always adds these characters at the end
- * of the builder; the insert method adds the characters at
+ * {@code append} method always adds these characters at the end
+ * of the builder; the {@code insert} method adds the characters at
* a specified point.
*
- * For example, if z refers to a string builder object
- * whose current contents are "start", then
- * the method call z.append("le") would cause the string
- * builder to contain "startle", whereas
- * z.insert(4, "le") would alter the string builder to
- * contain "starlet".
+ * For example, if {@code z} refers to a string builder object
+ * whose current contents are "{@code start}", then
+ * the method call {@code z.append("le")} would cause the string
+ * builder to contain "{@code startle}", whereas
+ * {@code z.insert(4, "le")} would alter the string builder to
+ * contain "{@code starlet}".
+ *
+ * In general, if sb refers to an instance of a {@code StringBuilder},
+ * then {@code sb.append(x)} has the same effect as
+ * {@code sb.insert(sb.length(), x)}.
*
- * In general, if sb refers to an instance of a StringBuilder,
- * then sb.append(x) has the same effect as
- * sb.insert(sb.length(), x).
- *
* Every string builder has a capacity. As long as the length of the
* character sequence contained in the string builder does not exceed
* the capacity, it is not necessary to allocate a new internal
* buffer. If the internal buffer overflows, it is automatically made larger.
*
- *
Instances of StringBuilder are not safe for
+ *
Instances of {@code StringBuilder} are not safe for
* use by multiple threads. If such synchronization is required then it is
* recommended that {@link java.lang.StringBuffer} be used.
*
@@ -87,11 +87,11 @@ public final class StringBuilder
/**
* Constructs a string builder with no characters in it and an
- * initial capacity specified by the capacity argument.
+ * initial capacity specified by the {@code capacity} argument.
*
* @param capacity the initial capacity.
- * @throws NegativeArraySizeException if the capacity
- * argument is less than 0.
+ * @throws NegativeArraySizeException if the {@code capacity}
+ * argument is less than {@code 0}.
*/
public StringBuilder(int capacity) {
super(capacity);
@@ -100,10 +100,10 @@ public final class StringBuilder
/**
* Constructs a string builder initialized to the contents of the
* specified string. The initial capacity of the string builder is
- * 16 plus the length of the string argument.
+ * {@code 16} plus the length of the string argument.
*
* @param str the initial contents of the buffer.
- * @throws NullPointerException if str is null
+ * @throws NullPointerException if {@code str} is {@code null}
*/
public StringBuilder(String str) {
super(str.length() + 16);
@@ -112,12 +112,12 @@ public final class StringBuilder
/**
* Constructs a string builder that contains the same characters
- * as the specified CharSequence. The initial capacity of
- * the string builder is 16 plus the length of the
- * CharSequence argument.
+ * as the specified {@code CharSequence}. The initial capacity of
+ * the string builder is {@code 16} plus the length of the
+ * {@code CharSequence} argument.
*
* @param seq the sequence to copy.
- * @throws NullPointerException if seq is null
+ * @throws NullPointerException if {@code seq} is {@code null}
*/
public StringBuilder(CharSequence seq) {
this(seq.length() + 16);
@@ -136,22 +136,22 @@ public final class StringBuilder
}
/**
- * Appends the specified StringBuffer to this sequence.
+ * Appends the specified {@code StringBuffer} to this sequence.
*
- * The characters of the StringBuffer argument are appended,
+ * The characters of the {@code StringBuffer} argument are appended,
* in order, to this sequence, increasing the
* length of this sequence by the length of the argument.
- * If sb is null, then the four characters
- * "null" are appended to this sequence.
+ * If {@code sb} is {@code null}, then the four characters
+ * {@code "null"} are appended to this sequence.
*
* Let n be the length of this character sequence just prior to
- * execution of the append method. Then the character at index
+ * execution of the {@code append} method. Then the character at index
* k in the new character sequence is equal to the character at
* index k in the old character sequence, if k is less than
* n; otherwise, it is equal to the character at index k-n
- * in the argument sb.
+ * in the argument {@code sb}.
*
- * @param sb the StringBuffer to append.
+ * @param sb the {@code StringBuffer} to append.
* @return a reference to this object.
*/
public StringBuilder append(StringBuffer sb) {
@@ -418,13 +418,13 @@ public final class StringBuilder
}
/**
- * Save the state of the StringBuilder instance to a stream
+ * Save the state of the {@code StringBuilder} instance to a stream
* (that is, serialize it).
*
* @serialData the number of characters currently stored in the string
- * builder (int), followed by the characters in the
- * string builder (char[]). The length of the
- * char array may be greater than the number of
+ * builder ({@code int}), followed by the characters in the
+ * string builder ({@code char[]}). The length of the
+ * {@code char} array may be greater than the number of
* characters currently stored in the string builder, in which
* case extra characters are ignored.
*/
diff --git a/jdk/src/share/classes/java/lang/StringIndexOutOfBoundsException.java b/jdk/src/share/classes/java/lang/StringIndexOutOfBoundsException.java
index 7067e29a88c..c3aa9b7a2df 100644
--- a/jdk/src/share/classes/java/lang/StringIndexOutOfBoundsException.java
+++ b/jdk/src/share/classes/java/lang/StringIndexOutOfBoundsException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2012, 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
@@ -26,7 +26,7 @@
package java.lang;
/**
- * Thrown by String methods to indicate that an index
+ * Thrown by {@code String} methods to indicate that an index
* is either negative or greater than the size of the string. For
* some methods such as the charAt method, this exception also is
* thrown when the index is equal to the size of the string.
@@ -40,7 +40,7 @@ class StringIndexOutOfBoundsException extends IndexOutOfBoundsException {
private static final long serialVersionUID = -6762910422159637258L;
/**
- * Constructs a StringIndexOutOfBoundsException with no
+ * Constructs a {@code StringIndexOutOfBoundsException} with no
* detail message.
*
* @since JDK1.0.
@@ -50,7 +50,7 @@ class StringIndexOutOfBoundsException extends IndexOutOfBoundsException {
}
/**
- * Constructs a StringIndexOutOfBoundsException with
+ * Constructs a {@code StringIndexOutOfBoundsException} with
* the specified detail message.
*
* @param s the detail message.
@@ -60,7 +60,7 @@ class StringIndexOutOfBoundsException extends IndexOutOfBoundsException {
}
/**
- * Constructs a new StringIndexOutOfBoundsException
+ * Constructs a new {@code StringIndexOutOfBoundsException}
* class with an argument indicating the illegal index.
*
* @param index the illegal index.
From e8ce882d4317fcdffd04066297221f9af3a3ff85 Mon Sep 17 00:00:00 2001
From: Mandy Chung
Date: Fri, 28 Dec 2012 22:25:21 -0800
Subject: [PATCH 04/53] 8003562: Provide a CLI tool to analyze class
dependencies
Reviewed-by: jjg, alanb, ulfzibis, erikj
---
langtools/make/build.properties | 1 +
langtools/makefiles/BuildLangtools.gmk | 4 +
.../com/sun/tools/classfile/Dependencies.java | 107 ++-
.../com/sun/tools/classfile/Dependency.java | 12 +
.../classes/com/sun/tools/jdeps/Archive.java | 173 +++++
.../com/sun/tools/jdeps/ClassFileReader.java | 326 +++++++++
.../com/sun/tools/jdeps/JdepsTask.java | 650 ++++++++++++++++++
.../classes/com/sun/tools/jdeps/Main.java | 66 ++
.../sun/tools/jdeps/PlatformClassPath.java | 169 +++++
.../tools/jdeps/resources/jdeps.properties | 57 ++
.../sun/tools/jdeps/resources/jdk.properties | 262 +++++++
.../resources/version.properties-template | 28 +
langtools/test/Makefile | 5 +-
langtools/test/tools/jdeps/Basic.java | 149 ++++
langtools/test/tools/jdeps/Test.java | 28 +
langtools/test/tools/jdeps/p/Foo.java | 35 +
16 files changed, 2049 insertions(+), 23 deletions(-)
create mode 100644 langtools/src/share/classes/com/sun/tools/jdeps/Archive.java
create mode 100644 langtools/src/share/classes/com/sun/tools/jdeps/ClassFileReader.java
create mode 100644 langtools/src/share/classes/com/sun/tools/jdeps/JdepsTask.java
create mode 100644 langtools/src/share/classes/com/sun/tools/jdeps/Main.java
create mode 100644 langtools/src/share/classes/com/sun/tools/jdeps/PlatformClassPath.java
create mode 100644 langtools/src/share/classes/com/sun/tools/jdeps/resources/jdeps.properties
create mode 100644 langtools/src/share/classes/com/sun/tools/jdeps/resources/jdk.properties
create mode 100644 langtools/src/share/classes/com/sun/tools/jdeps/resources/version.properties-template
create mode 100644 langtools/test/tools/jdeps/Basic.java
create mode 100644 langtools/test/tools/jdeps/Test.java
create mode 100644 langtools/test/tools/jdeps/p/Foo.java
diff --git a/langtools/make/build.properties b/langtools/make/build.properties
index 912342dcabc..3470a69d868 100644
--- a/langtools/make/build.properties
+++ b/langtools/make/build.properties
@@ -153,6 +153,7 @@ javah.tests = \
javap.includes = \
com/sun/tools/classfile/ \
com/sun/tools/javap/ \
+ com/sun/tools/jdeps/ \
sun/tools/javap/
javap.tests = \
diff --git a/langtools/makefiles/BuildLangtools.gmk b/langtools/makefiles/BuildLangtools.gmk
index 6fbbddd9aaa..833c8654442 100644
--- a/langtools/makefiles/BuildLangtools.gmk
+++ b/langtools/makefiles/BuildLangtools.gmk
@@ -75,6 +75,7 @@ $(LANGTOOLS_OUTPUTDIR)/gensrc/_the_props.d : $(PROPSOURCES) $(BUILD_TOOLS)
printf "jdk=$(JDK_VERSION)\nfull=$(FULL_VERSION)\nrelease=$(RELEASE)\n" > $(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/javah/resources/version.properties
printf "jdk=$(JDK_VERSION)\nfull=$(FULL_VERSION)\nrelease=$(RELEASE)\n" > $(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/javap/resources/version.properties
printf "jdk=$(JDK_VERSION)\nfull=$(FULL_VERSION)\nrelease=$(RELEASE)\n" > $(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/javac/resources/version.properties
+ printf "jdk=$(JDK_VERSION)\nfull=$(FULL_VERSION)\nrelease=$(RELEASE)\n" > $(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/jdeps/resources/version.properties
echo Compiling $(words $(PROPSOURCES) v1 v2 v3) properties into resource bundles
$(TOOL_COMPILEPROPS_CMD) $(PROPCMDLINE) \
-compile $(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/javah/resources/version.properties \
@@ -85,6 +86,9 @@ $(LANGTOOLS_OUTPUTDIR)/gensrc/_the_props.d : $(PROPSOURCES) $(BUILD_TOOLS)
java.util.ListResourceBundle \
-compile $(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/javac/resources/version.properties \
$(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/javac/resources/version.java \
+ java.util.ListResourceBundle \
+ -compile $(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/jdeps/resources/version.properties \
+ $(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/jdeps/resources/version.java \
java.util.ListResourceBundle
echo PROPS_ARE_CREATED=yes > $@
diff --git a/langtools/src/share/classes/com/sun/tools/classfile/Dependencies.java b/langtools/src/share/classes/com/sun/tools/classfile/Dependencies.java
index a33964369fc..39a58f30d1f 100644
--- a/langtools/src/share/classes/com/sun/tools/classfile/Dependencies.java
+++ b/langtools/src/share/classes/com/sun/tools/classfile/Dependencies.java
@@ -141,6 +141,15 @@ public class Dependencies {
return new APIDependencyFinder(access);
}
+ /**
+ * Get a finder to do class dependency analysis.
+ *
+ * @return a Class dependency finder
+ */
+ public static Finder getClassDependencyFinder() {
+ return new ClassDependencyFinder();
+ }
+
/**
* Get the finder used to locate the dependencies for a class.
* @return the finder
@@ -246,8 +255,6 @@ public class Dependencies {
return results;
}
-
-
/**
* Find the dependencies of a class, using the current
* {@link Dependencies#getFinder finder} and
@@ -306,38 +313,44 @@ public class Dependencies {
* A location identifying a class.
*/
static class SimpleLocation implements Location {
- public SimpleLocation(String className) {
- this.className = className;
+ public SimpleLocation(String name) {
+ this.name = name;
+ this.className = name.replace('/', '.').replace('$', '.');
+ }
+
+ public String getName() {
+ return name;
}
- /**
- * Get the name of the class being depended on. This name will be used to
- * locate the class file for transitive dependency analysis.
- * @return the name of the class being depended on
- */
public String getClassName() {
return className;
}
+ public String getPackageName() {
+ int i = name.lastIndexOf('/');
+ return (i > 0) ? name.substring(0, i).replace('/', '.') : "";
+ }
+
@Override
public boolean equals(Object other) {
if (this == other)
return true;
if (!(other instanceof SimpleLocation))
return false;
- return (className.equals(((SimpleLocation) other).className));
+ return (name.equals(((SimpleLocation) other).name));
}
@Override
public int hashCode() {
- return className.hashCode();
+ return name.hashCode();
}
@Override
public String toString() {
- return className;
+ return name;
}
+ private String name;
private String className;
}
@@ -431,9 +444,7 @@ public class Dependencies {
}
public boolean accepts(Dependency dependency) {
- String cn = dependency.getTarget().getClassName();
- int lastSep = cn.lastIndexOf("/");
- String pn = (lastSep == -1 ? "" : cn.substring(0, lastSep));
+ String pn = dependency.getTarget().getPackageName();
if (packageNames.contains(pn))
return true;
@@ -451,8 +462,6 @@ public class Dependencies {
private final boolean matchSubpackages;
}
-
-
/**
* This class identifies class names directly or indirectly in the constant pool.
*/
@@ -462,6 +471,26 @@ public class Dependencies {
for (CPInfo cpInfo: classfile.constant_pool.entries()) {
v.scan(cpInfo);
}
+ try {
+ v.addClass(classfile.super_class);
+ v.addClasses(classfile.interfaces);
+ v.scan(classfile.attributes);
+
+ for (Field f : classfile.fields) {
+ v.scan(f.descriptor, f.attributes);
+ }
+ for (Method m : classfile.methods) {
+ v.scan(m.descriptor, m.attributes);
+ Exceptions_attribute e =
+ (Exceptions_attribute)m.attributes.get(Attribute.Exceptions);
+ if (e != null) {
+ v.addClasses(e.exception_index_table);
+ }
+ }
+ } catch (ConstantPoolException e) {
+ throw new ClassFileError(e);
+ }
+
return v.deps;
}
}
@@ -558,9 +587,7 @@ public class Dependencies {
void scan(Descriptor d, Attributes attrs) {
try {
scan(new Signature(d.index).getType(constant_pool));
- Signature_attribute sa = (Signature_attribute) attrs.get(Attribute.Signature);
- if (sa != null)
- scan(new Signature(sa.signature_index).getType(constant_pool));
+ scan(attrs);
} catch (ConstantPoolException e) {
throw new ClassFileError(e);
}
@@ -574,6 +601,43 @@ public class Dependencies {
t.accept(this, null);
}
+ void scan(Attributes attrs) {
+ try {
+ Signature_attribute sa = (Signature_attribute)attrs.get(Attribute.Signature);
+ if (sa != null)
+ scan(sa.getParsedSignature().getType(constant_pool));
+
+ scan((RuntimeVisibleAnnotations_attribute)
+ attrs.get(Attribute.RuntimeVisibleAnnotations));
+ scan((RuntimeVisibleParameterAnnotations_attribute)
+ attrs.get(Attribute.RuntimeVisibleParameterAnnotations));
+ } catch (ConstantPoolException e) {
+ throw new ClassFileError(e);
+ }
+ }
+
+ private void scan(RuntimeAnnotations_attribute attr) throws ConstantPoolException {
+ if (attr == null) {
+ return;
+ }
+ for (int i = 0; i < attr.annotations.length; i++) {
+ int index = attr.annotations[i].type_index;
+ scan(new Signature(index).getType(constant_pool));
+ }
+ }
+
+ private void scan(RuntimeParameterAnnotations_attribute attr) throws ConstantPoolException {
+ if (attr == null) {
+ return;
+ }
+ for (int param = 0; param < attr.parameter_annotations.length; param++) {
+ for (int i = 0; i < attr.parameter_annotations[param].length; i++) {
+ int index = attr.parameter_annotations[param][i].type_index;
+ scan(new Signature(index).getType(constant_pool));
+ }
+ }
+ }
+
void addClass(int index) throws ConstantPoolException {
if (index != 0) {
String name = constant_pool.getClassInfo(index).getBaseName();
@@ -698,6 +762,7 @@ public class Dependencies {
findDependencies(type.paramTypes);
findDependencies(type.returnType);
findDependencies(type.throwsTypes);
+ findDependencies(type.typeParamTypes);
return null;
}
@@ -709,7 +774,7 @@ public class Dependencies {
public Void visitClassType(ClassType type, Void p) {
findDependencies(type.outerType);
- addDependency(type.name);
+ addDependency(type.getBinaryName());
findDependencies(type.typeArgs);
return null;
}
diff --git a/langtools/src/share/classes/com/sun/tools/classfile/Dependency.java b/langtools/src/share/classes/com/sun/tools/classfile/Dependency.java
index 5f42e814ba4..96c9427ec4a 100644
--- a/langtools/src/share/classes/com/sun/tools/classfile/Dependency.java
+++ b/langtools/src/share/classes/com/sun/tools/classfile/Dependency.java
@@ -71,7 +71,19 @@ public interface Dependency {
* dependency analysis.
* @return the name of the class containing the location.
*/
+ String getName();
+
+ /**
+ * Get the fully-qualified name of the class containing the location.
+ * @return the fully-qualified name of the class containing the location.
+ */
String getClassName();
+
+ /**
+ * Get the package name of the class containing the location.
+ * @return the package name of the class containing the location.
+ */
+ String getPackageName();
}
diff --git a/langtools/src/share/classes/com/sun/tools/jdeps/Archive.java b/langtools/src/share/classes/com/sun/tools/jdeps/Archive.java
new file mode 100644
index 00000000000..7b5a0c97d47
--- /dev/null
+++ b/langtools/src/share/classes/com/sun/tools/jdeps/Archive.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2012, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 com.sun.tools.jdeps;
+
+import com.sun.tools.classfile.Dependency;
+import com.sun.tools.classfile.Dependency.Location;
+import java.io.File;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.SortedSet;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+/**
+ * Represents the source of the class files.
+ */
+public class Archive {
+ private static Map archiveForClass = new HashMap();
+ public static Archive find(Location loc) {
+ return archiveForClass.get(loc.getName());
+ }
+
+ private final File file;
+ private final String filename;
+ private final DependencyRecorder recorder;
+ private final ClassFileReader reader;
+ public Archive(String name) {
+ this.file = null;
+ this.filename = name;
+ this.recorder = new DependencyRecorder();
+ this.reader = null;
+ }
+
+ public Archive(File f, ClassFileReader reader) {
+ this.file = f;
+ this.filename = f.getName();
+ this.recorder = new DependencyRecorder();
+ this.reader = reader;
+ }
+
+ public ClassFileReader reader() {
+ return reader;
+ }
+
+ public String getFileName() {
+ return filename;
+ }
+
+ public void addClass(String classFileName) {
+ Archive a = archiveForClass.get(classFileName);
+ assert(a == null || a == this); // ## issue warning?
+ if (!archiveForClass.containsKey(classFileName)) {
+ archiveForClass.put(classFileName, this);
+ }
+ }
+
+ public void addDependency(Dependency d) {
+ recorder.addDependency(d);
+ }
+
+ /**
+ * Returns a sorted map of a class to its dependencies.
+ */
+ public SortedMap> getDependencies() {
+ DependencyRecorder.Filter filter = new DependencyRecorder.Filter() {
+ public boolean accept(Location origin, Location target) {
+ return (archiveForClass.get(origin.getName()) !=
+ archiveForClass.get(target.getName()));
+ }};
+
+ SortedMap> result =
+ new TreeMap>(locationComparator);
+ for (Map.Entry> e : recorder.dependencies().entrySet()) {
+ Location o = e.getKey();
+ for (Location t : e.getValue()) {
+ if (filter.accept(o, t)) {
+ SortedSet odeps = result.get(o);
+ if (odeps == null) {
+ odeps = new TreeSet(locationComparator);
+ result.put(o, odeps);
+ }
+ odeps.add(t);
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns the set of archives this archive requires.
+ */
+ public Set getRequiredArchives() {
+ SortedSet deps = new TreeSet(new Comparator() {
+ public int compare(Archive a1, Archive a2) {
+ return a1.toString().compareTo(a2.toString());
+ }
+ });
+
+ for (Map.Entry> e : recorder.dependencies().entrySet()) {
+ Location o = e.getKey();
+ Archive origin = Archive.find(o);
+ for (Location t : e.getValue()) {
+ Archive target = Archive.find(t);
+ assert(origin != null && target != null);
+ if (origin != target) {
+ if (!deps.contains(target)) {
+ deps.add(target);
+ }
+ }
+ }
+ }
+ return deps;
+ }
+
+ public String toString() {
+ return file != null ? file.getPath() : filename;
+ }
+
+ private static class DependencyRecorder {
+ static interface Filter {
+ boolean accept(Location origin, Location target);
+ }
+
+ public void addDependency(Dependency d) {
+ Set odeps = map.get(d.getOrigin());
+ if (odeps == null) {
+ odeps = new HashSet();
+ map.put(d.getOrigin(), odeps);
+ }
+ odeps.add(d.getTarget());
+ }
+
+ public Map> dependencies() {
+ return map;
+ }
+
+ private final Map> map =
+ new HashMap>();
+ }
+
+ private static Comparator locationComparator =
+ new Comparator() {
+ public int compare(Location o1, Location o2) {
+ return o1.toString().compareTo(o2.toString());
+ }
+ };
+}
diff --git a/langtools/src/share/classes/com/sun/tools/jdeps/ClassFileReader.java b/langtools/src/share/classes/com/sun/tools/jdeps/ClassFileReader.java
new file mode 100644
index 00000000000..deea6fe906e
--- /dev/null
+++ b/langtools/src/share/classes/com/sun/tools/jdeps/ClassFileReader.java
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2012, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 com.sun.tools.jdeps;
+
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.ConstantPoolException;
+import com.sun.tools.classfile.Dependencies.ClassFileError;
+import java.io.*;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.*;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+/**
+ * ClassFileReader reads ClassFile(s) of a given path that can be
+ * a .class file, a directory, or a JAR file.
+ */
+public class ClassFileReader {
+ /**
+ * Returns a ClassFileReader instance of a given path.
+ */
+ public static ClassFileReader newInstance(File path) throws IOException {
+ if (!path.exists()) {
+ throw new FileNotFoundException(path.getAbsolutePath());
+ }
+
+ if (path.isDirectory()) {
+ return new DirectoryReader(path.toPath());
+ } else if (path.getName().endsWith(".jar")) {
+ return new JarFileReader(path.toPath());
+ } else {
+ return new ClassFileReader(path.toPath());
+ }
+ }
+
+ protected final Path path;
+ protected final String baseFileName;
+ private ClassFileReader(Path path) {
+ this.path = path;
+ this.baseFileName = path.getFileName() != null
+ ? path.getFileName().toString()
+ : path.toString();
+ }
+
+ public String getFileName() {
+ return baseFileName;
+ }
+
+ /**
+ * Returns the ClassFile matching the given binary name
+ * or a fully-qualified class name.
+ */
+ public ClassFile getClassFile(String name) throws IOException {
+ if (name.indexOf('.') > 0) {
+ int i = name.lastIndexOf('.');
+ String pathname = name.replace('.', File.separatorChar) + ".class";
+ if (baseFileName.equals(pathname) ||
+ baseFileName.equals(pathname.substring(0, i) + "$" +
+ pathname.substring(i+1, pathname.length()))) {
+ return readClassFile(path);
+ }
+ } else {
+ if (baseFileName.equals(name.replace('/', File.separatorChar) + ".class")) {
+ return readClassFile(path);
+ }
+ }
+ return null;
+ }
+
+ public Iterable getClassFiles() throws IOException {
+ return new Iterable() {
+ public Iterator iterator() {
+ return new FileIterator();
+ }
+ };
+ }
+
+ protected ClassFile readClassFile(Path p) throws IOException {
+ InputStream is = null;
+ try {
+ is = Files.newInputStream(p);
+ return ClassFile.read(is);
+ } catch (ConstantPoolException e) {
+ throw new ClassFileError(e);
+ } finally {
+ if (is != null) {
+ is.close();
+ }
+ }
+ }
+
+ class FileIterator implements Iterator {
+ int count;
+ FileIterator() {
+ this.count = 0;
+ }
+ public boolean hasNext() {
+ return count == 0 && baseFileName.endsWith(".class");
+ }
+
+ public ClassFile next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ try {
+ ClassFile cf = readClassFile(path);
+ count++;
+ return cf;
+ } catch (IOException e) {
+ throw new ClassFileError(e);
+ }
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+ }
+
+ public String toString() {
+ return path.toString();
+ }
+
+ private static class DirectoryReader extends ClassFileReader {
+ DirectoryReader(Path path) throws IOException {
+ super(path);
+ }
+
+ public ClassFile getClassFile(String name) throws IOException {
+ if (name.indexOf('.') > 0) {
+ int i = name.lastIndexOf('.');
+ String pathname = name.replace('.', File.separatorChar) + ".class";
+ Path p = path.resolve(pathname);
+ if (!p.toFile().exists()) {
+ p = path.resolve(pathname.substring(0, i) + "$" +
+ pathname.substring(i+1, pathname.length()));
+ }
+ if (p.toFile().exists()) {
+ return readClassFile(p);
+ }
+ } else {
+ Path p = path.resolve(name + ".class");
+ if (p.toFile().exists()) {
+ return readClassFile(p);
+ }
+ }
+ return null;
+ }
+
+ public Iterable getClassFiles() throws IOException {
+ final Iterator iter = new DirectoryIterator();
+ return new Iterable() {
+ public Iterator iterator() {
+ return iter;
+ }
+ };
+ }
+
+ private List walkTree(Path dir) throws IOException {
+ final List files = new ArrayList();
+ Files.walkFileTree(dir, new SimpleFileVisitor() {
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
+ throws IOException {
+ if (file.toFile().getName().endsWith(".class")) {
+ files.add(file);
+ }
+ return FileVisitResult.CONTINUE;
+ }
+ });
+ return files;
+ }
+
+ class DirectoryIterator implements Iterator {
+ private List entries;
+ private int index = 0;
+ DirectoryIterator() throws IOException {
+ entries = walkTree(path);
+ index = 0;
+ }
+
+ public boolean hasNext() {
+ return index != entries.size();
+ }
+
+ public ClassFile next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ Path path = entries.get(index++);
+ try {
+ return readClassFile(path);
+ } catch (IOException e) {
+ throw new ClassFileError(e);
+ }
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+ }
+ }
+
+ private static class JarFileReader extends ClassFileReader {
+ final JarFile jarfile;
+ JarFileReader(Path path) throws IOException {
+ super(path);
+ this.jarfile = new JarFile(path.toFile());
+ }
+
+ public ClassFile getClassFile(String name) throws IOException {
+ if (name.indexOf('.') > 0) {
+ int i = name.lastIndexOf('.');
+ String entryName = name.replace('.', '/') + ".class";
+ JarEntry e = jarfile.getJarEntry(entryName);
+ if (e == null) {
+ e = jarfile.getJarEntry(entryName.substring(0, i) + "$"
+ + entryName.substring(i + 1, entryName.length()));
+ }
+ if (e != null) {
+ return readClassFile(e);
+ }
+ } else {
+ JarEntry e = jarfile.getJarEntry(name + ".class");
+ if (e != null) {
+ return readClassFile(e);
+ }
+ }
+ return null;
+ }
+
+ private ClassFile readClassFile(JarEntry e) throws IOException {
+ InputStream is = null;
+ try {
+ is = jarfile.getInputStream(e);
+ return ClassFile.read(is);
+ } catch (ConstantPoolException ex) {
+ throw new ClassFileError(ex);
+ } finally {
+ if (is != null)
+ is.close();
+ }
+ }
+
+ public Iterable getClassFiles() throws IOException {
+ final Iterator iter = new JarFileIterator();
+ return new Iterable() {
+ public Iterator iterator() {
+ return iter;
+ }
+ };
+ }
+
+ class JarFileIterator implements Iterator {
+ private Enumeration entries;
+ private JarEntry nextEntry;
+ JarFileIterator() {
+ this.entries = jarfile.entries();
+ while (entries.hasMoreElements()) {
+ JarEntry e = entries.nextElement();
+ String name = e.getName();
+ if (name.endsWith(".class")) {
+ this.nextEntry = e;
+ break;
+ }
+ }
+ }
+
+ public boolean hasNext() {
+ return nextEntry != null;
+ }
+
+ public ClassFile next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+
+ ClassFile cf;
+ try {
+ cf = readClassFile(nextEntry);
+ } catch (IOException ex) {
+ throw new ClassFileError(ex);
+ }
+ JarEntry entry = nextEntry;
+ nextEntry = null;
+ while (entries.hasMoreElements()) {
+ JarEntry e = entries.nextElement();
+ String name = e.getName();
+ if (name.endsWith(".class")) {
+ nextEntry = e;
+ break;
+ }
+ }
+ return cf;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+ }
+ }
+}
diff --git a/langtools/src/share/classes/com/sun/tools/jdeps/JdepsTask.java b/langtools/src/share/classes/com/sun/tools/jdeps/JdepsTask.java
new file mode 100644
index 00000000000..024d6d2d55a
--- /dev/null
+++ b/langtools/src/share/classes/com/sun/tools/jdeps/JdepsTask.java
@@ -0,0 +1,650 @@
+/*
+ * Copyright (c) 2012, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 com.sun.tools.jdeps;
+
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.ConstantPoolException;
+import com.sun.tools.classfile.Dependencies;
+import com.sun.tools.classfile.Dependencies.ClassFileError;
+import com.sun.tools.classfile.Dependency;
+import com.sun.tools.classfile.Dependency.Location;
+import java.io.*;
+import java.text.MessageFormat;
+import java.util.*;
+import java.util.regex.Pattern;
+
+/**
+ * Implementation for the jdeps tool for static class dependency analysis.
+ */
+class JdepsTask {
+ class BadArgs extends Exception {
+ static final long serialVersionUID = 8765093759964640721L;
+ BadArgs(String key, Object... args) {
+ super(JdepsTask.this.getMessage(key, args));
+ this.key = key;
+ this.args = args;
+ }
+
+ BadArgs showUsage(boolean b) {
+ showUsage = b;
+ return this;
+ }
+ final String key;
+ final Object[] args;
+ boolean showUsage;
+ }
+
+ static abstract class Option {
+ Option(boolean hasArg, String... aliases) {
+ this.hasArg = hasArg;
+ this.aliases = aliases;
+ }
+
+ boolean isHidden() {
+ return false;
+ }
+
+ boolean matches(String opt) {
+ for (String a : aliases) {
+ if (a.equals(opt)) {
+ return true;
+ } else if (opt.startsWith("--") && hasArg && opt.startsWith(a + "=")) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ boolean ignoreRest() {
+ return false;
+ }
+
+ abstract void process(JdepsTask task, String opt, String arg) throws BadArgs;
+ final boolean hasArg;
+ final String[] aliases;
+ }
+
+ static abstract class HiddenOption extends Option {
+ HiddenOption(boolean hasArg, String... aliases) {
+ super(hasArg, aliases);
+ }
+
+ boolean isHidden() {
+ return true;
+ }
+ }
+
+ static Option[] recognizedOptions = {
+ new Option(false, "-h", "-?", "--help") {
+ void process(JdepsTask task, String opt, String arg) {
+ task.options.help = true;
+ }
+ },
+ new Option(false, "-s", "--summary") {
+ void process(JdepsTask task, String opt, String arg) {
+ task.options.showSummary = true;
+ task.options.verbose = Options.Verbose.SUMMARY;
+ }
+ },
+ new Option(false, "-v", "--verbose") {
+ void process(JdepsTask task, String opt, String arg) {
+ task.options.verbose = Options.Verbose.VERBOSE;
+ }
+ },
+ new Option(true, "-V", "--verbose-level") {
+ void process(JdepsTask task, String opt, String arg) throws BadArgs {
+ switch (arg) {
+ case "package":
+ task.options.verbose = Options.Verbose.PACKAGE;
+ break;
+ case "class":
+ task.options.verbose = Options.Verbose.CLASS;
+ break;
+ default:
+ throw task.new BadArgs("err.invalid.arg.for.option", opt);
+ }
+ }
+ },
+ new Option(true, "-c", "--classpath") {
+ void process(JdepsTask task, String opt, String arg) {
+ task.options.classpath = arg;
+ }
+ },
+ new Option(true, "-p", "--package") {
+ void process(JdepsTask task, String opt, String arg) {
+ task.options.packageNames.add(arg);
+ }
+ },
+ new Option(true, "-e", "--regex") {
+ void process(JdepsTask task, String opt, String arg) {
+ task.options.regex = arg;
+ }
+ },
+ new Option(false, "-P", "--profile") {
+ void process(JdepsTask task, String opt, String arg) {
+ task.options.showProfile = true;
+ }
+ },
+ new Option(false, "-R", "--recursive") {
+ void process(JdepsTask task, String opt, String arg) {
+ task.options.depth = 0;
+ }
+ },
+ new HiddenOption(true, "-d", "--depth") {
+ void process(JdepsTask task, String opt, String arg) throws BadArgs {
+ try {
+ task.options.depth = Integer.parseInt(arg);
+ } catch (NumberFormatException e) {
+ throw task.new BadArgs("err.invalid.arg.for.option", opt);
+ }
+ }
+ },
+ new Option(false, "--version") {
+ void process(JdepsTask task, String opt, String arg) {
+ task.options.version = true;
+ }
+ },
+ new HiddenOption(false, "--fullversion") {
+ void process(JdepsTask task, String opt, String arg) {
+ task.options.fullVersion = true;
+ }
+ },
+
+ };
+
+ private static final String PROGNAME = "jdeps";
+ private final Options options = new Options();
+ private final List classes = new ArrayList();
+
+ private PrintWriter log;
+ void setLog(PrintWriter out) {
+ log = out;
+ }
+
+ /**
+ * Result codes.
+ */
+ static final int EXIT_OK = 0, // Completed with no errors.
+ EXIT_ERROR = 1, // Completed but reported errors.
+ EXIT_CMDERR = 2, // Bad command-line arguments
+ EXIT_SYSERR = 3, // System error or resource exhaustion.
+ EXIT_ABNORMAL = 4;// terminated abnormally
+
+ int run(String[] args) {
+ if (log == null) {
+ log = new PrintWriter(System.out);
+ }
+ try {
+ handleOptions(args);
+ if (options.help) {
+ showHelp();
+ }
+ if (options.version || options.fullVersion) {
+ showVersion(options.fullVersion);
+ }
+ if (classes.isEmpty() && !options.wildcard) {
+ if (options.help || options.version || options.fullVersion) {
+ return EXIT_OK;
+ } else {
+ showHelp();
+ return EXIT_CMDERR;
+ }
+ }
+ if (options.regex != null && options.packageNames.size() > 0) {
+ showHelp();
+ return EXIT_CMDERR;
+ }
+ if (options.showSummary && options.verbose != Options.Verbose.SUMMARY) {
+ showHelp();
+ return EXIT_CMDERR;
+ }
+ boolean ok = run();
+ return ok ? EXIT_OK : EXIT_ERROR;
+ } catch (BadArgs e) {
+ reportError(e.key, e.args);
+ if (e.showUsage) {
+ log.println(getMessage("main.usage.summary", PROGNAME));
+ }
+ return EXIT_CMDERR;
+ } catch (IOException e) {
+ return EXIT_ABNORMAL;
+ } finally {
+ log.flush();
+ }
+ }
+
+ private final List sourceLocations = new ArrayList();
+ private final Archive NOT_FOUND = new Archive(getMessage("artifact.not.found"));
+ private boolean run() throws IOException {
+ findDependencies();
+ switch (options.verbose) {
+ case VERBOSE:
+ case CLASS:
+ printClassDeps(log);
+ break;
+ case PACKAGE:
+ printPackageDeps(log);
+ break;
+ case SUMMARY:
+ for (Archive origin : sourceLocations) {
+ for (Archive target : origin.getRequiredArchives()) {
+ log.format("%-30s -> %s%n", origin, target);
+ }
+ }
+ break;
+ default:
+ throw new InternalError("Should not reach here");
+ }
+ return true;
+ }
+
+ private boolean isValidClassName(String name) {
+ if (!Character.isJavaIdentifierStart(name.charAt(0))) {
+ return false;
+ }
+ for (int i=1; i < name.length(); i++) {
+ char c = name.charAt(i);
+ if (c != '.' && !Character.isJavaIdentifierPart(c)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private void findDependencies() throws IOException {
+ Dependency.Finder finder = Dependencies.getClassDependencyFinder();
+ Dependency.Filter filter;
+ if (options.regex != null) {
+ filter = Dependencies.getRegexFilter(Pattern.compile(options.regex));
+ } else if (options.packageNames.size() > 0) {
+ filter = Dependencies.getPackageFilter(options.packageNames, false);
+ } else {
+ filter = new Dependency.Filter() {
+ public boolean accepts(Dependency dependency) {
+ return !dependency.getOrigin().equals(dependency.getTarget());
+ }
+ };
+ }
+
+ List archives = new ArrayList();
+ Deque roots = new LinkedList();
+ for (String s : classes) {
+ File f = new File(s);
+ if (f.exists()) {
+ archives.add(new Archive(f, ClassFileReader.newInstance(f)));
+ } else {
+ if (isValidClassName(s)) {
+ roots.add(s);
+ } else {
+ warning("warn.invalid.arg", s);
+ }
+ }
+ }
+
+ List classpaths = new ArrayList(); // for class file lookup
+ if (options.wildcard) {
+ // include all archives from classpath to the initial list
+ archives.addAll(getClassPathArchives(options.classpath));
+ } else {
+ classpaths.addAll(getClassPathArchives(options.classpath));
+ }
+ classpaths.addAll(PlatformClassPath.getArchives());
+
+ // add all archives to the source locations for reporting
+ sourceLocations.addAll(archives);
+ sourceLocations.addAll(classpaths);
+
+ // Work queue of names of classfiles to be searched.
+ // Entries will be unique, and for classes that do not yet have
+ // dependencies in the results map.
+ Deque deque = new LinkedList();
+ Set doneClasses = new HashSet();
+
+ // get the immediate dependencies of the input files
+ for (Archive a : archives) {
+ for (ClassFile cf : a.reader().getClassFiles()) {
+ String classFileName;
+ try {
+ classFileName = cf.getName();
+ } catch (ConstantPoolException e) {
+ throw new ClassFileError(e);
+ }
+ a.addClass(classFileName);
+ if (!doneClasses.contains(classFileName)) {
+ doneClasses.add(classFileName);
+ }
+ for (Dependency d : finder.findDependencies(cf)) {
+ if (filter.accepts(d)) {
+ String cn = d.getTarget().getName();
+ if (!doneClasses.contains(cn) && !deque.contains(cn)) {
+ deque.add(cn);
+ }
+ a.addDependency(d);
+ }
+ }
+ }
+ }
+
+ // add Archive for looking up classes from the classpath
+ // for transitive dependency analysis
+ Deque unresolved = roots;
+ int depth = options.depth > 0 ? options.depth : Integer.MAX_VALUE;
+ do {
+ String name;
+ while ((name = unresolved.poll()) != null) {
+ if (doneClasses.contains(name)) {
+ continue;
+ }
+ ClassFile cf = null;
+ for (Archive a : classpaths) {
+ cf = a.reader().getClassFile(name);
+ if (cf != null) {
+ String classFileName;
+ try {
+ classFileName = cf.getName();
+ } catch (ConstantPoolException e) {
+ throw new ClassFileError(e);
+ }
+ a.addClass(classFileName);
+ if (!doneClasses.contains(classFileName)) {
+ // if name is a fully-qualified class name specified
+ // from command-line, this class might already be parsed
+ doneClasses.add(classFileName);
+ if (depth > 0) {
+ for (Dependency d : finder.findDependencies(cf)) {
+ if (filter.accepts(d)) {
+ String cn = d.getTarget().getName();
+ if (!doneClasses.contains(cn) && !deque.contains(cn)) {
+ deque.add(cn);
+ }
+ a.addDependency(d);
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+ if (cf == null) {
+ NOT_FOUND.addClass(name);
+ }
+ }
+ unresolved = deque;
+ deque = new LinkedList();
+ } while (!unresolved.isEmpty() && depth-- > 0);
+ }
+
+ private void printPackageDeps(PrintWriter out) {
+ for (Archive source : sourceLocations) {
+ SortedMap> deps = source.getDependencies();
+ if (deps.isEmpty())
+ continue;
+
+ for (Archive target : source.getRequiredArchives()) {
+ out.format("%s -> %s%n", source, target);
+ }
+
+ Map pkgs = new TreeMap();
+ SortedMap targets = new TreeMap();
+ String pkg = "";
+ for (Map.Entry> e : deps.entrySet()) {
+ String cn = e.getKey().getClassName();
+ String p = packageOf(e.getKey());
+ Archive origin = Archive.find(e.getKey());
+ assert origin != null;
+ if (!pkgs.containsKey(p)) {
+ pkgs.put(p, origin);
+ } else if (pkgs.get(p) != origin) {
+ warning("warn.split.package", p, origin, pkgs.get(p));
+ }
+
+ if (!p.equals(pkg)) {
+ printTargets(out, targets);
+ pkg = p;
+ targets.clear();
+ out.format(" %s (%s)%n", p, origin.getFileName());
+ }
+
+ for (Location t : e.getValue()) {
+ p = packageOf(t);
+ Archive target = Archive.find(t);
+ if (!targets.containsKey(p)) {
+ targets.put(p, target);
+ }
+ }
+ }
+ printTargets(out, targets);
+ out.println();
+ }
+ }
+
+ private void printTargets(PrintWriter out, Map targets) {
+ for (Map.Entry t : targets.entrySet()) {
+ String pn = t.getKey();
+ out.format(" -> %-40s %s%n", pn, getPackageInfo(pn, t.getValue()));
+ }
+ }
+
+ private String getPackageInfo(String pn, Archive source) {
+ if (PlatformClassPath.contains(source)) {
+ String name = PlatformClassPath.getProfileName(pn);
+ if (name.isEmpty()) {
+ return "JDK internal API (" + source.getFileName() + ")";
+ }
+ return options.showProfile ? name : "";
+ }
+ return source.getFileName();
+ }
+
+ private static String packageOf(Location loc) {
+ String pkg = loc.getPackageName();
+ return pkg.isEmpty() ? "" : pkg;
+ }
+
+ private void printClassDeps(PrintWriter out) {
+ for (Archive source : sourceLocations) {
+ SortedMap> deps = source.getDependencies();
+ if (deps.isEmpty())
+ continue;
+
+ for (Archive target : source.getRequiredArchives()) {
+ out.format("%s -> %s%n", source, target);
+ }
+ out.format("%s%n", source);
+ for (Map.Entry> e : deps.entrySet()) {
+ String cn = e.getKey().getClassName();
+ Archive origin = Archive.find(e.getKey());
+ out.format(" %s (%s)%n", cn, origin.getFileName());
+ for (Location t : e.getValue()) {
+ cn = t.getClassName();
+ Archive target = Archive.find(t);
+ out.format(" -> %-60s %s%n", cn, getPackageInfo(t.getPackageName(), target));
+ }
+ }
+ out.println();
+ }
+ }
+ public void handleOptions(String[] args) throws BadArgs {
+ // process options
+ for (int i=0; i < args.length; i++) {
+ if (args[i].charAt(0) == '-') {
+ String name = args[i];
+ Option option = getOption(name);
+ String param = null;
+ if (option.hasArg) {
+ if (name.startsWith("--") && name.indexOf('=') > 0) {
+ param = name.substring(name.indexOf('=') + 1, name.length());
+ } else if (i + 1 < args.length) {
+ param = args[++i];
+ }
+ if (param == null || param.isEmpty() || param.charAt(0) == '-') {
+ throw new BadArgs("err.missing.arg", name).showUsage(true);
+ }
+ }
+ option.process(this, name, param);
+ if (option.ignoreRest()) {
+ i = args.length;
+ }
+ } else {
+ // process rest of the input arguments
+ for (; i < args.length; i++) {
+ String name = args[i];
+ if (name.charAt(0) == '-') {
+ throw new BadArgs("err.option.after.class", name).showUsage(true);
+ }
+ if (name.equals("*") || name.equals("\"*\"")) {
+ options.wildcard = true;
+ } else {
+ classes.add(name);
+ }
+ }
+ }
+ }
+ }
+
+ private Option getOption(String name) throws BadArgs {
+ for (Option o : recognizedOptions) {
+ if (o.matches(name)) {
+ return o;
+ }
+ }
+ throw new BadArgs("err.unknown.option", name).showUsage(true);
+ }
+
+ private void reportError(String key, Object... args) {
+ log.println(getMessage("error.prefix") + " " + getMessage(key, args));
+ }
+
+ private void warning(String key, Object... args) {
+ log.println(getMessage("warn.prefix") + " " + getMessage(key, args));
+ }
+
+ private void showHelp() {
+ log.println(getMessage("main.usage", PROGNAME));
+ for (Option o : recognizedOptions) {
+ String name = o.aliases[0].substring(1); // there must always be at least one name
+ name = name.charAt(0) == '-' ? name.substring(1) : name;
+ if (o.isHidden() || name.equals("h")) {
+ continue;
+ }
+ log.println(getMessage("main.opt." + name));
+ }
+ }
+
+ private void showVersion(boolean full) {
+ log.println(version(full ? "full" : "release"));
+ }
+
+ private String version(String key) {
+ // key=version: mm.nn.oo[-milestone]
+ // key=full: mm.mm.oo[-milestone]-build
+ if (ResourceBundleHelper.versionRB == null) {
+ return System.getProperty("java.version");
+ }
+ try {
+ return ResourceBundleHelper.versionRB.getString(key);
+ } catch (MissingResourceException e) {
+ return getMessage("version.unknown", System.getProperty("java.version"));
+ }
+ }
+
+ public String getMessage(String key, Object... args) {
+ try {
+ return MessageFormat.format(ResourceBundleHelper.bundle.getString(key), args);
+ } catch (MissingResourceException e) {
+ throw new InternalError("Missing message: " + key);
+ }
+ }
+
+ private static class Options {
+ enum Verbose {
+ CLASS,
+ PACKAGE,
+ SUMMARY,
+ VERBOSE
+ };
+
+ boolean help;
+ boolean version;
+ boolean fullVersion;
+ boolean showFlags;
+ boolean showProfile;
+ boolean showSummary;
+ boolean wildcard;
+ String regex;
+ String classpath = "";
+ int depth = 1;
+ Verbose verbose = Verbose.PACKAGE;
+ Set packageNames = new HashSet();
+ }
+
+ private static class ResourceBundleHelper {
+ static final ResourceBundle versionRB;
+ static final ResourceBundle bundle;
+
+ static {
+ Locale locale = Locale.getDefault();
+ try {
+ bundle = ResourceBundle.getBundle("com.sun.tools.jdeps.resources.jdeps", locale);
+ } catch (MissingResourceException e) {
+ throw new InternalError("Cannot find jdeps resource bundle for locale " + locale);
+ }
+ try {
+ versionRB = ResourceBundle.getBundle("com.sun.tools.jdeps.resources.version");
+ } catch (MissingResourceException e) {
+ throw new InternalError("version.resource.missing");
+ }
+ }
+ }
+
+ private List getArchives(List filenames) throws IOException {
+ List result = new ArrayList();
+ for (String s : filenames) {
+ File f = new File(s);
+ if (f.exists()) {
+ result.add(new Archive(f, ClassFileReader.newInstance(f)));
+ } else {
+ warning("warn.file.not.exist", s);
+ }
+ }
+ return result;
+ }
+
+ private List getClassPathArchives(String paths) throws IOException {
+ List result = new ArrayList();
+ if (paths.isEmpty()) {
+ return result;
+ }
+ for (String p : paths.split(File.pathSeparator)) {
+ if (p.length() > 0) {
+ File f = new File(p);
+ if (f.exists()) {
+ result.add(new Archive(f, ClassFileReader.newInstance(f)));
+ }
+ }
+ }
+ return result;
+ }
+}
diff --git a/langtools/src/share/classes/com/sun/tools/jdeps/Main.java b/langtools/src/share/classes/com/sun/tools/jdeps/Main.java
new file mode 100644
index 00000000000..863815ff24a
--- /dev/null
+++ b/langtools/src/share/classes/com/sun/tools/jdeps/Main.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2012, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 com.sun.tools.jdeps;
+
+import java.io.*;
+
+/**
+ *
+ * Usage:
+ * jdeps [options] files ...
+ * where options include:
+ * -p package-name restrict analysis to classes in this package
+ * (may be given multiple times)
+ * -e regex restrict analysis to packages matching pattern
+ * (-p and -e are exclusive)
+ * -v show class-level dependencies
+ * default: package-level dependencies
+ * -r --recursive transitive dependencies analysis
+ * -classpath paths Classpath to locate class files
+ * -all process all class files in the given classpath
+ */
+public class Main {
+ public static void main(String... args) throws Exception {
+ JdepsTask t = new JdepsTask();
+ int rc = t.run(args);
+ System.exit(rc);
+ }
+
+
+ /**
+ * Entry point that does not call System.exit.
+ *
+ * @param args command line arguments
+ * @param out output stream
+ * @return an exit code. 0 means success, non-zero means an error occurred.
+ */
+ public static int run(String[] args, PrintWriter out) {
+ JdepsTask t = new JdepsTask();
+ t.setLog(out);
+ return t.run(args);
+ }
+}
+
diff --git a/langtools/src/share/classes/com/sun/tools/jdeps/PlatformClassPath.java b/langtools/src/share/classes/com/sun/tools/jdeps/PlatformClassPath.java
new file mode 100644
index 00000000000..2ae1b4637bc
--- /dev/null
+++ b/langtools/src/share/classes/com/sun/tools/jdeps/PlatformClassPath.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2012, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 com.sun.tools.jdeps;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.*;
+
+/**
+ * ClassPath for Java SE and JDK
+ */
+class PlatformClassPath {
+ /*
+ * Profiles for Java SE
+ *
+ * This is a temporary workaround until a common API is defined for langtools
+ * to determine which profile a given classname belongs to. The list of
+ * packages and profile names are hardcoded in jdk.properties and
+ * split packages are not supported.
+ */
+ static class Profile {
+ final String name;
+ final Set packages;
+
+ Profile(String name) {
+ this.name = name;
+ this.packages = new HashSet();
+ }
+ }
+
+ private final static String JAVAFX = "javafx";
+ private final static Map map = getProfilePackages();
+ static String getProfileName(String packageName) {
+ Profile profile = map.get(packageName);
+ if (packageName.startsWith(JAVAFX + ".")) {
+ profile = map.get(JAVAFX);
+ }
+ return profile != null ? profile.name : "";
+ }
+
+ private final static List javaHomeArchives = init();
+ static List getArchives() {
+ return javaHomeArchives;
+ }
+
+ static boolean contains(Archive archive) {
+ return javaHomeArchives.contains(archive);
+ }
+
+ private static List init() {
+ List result = new ArrayList();
+ String javaHome = System.getProperty("java.home");
+ List files = new ArrayList();
+ File jre = new File(javaHome, "jre");
+ File lib = new File(javaHome, "lib");
+
+ try {
+ if (jre.exists() && jre.isDirectory()) {
+ result.addAll(addJarFiles(new File(jre, "lib")));
+ result.addAll(addJarFiles(lib));
+ } else if (lib.exists() && lib.isDirectory()) {
+ // either a JRE or a jdk build image
+ File classes = new File(javaHome, "classes");
+ if (classes.exists() && classes.isDirectory()) {
+ // jdk build outputdir
+ result.add(new Archive(classes, ClassFileReader.newInstance(classes)));
+ }
+ // add other JAR files
+ result.addAll(addJarFiles(lib));
+ } else {
+ throw new RuntimeException("\"" + javaHome + "\" not a JDK home");
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ // add a JavaFX profile if there is jfxrt.jar
+ for (Archive archive : result) {
+ if (archive.getFileName().equals("jfxrt.jar")) {
+ map.put(JAVAFX, new Profile("jfxrt.jar"));
+ }
+ }
+ return result;
+ }
+
+ private static List addJarFiles(File f) throws IOException {
+ final List result = new ArrayList();
+ final Path root = f.toPath();
+ final Path ext = root.resolve("ext");
+ Files.walkFileTree(root, new SimpleFileVisitor() {
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
+ throws IOException
+ {
+ if (dir.equals(root) || dir.equals(ext)) {
+ return FileVisitResult.CONTINUE;
+ } else {
+ // skip other cobundled JAR files
+ return FileVisitResult.SKIP_SUBTREE;
+ }
+ }
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
+ throws IOException
+ {
+ File f = file.toFile();
+ String fn = f.getName();
+ if (fn.endsWith(".jar") && !fn.equals("alt-rt.jar")) {
+ result.add(new Archive(f, ClassFileReader.newInstance(f)));
+ }
+ return FileVisitResult.CONTINUE;
+ }
+ });
+ return result;
+ }
+
+ private static Map getProfilePackages() {
+ Map map = new HashMap();
+
+ // read the properties as a ResourceBundle as the build compiles
+ // the properties file into Java class. Another alternative is
+ // to load it as Properties and fix the build to exclude this file.
+ ResourceBundle profileBundle =
+ ResourceBundle.getBundle("com.sun.tools.jdeps.resources.jdk");
+
+ int i=1;
+ String key;
+ while (profileBundle.containsKey((key = "profile." + i + ".name"))) {
+ Profile profile = new Profile(profileBundle.getString(key));
+ String n = profileBundle.getString("profile." + i + ".packages");
+ String[] pkgs = n.split("\\s+");
+ for (String p : pkgs) {
+ if (p.isEmpty()) continue;
+ assert(map.containsKey(p) == false);
+ profile.packages.add(p);
+ map.put(p, profile);
+ }
+ i++;
+ }
+ return map;
+ }
+}
diff --git a/langtools/src/share/classes/com/sun/tools/jdeps/resources/jdeps.properties b/langtools/src/share/classes/com/sun/tools/jdeps/resources/jdeps.properties
new file mode 100644
index 00000000000..5456fd1e287
--- /dev/null
+++ b/langtools/src/share/classes/com/sun/tools/jdeps/resources/jdeps.properties
@@ -0,0 +1,57 @@
+main.usage.summary=\
+Usage: {0} \n\
+use -h, -? or --help for a list of possible options
+
+main.usage=\
+Usage: {0} \n\
+where can be a pathname to a .class file, a directory, a JAR file,\n\
+or a fully-qualified classname or wildcard "*". Possible options include:
+
+error.prefix=Error:
+warn.prefix=Warning:
+
+main.opt.h=\
+\ -h -? --help Print this usage message
+
+main.opt.version=\
+\ --version Version information
+
+main.opt.V=\
+\ -V --verbose-level= Print package-level or class-level dependencies\n\
+\ Valid levels are: "package" and "class"
+
+main.opt.v=\
+\ -v --verbose Print additional information
+
+main.opt.s=\
+\ -s --summary Print dependency summary only
+
+main.opt.p=\
+\ -p --package= Restrict analysis to classes in this package\n\
+\ (may be given multiple times)
+
+main.opt.e=\
+\ -e --regex= Restrict analysis to packages matching pattern\n\
+\ (-p and -e are exclusive)
+
+main.opt.P=\
+\ -P --profile Show profile or the file containing a package
+
+main.opt.c=\
+\ -c --classpath= Specify where to find class files
+
+main.opt.R=\
+\ -R --recursive Recursively traverse all dependencies
+
+main.opt.d=\
+\ -d --depth= Specify the depth of the transitive dependency analysis
+
+err.unknown.option=unknown option: {0}
+err.missing.arg=no value given for {0}
+err.internal.error=internal error: {0} {1} {2}
+err.invalid.arg.for.option=invalid argument for option: {0}
+err.option.after.class=option must be specified before classes: {0}
+warn.invalid.arg=Invalid classname or pathname not exist: {0}
+warn.split.package=package {0} defined in {1} {2}
+
+artifact.not.found=not found
diff --git a/langtools/src/share/classes/com/sun/tools/jdeps/resources/jdk.properties b/langtools/src/share/classes/com/sun/tools/jdeps/resources/jdk.properties
new file mode 100644
index 00000000000..59ad26dc253
--- /dev/null
+++ b/langtools/src/share/classes/com/sun/tools/jdeps/resources/jdk.properties
@@ -0,0 +1,262 @@
+# This properties file does not need localization.
+
+profile.1.name = compact1
+profile.1.packages = \
+ java.io \
+ java.lang \
+ java.lang.annotation \
+ java.lang.invoke \
+ java.lang.ref \
+ java.lang.reflect \
+ java.math \
+ java.net \
+ java.nio \
+ java.nio.channels \
+ java.nio.channels.spi \
+ java.nio.charset \
+ java.nio.charset.spi \
+ java.nio.file \
+ java.nio.file.attribute \
+ java.nio.file.spi \
+ java.security \
+ java.security.cert \
+ java.security.interfaces \
+ java.security.spec \
+ java.text \
+ java.text.spi \
+ java.util \
+ java.util.concurrent \
+ java.util.concurrent.atomic \
+ java.util.concurrent.locks \
+ java.util.jar \
+ java.util.logging \
+ java.util.regex \
+ java.util.spi \
+ java.util.zip \
+ javax.crypto \
+ javax.crypto.interfaces \
+ javax.crypto.spec \
+ javax.security.auth \
+ javax.security.auth.callback \
+ javax.security.auth.login \
+ javax.security.auth.spi \
+ javax.security.auth.x500 \
+ javax.net \
+ javax.net.ssl \
+ javax.security.cert \
+ \
+ com.sun.net.ssl \
+ com.sun.nio.file \
+ com.sun.nio.sctp \
+ com.sun.security.auth \
+ com.sun.security.auth.login
+
+profile.2.name = compact2
+profile.2.packages = \
+ java.sql \
+ javax.sql \
+ javax.xml \
+ javax.xml.datatype \
+ javax.xml.namespace \
+ javax.xml.parsers \
+ javax.xml.stream \
+ javax.xml.stream.events \
+ javax.xml.stream.util \
+ javax.xml.transform \
+ javax.xml.transform.dom \
+ javax.xml.transform.sax \
+ javax.xml.transform.stax \
+ javax.xml.transform.stream \
+ javax.xml.validation \
+ javax.xml.xpath \
+ org.w3c.dom \
+ org.w3c.dom.bootstrap \
+ org.w3c.dom.events \
+ org.w3c.dom.ls \
+ org.xml.sax \
+ org.xml.sax.ext \
+ org.xml.sax.helpers \
+ java.rmi \
+ java.rmi.activation \
+ java.rmi.dgc \
+ java.rmi.registry \
+ java.rmi.server \
+ javax.rmi.ssl \
+ javax.transaction \
+ javax.transaction.xa \
+ \
+ com.sun.net.httpserver \
+ com.sun.net.httpserver.spi
+
+profile.3.name = compact3
+profile.3.packages = \
+ java.lang.instrument \
+ java.lang.management \
+ java.security.acl \
+ java.util.prefs \
+ javax.management \
+ javax.management.loading \
+ javax.management.modelmbean \
+ javax.management.monitor \
+ javax.management.openmbean \
+ javax.management.relation \
+ javax.management.remote \
+ javax.management.remote.rmi \
+ javax.management.timer \
+ javax.naming \
+ javax.naming.directory \
+ javax.naming.event \
+ javax.naming.ldap \
+ javax.naming.spi \
+ javax.sql.rowset \
+ javax.sql.rowset.serial \
+ javax.sql.rowset.spi \
+ javax.security.auth.kerberos \
+ javax.security.sasl \
+ javax.script \
+ javax.smartcardio \
+ javax.xml.crypto \
+ javax.xml.crypto.dom \
+ javax.xml.crypto.dsig \
+ javax.xml.crypto.dsig.dom \
+ javax.xml.crypto.dsig.keyinfo \
+ javax.xml.crypto.dsig.spec \
+ javax.annotation.processing \
+ javax.lang.model \
+ javax.lang.model.element \
+ javax.lang.model.type \
+ javax.lang.model.util \
+ javax.tools \
+ javax.tools.annotation \
+ org.ietf.jgss \
+ \
+ com.sun.management \
+ com.sun.security.auth.callback \
+ com.sun.security.auth.module \
+ com.sun.security.jgss
+
+profile.4.name = Full JRE
+profile.4.packages = \
+ java.applet \
+ java.awt \
+ java.awt.color \
+ java.awt.datatransfer \
+ java.awt.dnd \
+ java.awt.dnd.peer \
+ java.awt.event \
+ java.awt.font \
+ java.awt.geom \
+ java.awt.im \
+ java.awt.im.spi \
+ java.awt.image \
+ java.awt.image.renderable \
+ java.awt.peer \
+ java.awt.print \
+ java.beans \
+ java.beans.beancontext \
+ javax.accessibility \
+ javax.imageio \
+ javax.imageio.event \
+ javax.imageio.metadata \
+ javax.imageio.plugins.bmp \
+ javax.imageio.plugins.jpeg \
+ javax.imageio.spi \
+ javax.imageio.stream \
+ javax.print \
+ javax.print.attribute \
+ javax.print.attribute.standard \
+ javax.print.event \
+ javax.sound.midi \
+ javax.sound.midi.spi \
+ javax.sound.sampled \
+ javax.sound.sampled.spi \
+ javax.swing \
+ javax.swing.border \
+ javax.swing.colorchooser \
+ javax.swing.event \
+ javax.swing.filechooser \
+ javax.swing.plaf \
+ javax.swing.plaf.basic \
+ javax.swing.plaf.metal \
+ javax.swing.plaf.multi \
+ javax.swing.plaf.nimbus \
+ javax.swing.plaf.synth \
+ javax.swing.table \
+ javax.swing.text \
+ javax.swing.text.html \
+ javax.swing.text.html.parser \
+ javax.swing.text.rtf \
+ javax.swing.tree \
+ javax.swing.undo \
+ javax.activation \
+ javax.jws \
+ javax.jws.soap \
+ javax.rmi \
+ javax.rmi.CORBA \
+ javax.xml.bind \
+ javax.xml.bind.annotation \
+ javax.xml.bind.annotation.adapters \
+ javax.xml.bind.attachment \
+ javax.xml.bind.helpers \
+ javax.xml.bind.util \
+ javax.xml.soap \
+ javax.xml.ws \
+ javax.xml.ws.handler \
+ javax.xml.ws.handler.soap \
+ javax.xml.ws.http \
+ javax.xml.ws.soap \
+ javax.xml.ws.spi \
+ javax.xml.ws.spi.http \
+ javax.xml.ws.wsaddressing \
+ javax.annotation \
+ org.omg.CORBA \
+ org.omg.CORBA.DynAnyPackage \
+ org.omg.CORBA.ORBPackage \
+ org.omg.CORBA.TypeCodePackage \
+ org.omg.CORBA.portable \
+ org.omg.CORBA_2_3 \
+ org.omg.CORBA_2_3.portable \
+ org.omg.CosNaming \
+ org.omg.CosNaming.NamingContextExtPackage \
+ org.omg.CosNaming.NamingContextPackage \
+ org.omg.Dynamic \
+ org.omg.DynamicAny \
+ org.omg.DynamicAny.DynAnyFactoryPackage \
+ org.omg.DynamicAny.DynAnyPackage \
+ org.omg.IOP \
+ org.omg.IOP.CodecFactoryPackage \
+ org.omg.IOP.CodecPackage \
+ org.omg.Messaging \
+ org.omg.PortableInterceptor \
+ org.omg.PortableInterceptor.ORBInitInfoPackage \
+ org.omg.PortableServer \
+ org.omg.PortableServer.CurrentPackage \
+ org.omg.PortableServer.POAManagerPackage \
+ org.omg.PortableServer.POAPackage \
+ org.omg.PortableServer.ServantLocatorPackage \
+ org.omg.PortableServer.portable \
+ org.omg.SendingContext \
+ org.omg.stub.java.rmi \
+ org.omg.stub.javax.management.remote.rmi
+
+# Remaining JDK supported API
+profile.5.name = JDK tools
+profile.5.packages = \
+ com.sun.jdi \
+ com.sun.jdi.connect \
+ com.sun.jdi.connect.spi \
+ com.sun.jdi.event \
+ com.sun.jdi.request \
+ com.sun.javadoc \
+ com.sun.tools.doclets \
+ com.sun.tools.doctree \
+ com.sun.source.tree \
+ com.sun.source.util \
+ com.sun.tools.attach \
+ com.sun.tools.attach.spi \
+ com.sun.tools.jconsole \
+ com.sun.tools.javac \
+ com.sun.tools.javah \
+ com.sun.tools.javap \
+ com.sun.tools.javadoc \
+ com.sun.servicetag
diff --git a/langtools/src/share/classes/com/sun/tools/jdeps/resources/version.properties-template b/langtools/src/share/classes/com/sun/tools/jdeps/resources/version.properties-template
new file mode 100644
index 00000000000..9e4fa623c22
--- /dev/null
+++ b/langtools/src/share/classes/com/sun/tools/jdeps/resources/version.properties-template
@@ -0,0 +1,28 @@
+#
+# Copyright (c) 2012, 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. Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# 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.
+#
+
+jdk=$(JDK_VERSION)
+full=$(FULL_VERSION)
+release=$(RELEASE)
diff --git a/langtools/test/Makefile b/langtools/test/Makefile
index 9db478dc8da..3a9a6d01cd1 100644
--- a/langtools/test/Makefile
+++ b/langtools/test/Makefile
@@ -229,7 +229,7 @@ JCK_RUNTIME_OUTPUT_DIR = $(ABS_TEST_OUTPUT_DIR)/jck-runtime-Xcompile
all: $(JPRT_CLEAN) jtreg-tests jck-compiler-tests jck-runtime-tests $(JPRT_ARCHIVE_BUNDLE) all-summary
@echo "Testing completed successfully"
-jtreg apt javac javadoc javah javap: $(JPRT_CLEAN) jtreg-tests $(JPRT_ARCHIVE_BUNDLE) jtreg-summary
+jtreg apt javac javadoc javah javap jdeps: $(JPRT_CLEAN) jtreg-tests $(JPRT_ARCHIVE_BUNDLE) jtreg-summary
@echo "Testing completed successfully"
jck-compiler: $(JPRT_CLEAN) jck-compiler-tests $(JPRT_ARCHIVE_BUNDLE) jck-compiler-summary
@@ -246,6 +246,7 @@ javac: JTREG_TESTDIRS = tools/javac
javadoc: JTREG_TESTDIRS = tools/javadoc com/sun/javadoc
javah: JTREG_TESTDIRS = tools/javah
javap: JTREG_TESTDIRS = tools/javap
+jdeps: JTREG_TESTDIRS = tools/jdeps
# Run jtreg tests
#
@@ -426,7 +427,7 @@ FRC:
# Phony targets (e.g. these are not filenames)
.PHONY: all clean \
- jtreg javac javadoc javah javap jtreg-tests jtreg-summary check-jtreg \
+ jtreg javac javadoc javah javap jdeps jtreg-tests jtreg-summary check-jtreg \
jck-compiler jck-compiler-tests jck-compiler-summary \
jck-runtime jck-runtime-tests jck-runtime-summary check-jck
diff --git a/langtools/test/tools/jdeps/Basic.java b/langtools/test/tools/jdeps/Basic.java
new file mode 100644
index 00000000000..236a17b10a4
--- /dev/null
+++ b/langtools/test/tools/jdeps/Basic.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2012, 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 8003562
+ * @summary Basic tests for jdeps tool
+ * @build Test p.Foo
+ * @run main Basic
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.*;
+import java.util.regex.*;
+
+public class Basic {
+ public static void main(String... args) throws Exception {
+ int errors = 0;
+
+ errors += new Basic().run();
+ if (errors > 0)
+ throw new Exception(errors + " errors found");
+ }
+
+ int run() throws IOException {
+ File testDir = new File(System.getProperty("test.classes", "."));
+ // test a .class file
+ test(new File(testDir, "Test.class"),
+ new String[] {"java.lang", "p"});
+ // test a directory
+ test(new File(testDir, "p"),
+ new String[] {"java.lang", "java.util"});
+ // test class-level dependency output
+ test(new File(testDir, "Test.class"),
+ new String[] {"java.lang.Object", "p.Foo"},
+ new String[] {"-V", "class"});
+ // test -p option
+ test(new File(testDir, "Test.class"),
+ new String[] {"p.Foo"},
+ new String[] {"--verbose-level=class", "-p", "p"});
+ // test -e option
+ test(new File(testDir, "Test.class"),
+ new String[] {"p.Foo"},
+ new String[] {"-V", "class", "-e", "p\\..*"});
+ test(new File(testDir, "Test.class"),
+ new String[] {"java.lang"},
+ new String[] {"-V", "package", "-e", "java\\.lang\\..*"});
+ // test -classpath and -all options
+ test(null,
+ new String[] {"com.sun.tools.jdeps", "java.lang", "java.util",
+ "java.util.regex", "java.io", "p"},
+ new String[] {"--classpath", testDir.getPath(), "*"});
+ return errors;
+ }
+
+ void test(File file, String[] expect) {
+ test(file, expect, new String[0]);
+ }
+
+ void test(File file, String[] expect, String[] options) {
+ String[] args;
+ if (file != null) {
+ args = Arrays.copyOf(options, options.length+1);
+ args[options.length] = file.getPath();
+ } else {
+ args = options;
+ }
+ String[] deps = jdeps(args);
+ checkEqual("dependencies", expect, deps);
+ }
+
+ String[] jdeps(String... args) {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ System.err.println("jdeps " + Arrays.toString(args));
+ int rc = com.sun.tools.jdeps.Main.run(args, pw);
+ pw.close();
+ String out = sw.toString();
+ if (!out.isEmpty())
+ System.err.println(out);
+ if (rc != 0)
+ throw new Error("jdeps failed: rc=" + rc);
+ return findDeps(out);
+ }
+
+ // Pattern used to parse lines
+ private static Pattern linePattern = Pattern.compile(".*\r?\n");
+ private static Pattern pattern = Pattern.compile("\\s+ -> (\\S+) +.*");
+
+ // Use the linePattern to break the given String into lines, applying
+ // the pattern to each line to see if we have a match
+ private static String[] findDeps(String out) {
+ List result = new ArrayList<>();
+ Matcher lm = linePattern.matcher(out); // Line matcher
+ Matcher pm = null; // Pattern matcher
+ int lines = 0;
+ while (lm.find()) {
+ lines++;
+ CharSequence cs = lm.group(); // The current line
+ if (pm == null)
+ pm = pattern.matcher(cs);
+ else
+ pm.reset(cs);
+ if (pm.find())
+ result.add(pm.group(1));
+ if (lm.end() == out.length())
+ break;
+ }
+ return result.toArray(new String[0]);
+ }
+
+ void checkEqual(String label, String[] expect, String[] found) {
+ Set s1 = new HashSet<>(Arrays.asList(expect));
+ Set s2 = new HashSet<>(Arrays.asList(found));
+
+ if (!s1.equals(s2))
+ error("Unexpected " + label + " found: '" + s2 + "', expected: '" + s1 + "'");
+ }
+
+ void error(String msg) {
+ System.err.println("Error: " + msg);
+ errors++;
+ }
+
+ int errors;
+}
diff --git a/langtools/test/tools/jdeps/Test.java b/langtools/test/tools/jdeps/Test.java
new file mode 100644
index 00000000000..8adc7b4f630
--- /dev/null
+++ b/langtools/test/tools/jdeps/Test.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2012, 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.
+ */
+
+public class Test {
+ public void test() {
+ p.Foo f = new p.Foo();
+ }
+}
diff --git a/langtools/test/tools/jdeps/p/Foo.java b/langtools/test/tools/jdeps/p/Foo.java
new file mode 100644
index 00000000000..14febbff507
--- /dev/null
+++ b/langtools/test/tools/jdeps/p/Foo.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2012, 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 p;
+
+import java.util.List;
+import java.util.Collections;
+public class Foo {
+ public static List foo() {
+ return Collections.emptyList();
+ }
+
+ public Foo() {
+ }
+}
From 73b497c12e06b16f72a7681a9eaed3acf9f46e93 Mon Sep 17 00:00:00 2001
From: Eric Mccorkle
Date: Sat, 29 Dec 2012 17:33:17 -0800
Subject: [PATCH 05/53] 8004727: Add compiler support for parameter reflection
Reviewed-by: jjg
---
.../com/sun/tools/classfile/Attribute.java | 5 +-
.../com/sun/tools/classfile/ClassWriter.java | 11 +-
.../classfile/MethodParameters_attribute.java | 87 +++++
.../com/sun/tools/javac/code/Symbol.java | 3 +-
.../com/sun/tools/javac/jvm/ClassReader.java | 62 +++-
.../com/sun/tools/javac/jvm/ClassWriter.java | 24 ++
.../com/sun/tools/javac/main/Option.java | 2 +
.../tools/javac/resources/javac.properties | 2 +
.../com/sun/tools/javac/util/Names.java | 2 +
.../com/sun/tools/javap/AttributeWriter.java | 25 +-
.../test/tools/javac/MethodParameters.java | 343 ++++++++++++++++++
.../test/tools/javap/MethodParameters.java | 165 +++++++++
12 files changed, 713 insertions(+), 18 deletions(-)
create mode 100644 langtools/src/share/classes/com/sun/tools/classfile/MethodParameters_attribute.java
create mode 100644 langtools/test/tools/javac/MethodParameters.java
create mode 100644 langtools/test/tools/javap/MethodParameters.java
diff --git a/langtools/src/share/classes/com/sun/tools/classfile/Attribute.java b/langtools/src/share/classes/com/sun/tools/classfile/Attribute.java
index 6c95e6ffdef..502baefc0d1 100644
--- a/langtools/src/share/classes/com/sun/tools/classfile/Attribute.java
+++ b/langtools/src/share/classes/com/sun/tools/classfile/Attribute.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2012, 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
@@ -51,6 +51,7 @@ public abstract class Attribute {
public static final String LineNumberTable = "LineNumberTable";
public static final String LocalVariableTable = "LocalVariableTable";
public static final String LocalVariableTypeTable = "LocalVariableTypeTable";
+ public static final String MethodParameters = "MethodParameters";
public static final String RuntimeVisibleAnnotations = "RuntimeVisibleAnnotations";
public static final String RuntimeInvisibleAnnotations = "RuntimeInvisibleAnnotations";
public static final String RuntimeVisibleParameterAnnotations = "RuntimeVisibleParameterAnnotations";
@@ -113,6 +114,7 @@ public abstract class Attribute {
standardAttributes.put(LocalVariableTypeTable, LocalVariableTypeTable_attribute.class);
if (!compat) { // old javap does not recognize recent attributes
+ standardAttributes.put(MethodParameters, MethodParameters_attribute.class);
standardAttributes.put(CompilationID, CompilationID_attribute.class);
standardAttributes.put(RuntimeInvisibleAnnotations, RuntimeInvisibleAnnotations_attribute.class);
standardAttributes.put(RuntimeInvisibleParameterAnnotations, RuntimeInvisibleParameterAnnotations_attribute.class);
@@ -171,6 +173,7 @@ public abstract class Attribute {
R visitLineNumberTable(LineNumberTable_attribute attr, P p);
R visitLocalVariableTable(LocalVariableTable_attribute attr, P p);
R visitLocalVariableTypeTable(LocalVariableTypeTable_attribute attr, P p);
+ R visitMethodParameters(MethodParameters_attribute attr, P p);
R visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, P p);
R visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr, P p);
R visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr, P p);
diff --git a/langtools/src/share/classes/com/sun/tools/classfile/ClassWriter.java b/langtools/src/share/classes/com/sun/tools/classfile/ClassWriter.java
index 87128a63ecd..38b896f3227 100644
--- a/langtools/src/share/classes/com/sun/tools/classfile/ClassWriter.java
+++ b/langtools/src/share/classes/com/sun/tools/classfile/ClassWriter.java
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2012, 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
@@ -479,6 +479,15 @@ public class ClassWriter {
out.writeShort(entry.index);
}
+ public Void visitMethodParameters(MethodParameters_attribute attr, ClassOutputStream out) {
+ out.writeByte(attr.method_parameter_table.length);
+ for (MethodParameters_attribute.Entry e : attr.method_parameter_table) {
+ out.writeShort(e.name_index);
+ out.writeInt(e.flags);
+ }
+ return null;
+ }
+
public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, ClassOutputStream out) {
annotationWriter.write(attr.annotations, out);
return null;
diff --git a/langtools/src/share/classes/com/sun/tools/classfile/MethodParameters_attribute.java b/langtools/src/share/classes/com/sun/tools/classfile/MethodParameters_attribute.java
new file mode 100644
index 00000000000..cbf44d20ae4
--- /dev/null
+++ b/langtools/src/share/classes/com/sun/tools/classfile/MethodParameters_attribute.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2012, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 com.sun.tools.classfile;
+
+import java.io.IOException;
+
+/**
+ * See JVMS, section 4.8.13.
+ *
+ * This is NOT part of any supported API.
+ * If you write code that depends on this, you do so at your own risk.
+ * This code and its internal interfaces are subject to change or
+ * deletion without notice.
+ */
+public class MethodParameters_attribute extends Attribute {
+
+ public final int method_parameter_table_length;
+ public final Entry[] method_parameter_table;
+
+ MethodParameters_attribute(ClassReader cr,
+ int name_index,
+ int length)
+ throws IOException {
+ super(name_index, length);
+
+ method_parameter_table_length = cr.readUnsignedByte();
+ method_parameter_table = new Entry[method_parameter_table_length];
+ for (int i = 0; i < method_parameter_table_length; i++)
+ method_parameter_table[i] = new Entry(cr);
+ }
+
+ public MethodParameters_attribute(ConstantPool constant_pool,
+ Entry[] method_parameter_table)
+ throws ConstantPoolException {
+ this(constant_pool.getUTF8Index(Attribute.MethodParameters),
+ method_parameter_table);
+ }
+
+ public MethodParameters_attribute(int name_index,
+ Entry[] method_parameter_table) {
+ super(name_index, 1 + method_parameter_table.length * Entry.length());
+ this.method_parameter_table_length = method_parameter_table.length;
+ this.method_parameter_table = method_parameter_table;
+ }
+
+ public R accept(Visitor visitor, D data) {
+ return visitor.visitMethodParameters(this, data);
+ }
+
+ public static class Entry {
+ Entry(ClassReader cr) throws IOException {
+ name_index = cr.readUnsignedShort();
+ flags = cr.readInt();
+ }
+
+ public static int length() {
+ return 6;
+ }
+
+ public final int name_index;
+ public final int flags;
+ }
+
+}
diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java
index 2f3f84ab054..6f2e19985a4 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java
@@ -1283,8 +1283,9 @@ public abstract class Symbol implements Element {
List paramNames = savedParameterNames;
savedParameterNames = null;
// discard the provided names if the list of names is the wrong size.
- if (paramNames == null || paramNames.size() != type.getParameterTypes().size())
+ if (paramNames == null || paramNames.size() != type.getParameterTypes().size()) {
paramNames = List.nil();
+ }
ListBuffer buf = new ListBuffer();
List remaining = paramNames;
// assert: remaining and paramNames are both empty or both
diff --git a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java
index 224045cc25d..33ee5a780fb 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java
@@ -217,6 +217,13 @@ public class ClassReader implements Completer {
*/
boolean haveParameterNameIndices;
+ /** Set this to false every time we start reading a method
+ * and are saving parameter names. Set it to true when we see
+ * MethodParameters, if it's set when we see a LocalVariableTable,
+ * then we ignore the parameter names from the LVT.
+ */
+ boolean sawMethodParameters;
+
/**
* The set of attribute names for which warnings have been generated for the current class
*/
@@ -984,7 +991,7 @@ public class ClassReader implements Completer {
new AttributeReader(names.LocalVariableTable, V45_3, CLASS_OR_MEMBER_ATTRIBUTE) {
protected void read(Symbol sym, int attrLen) {
int newbp = bp + attrLen;
- if (saveParameterNames) {
+ if (saveParameterNames && !sawMethodParameters) {
// Pick up parameter names from the variable table.
// Parameter names are not explicitly identified as such,
// but all parameter name entries in the LocalVariableTable
@@ -1017,6 +1024,25 @@ public class ClassReader implements Completer {
}
},
+ new AttributeReader(names.MethodParameters, V52, MEMBER_ATTRIBUTE) {
+ protected void read(Symbol sym, int attrlen) {
+ int newbp = bp + attrlen;
+ if (saveParameterNames) {
+ sawMethodParameters = true;
+ int numEntries = nextByte();
+ parameterNameIndices = new int[numEntries];
+ haveParameterNameIndices = true;
+ for (int i = 0; i < numEntries; i++) {
+ int nameIndex = nextChar();
+ int flags = nextInt();
+ parameterNameIndices[i] = nameIndex;
+ }
+ }
+ bp = newbp;
+ }
+ },
+
+
new AttributeReader(names.SourceFile, V45_3, CLASS_ATTRIBUTE) {
protected void read(Symbol sym, int attrLen) {
ClassSymbol c = (ClassSymbol) sym;
@@ -1826,6 +1852,7 @@ public class ClassReader implements Completer {
} else
Arrays.fill(parameterNameIndices, 0);
haveParameterNameIndices = false;
+ sawMethodParameters = false;
}
/**
@@ -1845,12 +1872,16 @@ public class ClassReader implements Completer {
// if no names were found in the class file, there's nothing more to do
if (!haveParameterNameIndices)
return;
-
- int firstParam = ((sym.flags() & STATIC) == 0) ? 1 : 0;
- // the code in readMethod may have skipped the first parameter when
- // setting up the MethodType. If so, we make a corresponding allowance
- // here for the position of the first parameter. Note that this
- // assumes the skipped parameter has a width of 1 -- i.e. it is not
+ // If we get parameter names from MethodParameters, then we
+ // don't need to skip.
+ int firstParam = 0;
+ if (!sawMethodParameters) {
+ firstParam = ((sym.flags() & STATIC) == 0) ? 1 : 0;
+ // the code in readMethod may have skipped the first
+ // parameter when setting up the MethodType. If so, we
+ // make a corresponding allowance here for the position of
+ // the first parameter. Note that this assumes the
+ // skipped parameter has a width of 1 -- i.e. it is not
// a double width type (long or double.)
if (sym.name == names.init && currentOwner.hasOuterInstance()) {
// Sometimes anonymous classes don't have an outer
@@ -1861,17 +1892,20 @@ public class ClassReader implements Completer {
}
if (sym.type != jvmType) {
- // reading the method attributes has caused the symbol's type to
- // be changed. (i.e. the Signature attribute.) This may happen if
- // there are hidden (synthetic) parameters in the descriptor, but
- // not in the Signature. The position of these hidden parameters
- // is unspecified; for now, assume they are at the beginning, and
- // so skip over them. The primary case for this is two hidden
- // parameters passed into Enum constructors.
+ // reading the method attributes has caused the
+ // symbol's type to be changed. (i.e. the Signature
+ // attribute.) This may happen if there are hidden
+ // (synthetic) parameters in the descriptor, but not
+ // in the Signature. The position of these hidden
+ // parameters is unspecified; for now, assume they are
+ // at the beginning, and so skip over them. The
+ // primary case for this is two hidden parameters
+ // passed into Enum constructors.
int skip = Code.width(jvmType.getParameterTypes())
- Code.width(sym.type.getParameterTypes());
firstParam += skip;
}
+ }
List paramNames = List.nil();
int index = firstParam;
for (Type t: sym.type.getParameterTypes()) {
diff --git a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java
index f67e0d3b69a..329000d3e4f 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java
@@ -725,6 +725,28 @@ public class ClassWriter extends ClassFile {
return acount;
}
+ /**
+ * Write method parameter names attribute.
+ */
+ int writeMethodParametersAttr(MethodSymbol m) {
+ if (m.params != null && 0 != m.params.length()) {
+ int attrIndex = writeAttr(names.MethodParameters);
+ databuf.appendByte(m.params.length());
+ for (VarSymbol s : m.params) {
+ // TODO: expand to cover synthesized, once we figure out
+ // how to represent that.
+ final int flags = (int) s.flags() & (FINAL | SYNTHETIC);
+ // output parameter info
+ databuf.appendChar(pool.put(s.name));
+ databuf.appendInt(flags);
+ }
+ endAttr(attrIndex);
+ return 1;
+ } else
+ return 0;
+ }
+
+
/** Write method parameter annotations;
* return number of attributes written.
*/
@@ -1034,6 +1056,8 @@ public class ClassWriter extends ClassFile {
endAttr(alenIdx);
acount++;
}
+ if (options.isSet(PARAMETERS))
+ acount += writeMethodParametersAttr(m);
acount += writeMemberAttrs(m);
acount += writeParameterAttrs(m);
endAttrs(acountIdx, acount);
diff --git a/langtools/src/share/classes/com/sun/tools/javac/main/Option.java b/langtools/src/share/classes/com/sun/tools/javac/main/Option.java
index df4d657269f..5eae7dcb84a 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/main/Option.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/main/Option.java
@@ -176,6 +176,8 @@ public enum Option {
PROCESSORPATH("-processorpath", "opt.arg.path", "opt.processorpath", STANDARD, FILEMANAGER),
+ PARAMETERS("-parameters","opt.parameters", STANDARD, BASIC),
+
D("-d", "opt.arg.directory", "opt.d", STANDARD, FILEMANAGER),
S("-s", "opt.arg.directory", "opt.sourceDest", STANDARD, FILEMANAGER),
diff --git a/langtools/src/share/classes/com/sun/tools/javac/resources/javac.properties b/langtools/src/share/classes/com/sun/tools/javac/resources/javac.properties
index 5d7e383aa6f..9263c3043bc 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/resources/javac.properties
+++ b/langtools/src/share/classes/com/sun/tools/javac/resources/javac.properties
@@ -55,6 +55,8 @@ javac.opt.processorpath=\
Specify where to find annotation processors
javac.opt.processor=\
Names of the annotation processors to run; bypasses default discovery process
+javac.opt.parameters=\
+ Generate metadata for reflection on method parameters
javac.opt.proc.none.only=\
Control whether annotation processing and/or compilation is done.
javac.opt.d=\
diff --git a/langtools/src/share/classes/com/sun/tools/javac/util/Names.java b/langtools/src/share/classes/com/sun/tools/javac/util/Names.java
index 77d7d4097b1..b7b6d3127b8 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/util/Names.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/util/Names.java
@@ -132,6 +132,7 @@ public class Names {
public final Name LineNumberTable;
public final Name LocalVariableTable;
public final Name LocalVariableTypeTable;
+ public final Name MethodParameters;
public final Name RuntimeInvisibleAnnotations;
public final Name RuntimeInvisibleParameterAnnotations;
public final Name RuntimeInvisibleTypeAnnotations;
@@ -265,6 +266,7 @@ public class Names {
LineNumberTable = fromString("LineNumberTable");
LocalVariableTable = fromString("LocalVariableTable");
LocalVariableTypeTable = fromString("LocalVariableTypeTable");
+ MethodParameters = fromString("MethodParameters");
RuntimeInvisibleAnnotations = fromString("RuntimeInvisibleAnnotations");
RuntimeInvisibleParameterAnnotations = fromString("RuntimeInvisibleParameterAnnotations");
RuntimeInvisibleTypeAnnotations = fromString("RuntimeInvisibleTypeAnnotations");
diff --git a/langtools/src/share/classes/com/sun/tools/javap/AttributeWriter.java b/langtools/src/share/classes/com/sun/tools/javap/AttributeWriter.java
index 6263fc86717..329dccb2f87 100644
--- a/langtools/src/share/classes/com/sun/tools/javap/AttributeWriter.java
+++ b/langtools/src/share/classes/com/sun/tools/javap/AttributeWriter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2012, 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
@@ -46,6 +46,7 @@ import com.sun.tools.classfile.InnerClasses_attribute;
import com.sun.tools.classfile.LineNumberTable_attribute;
import com.sun.tools.classfile.LocalVariableTable_attribute;
import com.sun.tools.classfile.LocalVariableTypeTable_attribute;
+import com.sun.tools.classfile.MethodParameters_attribute;
import com.sun.tools.classfile.RuntimeInvisibleAnnotations_attribute;
import com.sun.tools.classfile.RuntimeInvisibleParameterAnnotations_attribute;
import com.sun.tools.classfile.RuntimeVisibleAnnotations_attribute;
@@ -386,6 +387,28 @@ public class AttributeWriter extends BasicWriter
return null;
}
+ private static final String format = "%-31s%s";
+
+ public Void visitMethodParameters(MethodParameters_attribute attr,
+ Void ignore) {
+
+ final String header = String.format(format, "Name", "Flags");
+ println("MethodParameters:");
+ indent(+1);
+ println(header);
+ for (MethodParameters_attribute.Entry entry :
+ attr.method_parameter_table) {
+ String flagstr =
+ (0 != (entry.flags & ACC_FINAL) ? " final" : "") +
+ (0 != (entry.flags & ACC_SYNTHETIC) ? " synthetic" : "");
+ println(String.format(format,
+ constantWriter.stringValue(entry.name_index),
+ flagstr));
+ }
+ indent(-1);
+ return null;
+ }
+
public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, Void ignore) {
println("RuntimeVisibleAnnotations:");
indent(+1);
diff --git a/langtools/test/tools/javac/MethodParameters.java b/langtools/test/tools/javac/MethodParameters.java
new file mode 100644
index 00000000000..74357fa9d00
--- /dev/null
+++ b/langtools/test/tools/javac/MethodParameters.java
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2012, 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 javac should generate method parameters correctly.
+ */
+// key: opt.arg.parameters
+import com.sun.tools.classfile.*;
+import com.sun.tools.javac.file.JavacFileManager;
+import com.sun.tools.javac.main.Main;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.Name;
+import com.sun.tools.javac.util.Names;
+import java.io.*;
+import javax.lang.model.element.*;
+import java.util.*;
+
+public class MethodParameters {
+
+ static final String Foo_name = "Foo";
+ static final String Foo_contents =
+ "public class Foo {\n" +
+ " Foo() {}\n" +
+ " void foo0() {}\n" +
+ " void foo2(int j, int k) {}\n" +
+ "}";
+ static final String Bar_name = "Bar";
+ static final String Bar_contents =
+ "public class Bar {\n" +
+ " Bar(int i) {}" +
+ " Foo foo() { return new Foo(); }\n" +
+ "}";
+ static final String Baz_name = "Baz";
+ static final String Baz_contents =
+ "public class Baz {\n" +
+ " int baz;" +
+ " Baz(int i) {}" +
+ "}";
+ static final String Qux_name = "Qux";
+ static final String Qux_contents =
+ "public class Qux extends Baz {\n" +
+ " Qux(int i) { super(i); }" +
+ "}";
+ static final File classesdir = new File("methodparameters");
+
+ public static void main(String... args) throws Exception {
+ new MethodParameters().run();
+ }
+
+ void run() throws Exception {
+ classesdir.mkdir();
+ final File Foo_java =
+ writeFile(classesdir, Foo_name + ".java", Foo_contents);
+ final File Bar_java =
+ writeFile(classesdir, Bar_name + ".java", Bar_contents);
+ final File Baz_java =
+ writeFile(classesdir, Baz_name + ".java", Baz_contents);
+ System.err.println("Test compile with -parameter");
+ compile("-parameters", "-d", classesdir.getPath(), Foo_java.getPath());
+ // First test: make sure javac doesn't choke to death on
+ // MethodParameter attributes
+ System.err.println("Test compile with classfile containing MethodParameter attributes");
+ compile("-parameters", "-d", classesdir.getPath(),
+ "-cp", classesdir.getPath(), Bar_java.getPath());
+ System.err.println("Examine class foo");
+ checkFoo();
+ checkBar();
+ System.err.println("Test debug information conflict");
+ compile("-g", "-parameters", "-d", classesdir.getPath(),
+ "-cp", classesdir.getPath(), Baz_java.getPath());
+ System.err.println("Introducing debug information conflict");
+ Baz_java.delete();
+ modifyBaz(false);
+ System.err.println("Checking language model");
+ inspectBaz();
+ System.err.println("Permuting attributes");
+ modifyBaz(true);
+ System.err.println("Checking language model");
+ inspectBaz();
+
+ if(0 != errors)
+ throw new Exception("MethodParameters test failed with " +
+ errors + " errors");
+ }
+
+ void inspectBaz() throws Exception {
+ final File Qux_java =
+ writeFile(classesdir, Qux_name + ".java", Qux_contents);
+ final String[] args = { "-XDsave-parameter-names", "-d",
+ classesdir.getPath(),
+ "-cp", classesdir.getPath(),
+ Qux_java.getPath() };
+ final StringWriter sw = new StringWriter();
+ final PrintWriter pw = new PrintWriter(sw);
+
+ // We need to be able to crack open javac and look at its data
+ // structures. We'll rig up a compiler instance, but keep its
+ // Context, thus allowing us to get at the ClassReader.
+ Context context = new Context();
+ Main comp = new Main("javac", pw);
+ JavacFileManager.preRegister(context);
+
+ // Compile Qux, which uses Baz.
+ comp.compile(args, context);
+ pw.close();
+ final String out = sw.toString();
+ if (out.length() > 0)
+ System.err.println(out);
+
+ // Now get the class reader, construct a name for Baz, and load it.
+ com.sun.tools.javac.jvm.ClassReader cr =
+ com.sun.tools.javac.jvm.ClassReader.instance(context);
+ Name name = Names.instance(context).fromString(Baz_name);
+
+ // Now walk down the language model and check the name of the
+ // parameter.
+ final Element baz = cr.loadClass(name);
+ for (Element e : baz.getEnclosedElements()) {
+ if (e instanceof ExecutableElement) {
+ final ExecutableElement ee = (ExecutableElement) e;
+ final List extends VariableElement> params =
+ ee.getParameters();
+ if (1 != params.size())
+ throw new Exception("Classfile Baz badly formed: wrong number of methods");
+ final VariableElement param = params.get(0);
+ if (!param.getSimpleName().contentEquals("baz")) {
+ errors++;
+ System.err.println("javac did not correctly resolve the metadata conflict, parameter's name reads as " + param.getSimpleName());
+ } else
+ System.err.println("javac did correctly resolve the metadata conflict");
+ }
+ }
+ }
+
+ void modifyBaz(boolean flip) throws Exception {
+ final File Baz_class = new File(classesdir, Baz_name + ".class");
+ final ClassFile baz = ClassFile.read(Baz_class);
+ final int ind = baz.constant_pool.getUTF8Index("baz");
+ MethodParameters_attribute mpattr = null;
+ int mpind = 0;
+ Code_attribute cattr = null;
+ int cind = 0;
+
+ // Find the indexes of the MethodParameters and the Code attributes
+ if (baz.methods.length != 1)
+ throw new Exception("Classfile Baz badly formed: wrong number of methods");
+ if (!baz.methods[0].getName(baz.constant_pool).equals(""))
+ throw new Exception("Classfile Baz badly formed: method has name " +
+ baz.methods[0].getName(baz.constant_pool));
+ for (int i = 0; i < baz.methods[0].attributes.attrs.length; i++) {
+ if (baz.methods[0].attributes.attrs[i] instanceof
+ MethodParameters_attribute) {
+ mpattr = (MethodParameters_attribute)
+ baz.methods[0].attributes.attrs[i];
+ mpind = i;
+ } else if (baz.methods[0].attributes.attrs[i] instanceof
+ Code_attribute) {
+ cattr = (Code_attribute) baz.methods[0].attributes.attrs[i];
+ cind = i;
+ }
+ }
+ if (null == mpattr)
+ throw new Exception("Classfile Baz badly formed: no method parameters info");
+ if (null == cattr)
+ throw new Exception("Classfile Baz badly formed: no local variable table");
+
+ int flags = mpattr.method_parameter_table[0].flags;
+
+ // Alter the MethodParameters attribute, changing the name of
+ // the parameter from i to baz. This requires Black Magic...
+ //
+ // The (well-designed) classfile library (correctly) does not
+ // allow us to mess around with the attribute data structures,
+ // or arbitrarily generate new ones.
+ //
+ // Instead, we install a new subclass of Attribute that
+ // hijacks the Visitor pattern and outputs the sequence of
+ // bytes that we want. This only works in this particular
+ // instance, because we know we'll only every see one kind of
+ // visitor.
+ //
+ // If anyone ever changes the makeup of the Baz class, or
+ // tries to install some kind of visitor that gets run prior
+ // to serialization, this will break.
+ baz.methods[0].attributes.attrs[mpind] =
+ new Attribute(mpattr.attribute_name_index,
+ mpattr.attribute_length) {
+ public R accept(Visitor visitor, D data) {
+ if (data instanceof ByteArrayOutputStream) {
+ ByteArrayOutputStream out =
+ (ByteArrayOutputStream) data;
+ out.write(1);
+ out.write((ind >> 8) & 0xff);
+ out.write(ind & 0xff);
+ out.write((flags >> 24) & 0xff);
+ out.write((flags >> 16) & 0xff);
+ out.write((flags >> 8) & 0xff);
+ out.write(flags & 0xff);
+ } else
+ throw new RuntimeException("Output stream is of type " + data.getClass() + ", which is not handled by this test. Update the test and it should work.");
+ return null;
+ }
+ };
+
+ // Flip the code and method attributes. This is for checking
+ // that order doesn't matter.
+ if (flip) {
+ baz.methods[0].attributes.attrs[mpind] = cattr;
+ baz.methods[0].attributes.attrs[cind] = mpattr;
+ }
+
+ new ClassWriter().write(baz, Baz_class);
+ }
+
+ // Run a bunch of structural tests on foo to make sure it looks right.
+ void checkFoo() throws Exception {
+ final File Foo_class = new File(classesdir, Foo_name + ".class");
+ final ClassFile foo = ClassFile.read(Foo_class);
+ for (int i = 0; i < foo.methods.length; i++) {
+ System.err.println("Examine method Foo." + foo.methods[i].getName(foo.constant_pool));
+ if (foo.methods[i].getName(foo.constant_pool).equals("foo2")) {
+ for (int j = 0; j < foo.methods[i].attributes.attrs.length; j++)
+ if (foo.methods[i].attributes.attrs[j] instanceof
+ MethodParameters_attribute) {
+ MethodParameters_attribute mp =
+ (MethodParameters_attribute)
+ foo.methods[i].attributes.attrs[j];
+ System.err.println("Foo.foo2 should have 2 parameters: j and k");
+ if (2 != mp.method_parameter_table_length)
+ error("expected 2 method parameter entries in foo2, got " +
+ mp.method_parameter_table_length);
+ else if (!foo.constant_pool.getUTF8Value(mp.method_parameter_table[0].name_index).equals("j"))
+ error("expected first parameter to foo2 to be \"j\", got \"" +
+ foo.constant_pool.getUTF8Value(mp.method_parameter_table[0].name_index) +
+ "\" instead");
+ else if (!foo.constant_pool.getUTF8Value(mp.method_parameter_table[1].name_index).equals("k"))
+ error("expected first parameter to foo2 to be \"k\", got \"" +
+ foo.constant_pool.getUTF8Value(mp.method_parameter_table[1].name_index) +
+ "\" instead");
+ }
+ }
+ else if (foo.methods[i].getName(foo.constant_pool).equals("")) {
+ for (int j = 0; j < foo.methods[i].attributes.attrs.length; j++) {
+ if (foo.methods[i].attributes.attrs[j] instanceof
+ MethodParameters_attribute)
+ error("Zero-argument constructor shouldn't have MethodParameters");
+ }
+ }
+ else if (foo.methods[i].getName(foo.constant_pool).equals("foo0")) {
+ for (int j = 0; j < foo.methods[i].attributes.attrs.length; j++)
+ if (foo.methods[i].attributes.attrs[j] instanceof
+ MethodParameters_attribute)
+ error("Zero-argument method shouldn't have MethodParameters");
+ }
+ else
+ error("Unknown method " + foo.methods[i].getName(foo.constant_pool) + " showed up in class Foo");
+ }
+ }
+
+ // Run a bunch of structural tests on Bar to make sure it looks right.
+ void checkBar() throws Exception {
+ final File Bar_class = new File(classesdir, Bar_name + ".class");
+ final ClassFile bar = ClassFile.read(Bar_class);
+ for (int i = 0; i < bar.methods.length; i++) {
+ System.err.println("Examine method Bar." + bar.methods[i].getName(bar.constant_pool));
+ if (bar.methods[i].getName(bar.constant_pool).equals("")) {
+ for (int j = 0; j < bar.methods[i].attributes.attrs.length; j++)
+ if (bar.methods[i].attributes.attrs[j] instanceof
+ MethodParameters_attribute) {
+ MethodParameters_attribute mp =
+ (MethodParameters_attribute)
+ bar.methods[i].attributes.attrs[j];
+ System.err.println("Bar constructor should have 1 parameter: i");
+ if (1 != mp.method_parameter_table_length)
+ error("expected 1 method parameter entries in constructor, got " +
+ mp.method_parameter_table_length);
+ else if (!bar.constant_pool.getUTF8Value(mp.method_parameter_table[0].name_index).equals("i"))
+ error("expected first parameter to foo2 to be \"i\", got \"" +
+ bar.constant_pool.getUTF8Value(mp.method_parameter_table[0].name_index) +
+ "\" instead");
+ }
+ }
+ else if (bar.methods[i].getName(bar.constant_pool).equals("foo")) {
+ for (int j = 0; j < bar.methods[i].attributes.attrs.length; j++) {
+ if (bar.methods[i].attributes.attrs[j] instanceof
+ MethodParameters_attribute)
+ error("Zero-argument constructor shouldn't have MethodParameters");
+ }
+ }
+ }
+ }
+
+ String compile(String... args) throws Exception {
+ System.err.println("compile: " + Arrays.asList(args));
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ int rc = com.sun.tools.javac.Main.compile(args, pw);
+ pw.close();
+ String out = sw.toString();
+ if (out.length() > 0)
+ System.err.println(out);
+ if (rc != 0)
+ error("compilation failed, rc=" + rc);
+ return out;
+ }
+
+ File writeFile(File dir, String path, String body) throws IOException {
+ File f = new File(dir, path);
+ f.getParentFile().mkdirs();
+ FileWriter out = new FileWriter(f);
+ out.write(body);
+ out.close();
+ return f;
+ }
+
+ void error(String msg) {
+ System.err.println("Error: " + msg);
+ errors++;
+ }
+
+ int errors;
+}
diff --git a/langtools/test/tools/javap/MethodParameters.java b/langtools/test/tools/javap/MethodParameters.java
new file mode 100644
index 00000000000..500f7417d7a
--- /dev/null
+++ b/langtools/test/tools/javap/MethodParameters.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2010, 2012, 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 javac should generate method parameters correctly.
+ */
+
+import java.io.*;
+import java.util.*;
+
+public class MethodParameters {
+
+ static final String Foo_name = "Foo";
+ static final String Foo_contents =
+ ("public class Foo {\n" +
+ " Foo() {}\n" +
+ " Foo(int i) {}\n" +
+ " void foo0() {}\n" +
+ " void foo2(int j, int k) {}\n" +
+ "}").replaceAll(" +", " ");
+ static final String Init0_expected =
+ (" Foo();\n" +
+ " flags: \n" +
+ " Code:\n" +
+ " stack=1, locals=1, args_size=1\n" +
+ " 0: aload_0 \n" +
+ " 1: invokespecial #1 // Method java/lang/Object.\"\":()V\n" +
+ " 4: return \n" +
+ " LineNumberTable:\n" +
+ " line 2: 0").replaceAll(" +", " ");
+ static final String Init1_expected =
+ (" Foo(int);\n" +
+ " flags: \n" +
+ " Code:\n" +
+ " stack=1, locals=2, args_size=2\n" +
+ " 0: aload_0 \n" +
+ " 1: invokespecial #1 // Method java/lang/Object.\"\":()V\n" +
+ " 4: return \n" +
+ " LineNumberTable:\n" +
+ " line 3: 0\n" +
+ " MethodParameters:\n" +
+ " Name Flags\n" +
+ " i").replaceAll(" +", " ");
+ static final String foo0_expected =
+ (" void foo0();\n" +
+ " flags: \n" +
+ " Code:\n" +
+ " stack=0, locals=1, args_size=1\n" +
+ " 0: return \n" +
+ " LineNumberTable:\n" +
+ " line 4: 0").replaceAll(" +", " ");
+ static final String foo2_expected =
+ (" void foo2(int, int);\n" +
+ " flags: \n" +
+ " Code:\n" +
+ " stack=0, locals=3, args_size=3\n" +
+ " 0: return \n" +
+ " LineNumberTable:\n" +
+ " line 5: 0\n" +
+ " MethodParameters:\n" +
+ " Name Flags\n" +
+ " j \n" +
+ " k").replaceAll(" +", " ");
+
+ static final File classesdir = new File("methodparameters");
+ static final String separator = System.getProperty("line.separator");
+
+ public static void main(String... args) throws Exception {
+ new MethodParameters().run();
+ }
+
+ void run() throws Exception {
+ classesdir.mkdir();
+ final File Foo_java =
+ writeFile(classesdir, Foo_name + ".java", Foo_contents);
+ compile("-parameters", "-d", classesdir.getPath(), Foo_java.getPath());
+ System.out.println("Run javap");
+ String output =
+ javap("-c", "-verbose", "-classpath",
+ classesdir.getPath(), Foo_name);
+ String normalized =
+ output.replaceAll(separator, "\n").replaceAll(" +", " ");
+
+ if (!normalized.contains(Init0_expected))
+ error("Bad output for zero-parameter constructor. Expected\n" +
+ Init0_expected + "\n" + "but got\n" + normalized);
+ if (!normalized.contains(Init1_expected))
+ error("Bad output for one-parameter constructor. Expected\n" +
+ Init1_expected + "\n" + "but got\n" + normalized);
+ if (!normalized.contains(foo0_expected))
+ error("Bad output for zero-parameter method. Expected\n" +
+ foo0_expected + "\n" + "but got\n" + normalized);
+ if (!normalized.contains(foo2_expected))
+ error("Bad output for two-parameter method Expected\n" +
+ foo2_expected + "\n" + "but got\n" + normalized);
+
+ if (0 != errors)
+ throw new Exception("MethodParameters test failed with " +
+ errors + " errors");
+ }
+
+ String javap(String... args) {
+ StringWriter sw = new StringWriter();
+ PrintWriter out = new PrintWriter(sw);
+ //sun.tools.javap.Main.entry(args);
+ int rc = com.sun.tools.javap.Main.run(args, out);
+ if (rc != 0)
+ throw new Error("javap failed. rc=" + rc);
+ out.close();
+ System.out.println(sw);
+ return sw.toString();
+ }
+
+ String compile(String... args) throws Exception {
+ System.err.println("compile: " + Arrays.asList(args));
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ int rc = com.sun.tools.javac.Main.compile(args, pw);
+ pw.close();
+ String out = sw.toString();
+ if (out.length() > 0)
+ System.err.println(out);
+ if (rc != 0)
+ error("compilation failed, rc=" + rc);
+ return out;
+ }
+
+ File writeFile(File dir, String path, String body) throws IOException {
+ File f = new File(dir, path);
+ f.getParentFile().mkdirs();
+ FileWriter out = new FileWriter(f);
+ out.write(body);
+ out.close();
+ return f;
+ }
+
+ void error(String msg) {
+ System.err.println("Error: " + msg);
+ errors++;
+ }
+
+ int errors;
+
+}
From 39734d27f0e2600e329a00489178bc28950ce274 Mon Sep 17 00:00:00 2001
From: Jonathan Gibbons
Date: Sun, 30 Dec 2012 06:17:36 -0800
Subject: [PATCH 06/53] 8005195: Doclint regression tests fail on windows
Reviewed-by: mcimadamore
---
langtools/test/tools/doclint/DocLintTester.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/langtools/test/tools/doclint/DocLintTester.java b/langtools/test/tools/doclint/DocLintTester.java
index 06df949213d..53e26b352f0 100644
--- a/langtools/test/tools/doclint/DocLintTester.java
+++ b/langtools/test/tools/doclint/DocLintTester.java
@@ -107,7 +107,7 @@ public class DocLintTester {
private static final Pattern dirFileLine = Pattern.compile(
"(?m)" // multi-line mode
- + "^([^: ]+?)" // directory part of file name
+ + "^(.*?)" // directory part of file name
+ "([A-Za-z0-9.]+:[0-9]+:)"); // file name and line number
String removeFileNames(String s) {
From 83223ad4acfd5e7e963f2830456bf13e5835cc59 Mon Sep 17 00:00:00 2001
From: Chris Hegarty
Date: Thu, 3 Jan 2013 10:00:55 +0000
Subject: [PATCH 07/53] 8005634: tools/launcher/VersionCheck.java fails version
check on jdeps
Add jdeps to the list of tools that do not support '-version'
Reviewed-by: mchung
---
jdk/test/tools/launcher/VersionCheck.java | 1 +
1 file changed, 1 insertion(+)
diff --git a/jdk/test/tools/launcher/VersionCheck.java b/jdk/test/tools/launcher/VersionCheck.java
index d8018214181..c30ef424011 100644
--- a/jdk/test/tools/launcher/VersionCheck.java
+++ b/jdk/test/tools/launcher/VersionCheck.java
@@ -68,6 +68,7 @@ public class VersionCheck extends TestHelper {
"jcmd",
"jconsole",
"jcontrol",
+ "jdeps",
"jinfo",
"jmap",
"jps",
From 37f63f5f8ad2f9ae03c4f377cc36ea6af1bd04c9 Mon Sep 17 00:00:00 2001
From: David Katleman
Date: Thu, 3 Jan 2013 12:44:32 -0800
Subject: [PATCH 08/53] Added tag jdk8-b71 for changeset 456ba4f4c541
---
.hgtags-top-repo | 1 +
1 file changed, 1 insertion(+)
diff --git a/.hgtags-top-repo b/.hgtags-top-repo
index e187abcd614..39cdca44b38 100644
--- a/.hgtags-top-repo
+++ b/.hgtags-top-repo
@@ -192,3 +192,4 @@ b772de306dc24c17f7bd1398531ddeb58723b804 jdk8-b65
cdb401a60cea6ad5ef3f498725ed1decf8dda1ea jdk8-b68
6ee8080a6efe0639fcd00627a5e0f839bf010481 jdk8-b69
105a25ffa4a4f0af70188d4371b4a0385009b7ce jdk8-b70
+51ad2a34342055333eb5f36e2fb514b027895708 jdk8-b71
From 1c2cee9c68317af8ecc5adaa49705444c69dcc80 Mon Sep 17 00:00:00 2001
From: David Katleman
Date: Thu, 3 Jan 2013 12:44:34 -0800
Subject: [PATCH 09/53] Added tag jdk8-b71 for changeset 9d40ca78a623
---
corba/.hgtags | 1 +
1 file changed, 1 insertion(+)
diff --git a/corba/.hgtags b/corba/.hgtags
index 4b792172c50..63281ba72d9 100644
--- a/corba/.hgtags
+++ b/corba/.hgtags
@@ -192,3 +192,4 @@ d54dc53e223ed9ce7d5f4d2cd02ad9d5def3c2db jdk8-b59
82000531feaa7baef76b6406099e5cd88943d635 jdk8-b68
22ddcac208a8dea894a16887d04f3ca4d3c5d267 jdk8-b69
603cceb495c8133d47b26a7502d51c7d8a67d76b jdk8-b70
+8171d23e914d758836527b80b06debcfdb718f2d jdk8-b71
From 54b645a88bb32c0c3be6f2458afbc25d647adfa1 Mon Sep 17 00:00:00 2001
From: David Katleman
Date: Thu, 3 Jan 2013 12:44:39 -0800
Subject: [PATCH 10/53] Added tag jdk8-b71 for changeset 03dafcea1815
---
hotspot/.hgtags | 1 +
1 file changed, 1 insertion(+)
diff --git a/hotspot/.hgtags b/hotspot/.hgtags
index a7ac93bb5cd..ea060b2d1f4 100644
--- a/hotspot/.hgtags
+++ b/hotspot/.hgtags
@@ -304,3 +304,4 @@ b6c9c0109a608eedbb6b868d260952990e3c91fe hs25-b13
cb8a4e04bc8c104de8a2f67463c7e31232bf8d68 jdk8-b69
990bbd393c239d95310ccc38094e57923bbf1d4a hs25-b14
e94068d4ff52849c8aa0786a53a59b63d1312a39 jdk8-b70
+0847210f85480bf3848dc90bc2ab23c0a4791b55 jdk8-b71
From 98f5be72c4c44ae8f66a2fadaa026c58b8200b6b Mon Sep 17 00:00:00 2001
From: David Katleman
Date: Thu, 3 Jan 2013 12:44:46 -0800
Subject: [PATCH 11/53] Added tag jdk8-b71 for changeset c27887135b51
---
jaxp/.hgtags | 1 +
1 file changed, 1 insertion(+)
diff --git a/jaxp/.hgtags b/jaxp/.hgtags
index a3961e5fd96..e458166f146 100644
--- a/jaxp/.hgtags
+++ b/jaxp/.hgtags
@@ -192,3 +192,4 @@ e6af1ad464e3d9b1154b9f9ed9a5373b97d129fc jdk8-b66
b854e70084214e9dcf1b37373f6e4b1a68760e03 jdk8-b68
789a855de959f7e9600e57759c6c3dbb0b24d78b jdk8-b69
6ec9edffc286c9c9ac96c9cd2050b01cb5d514a8 jdk8-b70
+499be952a291cec1dc774a84a238941d6faf772d jdk8-b71
From 240cfb1ef1b165ca4aa7ea983bf1332896c02d17 Mon Sep 17 00:00:00 2001
From: David Katleman
Date: Thu, 3 Jan 2013 12:44:47 -0800
Subject: [PATCH 12/53] Added tag jdk8-b71 for changeset 25285d2ea668
---
jaxws/.hgtags | 1 +
1 file changed, 1 insertion(+)
diff --git a/jaxws/.hgtags b/jaxws/.hgtags
index 8ea30fd20d0..f4748481e87 100644
--- a/jaxws/.hgtags
+++ b/jaxws/.hgtags
@@ -192,3 +192,4 @@ eb06aa51dfc225614dba2d89ae7ca6cedddff982 jdk8-b67
d3fe408f3a9ad250bc9a4e9365bdfc3f28c1d3f4 jdk8-b68
756323c990115a9c0341d67b10f2d52c6370e35d jdk8-b69
3b1c2733d47ee9f8c530925df4041c59f9ee5a31 jdk8-b70
+f577a39c9fb3d5820248c13c2cc74a192a9313e0 jdk8-b71
From 36dee83516545a73ed68ae5652236746cf4150ec Mon Sep 17 00:00:00 2001
From: David Katleman
Date: Thu, 3 Jan 2013 12:44:50 -0800
Subject: [PATCH 13/53] Added tag jdk8-b71 for changeset 8c4241503c02
---
jdk/.hgtags | 1 +
1 file changed, 1 insertion(+)
diff --git a/jdk/.hgtags b/jdk/.hgtags
index c234e2c613b..9ea50bcf6b8 100644
--- a/jdk/.hgtags
+++ b/jdk/.hgtags
@@ -192,3 +192,4 @@ ce9b02a3a17edd1983201002cfa0f364e4ab7524 jdk8-b67
53fb43e4d614c92310e1fb00ec41d1960fd9facf jdk8-b68
a8012d8d7e9c5035de0bdd4887dc9f7c54008f21 jdk8-b69
a996b57e554198f4592a5f3c30f2f9f4075e545d jdk8-b70
+2a5af0f766d0acd68a81fb08fe11fd66795f86af jdk8-b71
From 696db0f4f7a10619c4ea9cc0479a027cea9d4c1e Mon Sep 17 00:00:00 2001
From: David Katleman
Date: Thu, 3 Jan 2013 12:44:58 -0800
Subject: [PATCH 14/53] Added tag jdk8-b71 for changeset 3849a5b1c05c
---
langtools/.hgtags | 1 +
1 file changed, 1 insertion(+)
diff --git a/langtools/.hgtags b/langtools/.hgtags
index ea5dc98ff77..736fb76891a 100644
--- a/langtools/.hgtags
+++ b/langtools/.hgtags
@@ -192,3 +192,4 @@ e6ee43b3e2473798b17a556e9f11eebe25ab81d4 jdk8-b64
014a6a11dfe5ddc23ec8c76bb42ac998dbf49acb jdk8-b68
d7360bf35ee1f40ff78c2e83a22b5446ee464346 jdk8-b69
47f71d7c124f24c2fe2dfc49865b332345b458ed jdk8-b70
+467e4d9281bcf119eaec42af1423c96bd401871c jdk8-b71
From 6061c09cab10db4ba809a8e7d140188c9c382ce7 Mon Sep 17 00:00:00 2001
From: Chris Hegarty
Date: Fri, 4 Jan 2013 11:18:00 +0000
Subject: [PATCH 15/53] 8005659: Add tools/pack200/AttributeTests.java to
exclude list (ProblemList.txt) until pack200 updated to support method
parameters
Reviewed-by: mchung, ksrini
---
jdk/test/ProblemList.txt | 3 +++
1 file changed, 3 insertions(+)
diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt
index ec698c7ef5d..e8bd6328599 100644
--- a/jdk/test/ProblemList.txt
+++ b/jdk/test/ProblemList.txt
@@ -324,6 +324,9 @@ tools/pack200/Pack200Test.java generic-all
# 7150569
tools/launcher/UnicodeTest.java macosx-all
+# 8005252
+tools/pack200/AttributeTests.java generic-all
+
############################################################################
# jdk_jdi
From c994d9bc0e6bfa2a730f71be8fcafd708537a240 Mon Sep 17 00:00:00 2001
From: Chris Hegarty
Date: Fri, 4 Jan 2013 11:34:17 +0000
Subject: [PATCH 16/53] 8005638: Less secure Authentication schemes should work
when more secure schemes are not available
Reviewed-by: alanb
---
.../sun/net/www/protocol/http/AuthenticationHeader.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/jdk/src/share/classes/sun/net/www/protocol/http/AuthenticationHeader.java b/jdk/src/share/classes/sun/net/www/protocol/http/AuthenticationHeader.java
index 390898292f0..41f55998973 100644
--- a/jdk/src/share/classes/sun/net/www/protocol/http/AuthenticationHeader.java
+++ b/jdk/src/share/classes/sun/net/www/protocol/http/AuthenticationHeader.java
@@ -206,7 +206,8 @@ public class AuthenticationHeader {
if(v == null) {
if ((v=schemes.get ("digest")) == null) {
- if (((v=schemes.get("ntlm"))==null)) {
+ if (!NTLMAuthenticationProxy.supported
+ || ((v=schemes.get("ntlm"))==null)) {
v = schemes.get ("basic");
}
}
From 6ae79cff82bca3ab44651139dbcfced307c3f0e0 Mon Sep 17 00:00:00 2001
From: Amy Lu
Date: Fri, 4 Jan 2013 16:10:14 -0800
Subject: [PATCH 17/53] 8005683: ProblemList.txt updates (01/2013)
Reviewed-by: mchung, alanb
---
jdk/test/ProblemList.txt | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt
index e8bd6328599..d2387317b5d 100644
--- a/jdk/test/ProblemList.txt
+++ b/jdk/test/ProblemList.txt
@@ -122,9 +122,6 @@
# jdk_lang
-# 7194607
-java/lang/instrument/VerifyLocalVariableTableOnRetransformTest.sh generic-all
-
# 6944188
java/lang/management/ThreadMXBean/ThreadStateTest.java generic-all
@@ -148,6 +145,9 @@ java/lang/management/MemoryMXBean/LowMemoryTest2.sh generic-all
# 6959636
javax/management/loading/LibraryLoader/LibraryLoaderTest.java windows-all
+# 8005472
+com/sun/jmx/remote/NotificationMarshalVersions/TestSerializationMismatch.sh windows-all
+
############################################################################
# jdk_math
From 1dbfb160ba30cfb15983fa0e8e9326198401dc31 Mon Sep 17 00:00:00 2001
From: Bhavesh Patel
Date: Fri, 4 Jan 2013 23:06:05 -0800
Subject: [PATCH 18/53] 8004891: Check for abstract method in javadoc does not
conform to the language model
Reviewed-by: jjg
---
.../formats/html/AbstractMemberWriter.java | 18 ++-
.../com/sun/tools/javadoc/MethodDocImpl.java | 11 +-
.../TestAbstractMethod.java | 121 ++++++++++++++++++
.../sun/javadoc/testAbstractMethod/pkg/A.java | 31 +++++
.../sun/javadoc/testAbstractMethod/pkg/B.java | 31 +++++
.../sun/javadoc/testAbstractMethod/pkg/C.java | 29 +++++
6 files changed, 224 insertions(+), 17 deletions(-)
create mode 100644 langtools/test/com/sun/javadoc/testAbstractMethod/TestAbstractMethod.java
create mode 100644 langtools/test/com/sun/javadoc/testAbstractMethod/pkg/A.java
create mode 100644 langtools/test/com/sun/javadoc/testAbstractMethod/pkg/B.java
create mode 100644 langtools/test/com/sun/javadoc/testAbstractMethod/pkg/C.java
diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractMemberWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractMemberWriter.java
index b11d255e565..b8b03545380 100644
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractMemberWriter.java
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractMemberWriter.java
@@ -321,7 +321,8 @@ public abstract class AbstractMemberWriter {
code.addContent(" ");
}
if (member.isMethod()) {
- if (((MethodDoc)member).isAbstract()) {
+ if (!(member.containingClass().isInterface()) &&
+ ((MethodDoc)member).isAbstract()) {
code.addContent("abstract ");
}
// This check for isDefault() and the default modifier needs to be
@@ -329,7 +330,7 @@ public abstract class AbstractMemberWriter {
// method summary section. Once the default modifier is added
// to the Modifier list on DocEnv and once it is updated to use the
// javax.lang.model.element.Modifier, we will need to remove this.
- else if (((MethodDoc)member).isDefault()) {
+ if (((MethodDoc)member).isDefault()) {
code.addContent("default ");
}
}
@@ -561,11 +562,14 @@ public abstract class AbstractMemberWriter {
if (member instanceof MethodDoc && !member.isAnnotationTypeElement()) {
int methodType = (member.isStatic()) ? MethodTypes.STATIC.value() :
MethodTypes.INSTANCE.value();
- methodType = (classdoc.isInterface() || ((MethodDoc)member).isAbstract()) ?
- methodType | MethodTypes.ABSTRACT.value() :
- methodType | MethodTypes.CONCRETE.value();
- if (((MethodDoc)member).isDefault()) {
- methodType = methodType | MethodTypes.DEFAULT.value();
+ if (member.containingClass().isInterface()) {
+ methodType = (((MethodDoc) member).isAbstract())
+ ? methodType | MethodTypes.ABSTRACT.value()
+ : methodType | MethodTypes.DEFAULT.value();
+ } else {
+ methodType = (((MethodDoc) member).isAbstract())
+ ? methodType | MethodTypes.ABSTRACT.value()
+ : methodType | MethodTypes.CONCRETE.value();
}
if (Util.isDeprecated(member) || Util.isDeprecated(classdoc)) {
methodType = methodType | MethodTypes.DEPRECATED.value();
diff --git a/langtools/src/share/classes/com/sun/tools/javadoc/MethodDocImpl.java b/langtools/src/share/classes/com/sun/tools/javadoc/MethodDocImpl.java
index 52b828fea1f..d8c03a8c980 100644
--- a/langtools/src/share/classes/com/sun/tools/javadoc/MethodDocImpl.java
+++ b/langtools/src/share/classes/com/sun/tools/javadoc/MethodDocImpl.java
@@ -86,16 +86,7 @@ public class MethodDocImpl
* Return true if this method is abstract
*/
public boolean isAbstract() {
- //### This is dubious, but old 'javadoc' apparently does it.
- //### I regard this as a bug and an obstacle to treating the
- //### doclet API as a proper compile-time reflection facility.
- //### (maddox 09/26/2000)
- if (containingClass().isInterface()) {
- //### Don't force creation of ClassDocImpl for super here.
- // Abstract modifier is implicit. Strip/canonicalize it.
- return false;
- }
- return Modifier.isAbstract(getModifiers());
+ return (Modifier.isAbstract(getModifiers()) && !isDefault());
}
/**
diff --git a/langtools/test/com/sun/javadoc/testAbstractMethod/TestAbstractMethod.java b/langtools/test/com/sun/javadoc/testAbstractMethod/TestAbstractMethod.java
new file mode 100644
index 00000000000..75a662da7d2
--- /dev/null
+++ b/langtools/test/com/sun/javadoc/testAbstractMethod/TestAbstractMethod.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2012, 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 8004891
+ * @summary Make sure that the abstract method is identified correctly
+ * if the abstract modifier is present explicitly or implicitly.
+ * @author bpatel
+ * @library ../lib/
+ * @build JavadocTester TestAbstractMethod
+ * @run main TestAbstractMethod
+ */
+
+public class TestAbstractMethod extends JavadocTester {
+
+ //Test information.
+ private static final String BUG_ID = "8004891";
+
+ //Javadoc arguments.
+ private static final String[] ARGS = new String[] {
+ "-d", BUG_ID, "-sourcepath", SRC_DIR, "pkg"
+ };
+
+ //Input for string search tests.
+ private static final String[][] TEST = {
+ {BUG_ID + FS + "pkg" + FS + "A.html",
+ "default void | "},
+ {BUG_ID + FS + "pkg" + FS + "A.html",
+ "" +
+ "All Methods " +
+ "" +
+ "Instance Methods" +
+ " " +
+ "Abstract Methods " +
+ "" +
+ "Default Methods" +
+ " "},
+ {BUG_ID + FS + "pkg" + FS + "B.html",
+ "" +
+ "All Methods " +
+ "" +
+ "Instance Methods" +
+ " Abstract " +
+ "Methods " +
+ "" +
+ "Concrete Methods" +
+ " "},
+ {BUG_ID + FS + "pkg" + FS + "B.html",
+ "abstract void | "},
+ {BUG_ID + FS + "pkg" + FS + "C.html",
+ "" +
+ "All Methods " +
+ "" +
+ "Instance Methods" +
+ " " +
+ "" +
+ "Default Methods" +
+ " "},
+ {BUG_ID + FS + "pkg" + FS + "C.html",
+ "default void | "}
+ };
+ private static final String[][] NEGATED_TEST = {
+ {BUG_ID + FS + "pkg" + FS + "A.html",
+ "abstract void | "},
+ {BUG_ID + FS + "pkg" + FS + "B.html",
+ "Default Methods" +
+ " "},
+ {BUG_ID + FS + "pkg" + FS + "B.html",
+ "default void | "},
+ {BUG_ID + FS + "pkg" + FS + "C.html",
+ "Abstract Methods" +
+ " "}
+ };
+
+ /**
+ * The entry point of the test.
+ * @param args the array of command line arguments.
+ */
+ public static void main(String[] args) {
+ TestAbstractMethod tester = new TestAbstractMethod();
+ run(tester, ARGS, TEST, NEGATED_TEST);
+ tester.printSummary();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getBugId() {
+ return BUG_ID;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getBugName() {
+ return getClass().getName();
+ }
+}
diff --git a/langtools/test/com/sun/javadoc/testAbstractMethod/pkg/A.java b/langtools/test/com/sun/javadoc/testAbstractMethod/pkg/A.java
new file mode 100644
index 00000000000..c52f249b491
--- /dev/null
+++ b/langtools/test/com/sun/javadoc/testAbstractMethod/pkg/A.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2012, 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 pkg;
+
+public interface A {
+
+ public void method1();
+
+ public default void defaultMethod() { }
+}
diff --git a/langtools/test/com/sun/javadoc/testAbstractMethod/pkg/B.java b/langtools/test/com/sun/javadoc/testAbstractMethod/pkg/B.java
new file mode 100644
index 00000000000..ccc58e191d2
--- /dev/null
+++ b/langtools/test/com/sun/javadoc/testAbstractMethod/pkg/B.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2012, 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 pkg;
+
+public abstract class B {
+
+ public abstract void method1();
+
+ public void method2() { }
+}
diff --git a/langtools/test/com/sun/javadoc/testAbstractMethod/pkg/C.java b/langtools/test/com/sun/javadoc/testAbstractMethod/pkg/C.java
new file mode 100644
index 00000000000..a348a69ae8c
--- /dev/null
+++ b/langtools/test/com/sun/javadoc/testAbstractMethod/pkg/C.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2012, 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 pkg;
+
+public interface C {
+
+ public default void onlyMethod() { }
+}
From d0ff55ec00b4f4446c03e7eaa3be28906fb451c5 Mon Sep 17 00:00:00 2001
From: Bhavesh Patel
Date: Sat, 5 Jan 2013 00:55:53 -0800
Subject: [PATCH 19/53] 8005092: javadoc should check for synthesized bit on an
annotation
Reviewed-by: jjg
---
.../com/sun/javadoc/AnnotationDesc.java | 6 +
.../formats/html/HtmlDocletWriter.java | 167 +++++++++++++---
.../sun/tools/javadoc/AnnotationDescImpl.java | 9 +
.../TestRepeatedAnnotations.java | 187 ++++++++++++++++++
.../testRepeatedAnnotations/pkg/C.java | 39 ++++
.../pkg/ContaineeRegDoc.java | 36 ++++
.../pkg/ContaineeSynthDoc.java | 37 ++++
.../pkg/ContainerRegDoc.java | 38 ++++
.../pkg/ContainerRegNotDoc.java | 37 ++++
.../pkg/ContainerSynthDoc.java | 39 ++++
.../testRepeatedAnnotations/pkg/D.java | 37 ++++
.../pkg/NonSynthDocContainer.java | 38 ++++
.../pkg/RegArryDoc.java | 38 ++++
.../pkg/RegContaineeDoc.java | 36 ++++
.../pkg/RegContaineeNotDoc.java | 36 ++++
.../pkg/RegContainerDoc.java | 38 ++++
.../pkg/RegContainerNotDoc.java | 37 ++++
.../testRepeatedAnnotations/pkg/RegDoc.java | 38 ++++
.../testRepeatedAnnotations/pkg1/C.java | 38 ++++
.../pkg1/ContaineeNotDoc.java | 36 ++++
.../pkg1/ContaineeSynthDoc.java | 37 ++++
.../pkg1/ContainerSynthNotDoc.java | 38 ++++
.../pkg1/ContainerValDoc.java | 40 ++++
.../pkg1/ContainerValNotDoc.java | 39 ++++
.../pkg1/RegContaineeDoc.java | 36 ++++
.../pkg1/RegContaineeNotDoc.java | 35 ++++
.../pkg1/RegContainerValDoc.java | 40 ++++
.../pkg1/RegContainerValNotDoc.java | 39 ++++
28 files changed, 1243 insertions(+), 28 deletions(-)
create mode 100644 langtools/test/com/sun/javadoc/testRepeatedAnnotations/TestRepeatedAnnotations.java
create mode 100644 langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/C.java
create mode 100644 langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/ContaineeRegDoc.java
create mode 100644 langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/ContaineeSynthDoc.java
create mode 100644 langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/ContainerRegDoc.java
create mode 100644 langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/ContainerRegNotDoc.java
create mode 100644 langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/ContainerSynthDoc.java
create mode 100644 langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/D.java
create mode 100644 langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/NonSynthDocContainer.java
create mode 100644 langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/RegArryDoc.java
create mode 100644 langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/RegContaineeDoc.java
create mode 100644 langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/RegContaineeNotDoc.java
create mode 100644 langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/RegContainerDoc.java
create mode 100644 langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/RegContainerNotDoc.java
create mode 100644 langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/RegDoc.java
create mode 100644 langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/C.java
create mode 100644 langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/ContaineeNotDoc.java
create mode 100644 langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/ContaineeSynthDoc.java
create mode 100644 langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/ContainerSynthNotDoc.java
create mode 100644 langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/ContainerValDoc.java
create mode 100644 langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/ContainerValNotDoc.java
create mode 100644 langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/RegContaineeDoc.java
create mode 100644 langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/RegContaineeNotDoc.java
create mode 100644 langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/RegContainerValDoc.java
create mode 100644 langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/RegContainerValNotDoc.java
diff --git a/langtools/src/share/classes/com/sun/javadoc/AnnotationDesc.java b/langtools/src/share/classes/com/sun/javadoc/AnnotationDesc.java
index 068763bf85c..bf99121043a 100644
--- a/langtools/src/share/classes/com/sun/javadoc/AnnotationDesc.java
+++ b/langtools/src/share/classes/com/sun/javadoc/AnnotationDesc.java
@@ -52,6 +52,12 @@ public interface AnnotationDesc {
*/
ElementValuePair[] elementValues();
+ /**
+ * Check for the synthesized bit on the annotation.
+ *
+ * @return true if the annotation is synthesized.
+ */
+ boolean isSynthesized();
/**
* Represents an association between an annotation type element
diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java
index 57609a10b48..d8f21e815ba 100644
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java
@@ -89,6 +89,16 @@ public class HtmlDocletWriter extends HtmlDocWriter {
*/
protected boolean printedAnnotationHeading = false;
+ /**
+ * To check whether the repeated annotations is documented or not.
+ */
+ private boolean isAnnotationDocumented = false;
+
+ /**
+ * To check whether the container annotations is documented or not.
+ */
+ private boolean isContainerDocumented = false;
+
/**
* Constructor to construct the HtmlStandardWriter object.
*
@@ -1793,50 +1803,66 @@ public class HtmlDocletWriter extends HtmlDocWriter {
StringBuilder annotation;
for (int i = 0; i < descList.length; i++) {
AnnotationTypeDoc annotationDoc = descList[i].annotationType();
- if (! Util.isDocumentedAnnotation(annotationDoc)){
+ // If an annotation is not documented, do not add it to the list. If
+ // the annotation is of a repeatable type, and if it is not documented
+ // and also if its container annotation is not documented, do not add it
+ // to the list. If an annotation of a repeatable type is not documented
+ // but its container is documented, it will be added to the list.
+ if (! Util.isDocumentedAnnotation(annotationDoc) &&
+ (!isAnnotationDocumented && !isContainerDocumented)) {
continue;
}
annotation = new StringBuilder();
+ isAnnotationDocumented = false;
LinkInfoImpl linkInfo = new LinkInfoImpl(configuration,
LinkInfoImpl.CONTEXT_ANNOTATION, annotationDoc);
- linkInfo.label = "@" + annotationDoc.name();
- annotation.append(getLink(linkInfo));
AnnotationDesc.ElementValuePair[] pairs = descList[i].elementValues();
- if (pairs.length > 0) {
- annotation.append('(');
+ // If the annotation is synthesized, do not print the container.
+ if (descList[i].isSynthesized()) {
for (int j = 0; j < pairs.length; j++) {
- if (j > 0) {
- annotation.append(",");
- if (linkBreak) {
- annotation.append(DocletConstants.NL);
- int spaces = annotationDoc.name().length() + 2;
- for (int k = 0; k < (spaces + indent); k++) {
- annotation.append(' ');
- }
- }
- }
- annotation.append(getDocLink(LinkInfoImpl.CONTEXT_ANNOTATION,
- pairs[j].element(), pairs[j].element().name(), false));
- annotation.append('=');
AnnotationValue annotationValue = pairs[j].value();
List annotationTypeValues = new ArrayList();
if (annotationValue.value() instanceof AnnotationValue[]) {
AnnotationValue[] annotationArray =
- (AnnotationValue[]) annotationValue.value();
- for (int k = 0; k < annotationArray.length; k++) {
- annotationTypeValues.add(annotationArray[k]);
- }
+ (AnnotationValue[]) annotationValue.value();
+ annotationTypeValues.addAll(Arrays.asList(annotationArray));
} else {
annotationTypeValues.add(annotationValue);
}
- annotation.append(annotationTypeValues.size() == 1 ? "" : "{");
- for (Iterator iter = annotationTypeValues.iterator(); iter.hasNext(); ) {
- annotation.append(annotationValueToString(iter.next()));
- annotation.append(iter.hasNext() ? "," : "");
+ String sep = "";
+ for (AnnotationValue av : annotationTypeValues) {
+ annotation.append(sep);
+ annotation.append(annotationValueToString(av));
+ sep = " ";
}
- annotation.append(annotationTypeValues.size() == 1 ? "" : "}");
}
- annotation.append(")");
+ }
+ else if (isAnnotationArray(pairs)) {
+ // If the container has 1 or more value defined and if the
+ // repeatable type annotation is not documented, do not print
+ // the container.
+ if (pairs.length == 1 && isAnnotationDocumented) {
+ AnnotationValue[] annotationArray =
+ (AnnotationValue[]) (pairs[0].value()).value();
+ List annotationTypeValues = new ArrayList();
+ annotationTypeValues.addAll(Arrays.asList(annotationArray));
+ String sep = "";
+ for (AnnotationValue av : annotationTypeValues) {
+ annotation.append(sep);
+ annotation.append(annotationValueToString(av));
+ sep = " ";
+ }
+ }
+ // If the container has 1 or more value defined and if the
+ // repeatable type annotation is not documented, print the container.
+ else {
+ addAnnotations(annotationDoc, linkInfo, annotation, pairs,
+ indent, false);
+ }
+ }
+ else {
+ addAnnotations(annotationDoc, linkInfo, annotation, pairs,
+ indent, linkBreak);
}
annotation.append(linkBreak ? DocletConstants.NL : "");
results.add(annotation.toString());
@@ -1844,6 +1870,91 @@ public class HtmlDocletWriter extends HtmlDocWriter {
return results;
}
+ /**
+ * Add annotation to the annotation string.
+ *
+ * @param annotationDoc the annotation being documented
+ * @param linkInfo the information about the link
+ * @param annotation the annotation string to which the annotation will be added
+ * @param pairs annotation type element and value pairs
+ * @param indent the number of extra spaces to indent the annotations.
+ * @param linkBreak if true, add new line between each member value
+ */
+ private void addAnnotations(AnnotationTypeDoc annotationDoc, LinkInfoImpl linkInfo,
+ StringBuilder annotation, AnnotationDesc.ElementValuePair[] pairs,
+ int indent, boolean linkBreak) {
+ linkInfo.label = "@" + annotationDoc.name();
+ annotation.append(getLink(linkInfo));
+ if (pairs.length > 0) {
+ annotation.append('(');
+ for (int j = 0; j < pairs.length; j++) {
+ if (j > 0) {
+ annotation.append(",");
+ if (linkBreak) {
+ annotation.append(DocletConstants.NL);
+ int spaces = annotationDoc.name().length() + 2;
+ for (int k = 0; k < (spaces + indent); k++) {
+ annotation.append(' ');
+ }
+ }
+ }
+ annotation.append(getDocLink(LinkInfoImpl.CONTEXT_ANNOTATION,
+ pairs[j].element(), pairs[j].element().name(), false));
+ annotation.append('=');
+ AnnotationValue annotationValue = pairs[j].value();
+ List annotationTypeValues = new ArrayList();
+ if (annotationValue.value() instanceof AnnotationValue[]) {
+ AnnotationValue[] annotationArray =
+ (AnnotationValue[]) annotationValue.value();
+ annotationTypeValues.addAll(Arrays.asList(annotationArray));
+ } else {
+ annotationTypeValues.add(annotationValue);
+ }
+ annotation.append(annotationTypeValues.size() == 1 ? "" : "{");
+ String sep = "";
+ for (AnnotationValue av : annotationTypeValues) {
+ annotation.append(sep);
+ annotation.append(annotationValueToString(av));
+ sep = ",";
+ }
+ annotation.append(annotationTypeValues.size() == 1 ? "" : "}");
+ isContainerDocumented = false;
+ }
+ annotation.append(")");
+ }
+ }
+
+ /**
+ * Check if the annotation contains an array of annotation as a value. This
+ * check is to verify if a repeatable type annotation is present or not.
+ *
+ * @param pairs annotation type element and value pairs
+ *
+ * @return true if the annotation contains an array of annotation as a value.
+ */
+ private boolean isAnnotationArray(AnnotationDesc.ElementValuePair[] pairs) {
+ AnnotationValue annotationValue;
+ for (int j = 0; j < pairs.length; j++) {
+ annotationValue = pairs[j].value();
+ if (annotationValue.value() instanceof AnnotationValue[]) {
+ AnnotationValue[] annotationArray =
+ (AnnotationValue[]) annotationValue.value();
+ if (annotationArray.length > 1) {
+ if (annotationArray[0].value() instanceof AnnotationDesc) {
+ AnnotationTypeDoc annotationDoc =
+ ((AnnotationDesc) annotationArray[0].value()).annotationType();
+ isContainerDocumented = true;
+ if (Util.isDocumentedAnnotation(annotationDoc)) {
+ isAnnotationDocumented = true;
+ }
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
private String annotationValueToString(AnnotationValue annotationValue) {
if (annotationValue.value() instanceof Type) {
Type type = (Type) annotationValue.value();
diff --git a/langtools/src/share/classes/com/sun/tools/javadoc/AnnotationDescImpl.java b/langtools/src/share/classes/com/sun/tools/javadoc/AnnotationDescImpl.java
index 7cfbf52425e..166089dfd11 100644
--- a/langtools/src/share/classes/com/sun/tools/javadoc/AnnotationDescImpl.java
+++ b/langtools/src/share/classes/com/sun/tools/javadoc/AnnotationDescImpl.java
@@ -88,6 +88,15 @@ public class AnnotationDescImpl implements AnnotationDesc {
return res;
}
+ /**
+ * Check for the synthesized bit on the annotation.
+ *
+ * @return true if the annotation is synthesized.
+ */
+ public boolean isSynthesized() {
+ return annotation.isSynthesized();
+ }
+
/**
* Returns a string representation of this annotation.
* String is of one of the forms:
diff --git a/langtools/test/com/sun/javadoc/testRepeatedAnnotations/TestRepeatedAnnotations.java b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/TestRepeatedAnnotations.java
new file mode 100644
index 00000000000..709b2ef2d32
--- /dev/null
+++ b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/TestRepeatedAnnotations.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2012, 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 8005092
+ * @summary Test repeated annotations output.
+ * @author bpatel
+ * @library ../lib/
+ * @build JavadocTester TestRepeatedAnnotations
+ * @run main TestRepeatedAnnotations
+ */
+
+public class TestRepeatedAnnotations extends JavadocTester {
+
+ //Test information.
+ private static final String BUG_ID = "8005092";
+
+ //Javadoc arguments.
+ private static final String[] ARGS = new String[] {
+ "-d", BUG_ID, "-sourcepath", SRC_DIR, "pkg", "pkg1"
+ };
+
+ //Input for string search tests.
+ private static final String[][] TEST = {
+ {BUG_ID + FS + "pkg" + FS + "C.html",
+ "@ContaineeSynthDoc " +
+ "@ContaineeSynthDoc"},
+ {BUG_ID + FS + "pkg" + FS + "C.html",
+ "@ContaineeRegDoc " +
+ "@ContaineeRegDoc"},
+ {BUG_ID + FS + "pkg" + FS + "C.html",
+ "@RegContainerDoc" +
+ "(value={" +
+ "@RegContaineeNotDoc," +
+ "@RegContaineeNotDoc})"},
+ {BUG_ID + FS + "pkg" + FS + "C.html",
+ "@ContaineeSynthDoc " +
+ "@ContaineeSynthDoc " +
+ "@ContaineeSynthDoc"},
+ {BUG_ID + FS + "pkg" + FS + "C.html",
+ "@ContainerSynthDoc(" +
+ "value=" +
+ "@ContaineeSynthDoc)"},
+ {BUG_ID + FS + "pkg" + FS + "C.html",
+ "@ContaineeSynthDoc " +
+ "@ContaineeSynthDoc"},
+
+ {BUG_ID + FS + "pkg" + FS + "D.html",
+ "@RegDoc" +
+ "(x=1)"},
+ {BUG_ID + FS + "pkg" + FS + "D.html",
+ "@RegArryDoc" +
+ "(y=1)"},
+ {BUG_ID + FS + "pkg" + FS + "D.html",
+ "@RegArryDoc" +
+ "(y={1,2})"},
+ {BUG_ID + FS + "pkg" + FS + "D.html",
+ "@NonSynthDocContainer" +
+ "(value=" +
+ "@RegArryDoc)"},
+
+ {BUG_ID + FS + "pkg1" + FS + "C.html",
+ "@RegContainerValDoc" +
+ "(value={" +
+ "@RegContaineeNotDoc," +
+ "@RegContaineeNotDoc}," +
+ "y=3)"},
+ {BUG_ID + FS + "pkg1" + FS + "C.html",
+ "@ContainerValDoc" +
+ "(value={" +
+ "@ContaineeNotDoc," +
+ "@ContaineeNotDoc}," +
+ "x=1)"}
+ };
+
+ private static final String[][] NEGATED_TEST = {
+ {BUG_ID + FS + "pkg" + FS + "C.html",
+ "@RegContaineeDoc " +
+ "@RegContaineeDoc"},
+ {BUG_ID + FS + "pkg" + FS + "C.html",
+ "@RegContainerNotDoc" +
+ "(value={" +
+ "@RegContaineeNotDoc," +
+ "@RegContaineeNotDoc})"},
+
+ {BUG_ID + FS + "pkg1" + FS + "C.html",
+ "@ContaineeSynthDoc " +
+ "@ContaineeSynthDoc"},
+ {BUG_ID + FS + "pkg1" + FS + "C.html",
+ "@RegContainerValNotDoc" +
+ "(value={" +
+ "@RegContaineeDoc," +
+ "@RegContaineeDoc}," +
+ "y=4)"},
+ {BUG_ID + FS + "pkg1" + FS + "C.html",
+ "@ContainerValNotDoc" +
+ "(value={" +
+ "@ContaineeNotDoc," +
+ "@ContaineeNotDoc}," +
+ "x=2)"},
+ {BUG_ID + FS + "pkg1" + FS + "C.html",
+ "@ContainerSynthNotDoc(" +
+ "value=" +
+ "@ContaineeSynthDoc)"}
+ };
+
+ /**
+ * The entry point of the test.
+ * @param args the array of command line arguments.
+ */
+ public static void main(String[] args) {
+ TestRepeatedAnnotations tester = new TestRepeatedAnnotations();
+ run(tester, ARGS, TEST, NEGATED_TEST);
+ tester.printSummary();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getBugId() {
+ return BUG_ID;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getBugName() {
+ return getClass().getName();
+ }
+}
diff --git a/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/C.java b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/C.java
new file mode 100644
index 00000000000..aa8854980da
--- /dev/null
+++ b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/C.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2012, 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 pkg;
+
+@ContainerSynthDoc(value={@ContaineeSynthDoc,@ContaineeSynthDoc})
+@ContainerRegDoc(value={@ContaineeRegDoc,@ContaineeRegDoc})
+@RegContainerDoc(value={@RegContaineeNotDoc,@RegContaineeNotDoc})
+@ContainerRegNotDoc(value={@RegContaineeDoc,@RegContaineeDoc})
+@RegContainerNotDoc(value={@RegContaineeNotDoc,@RegContaineeNotDoc})
+@ContaineeSynthDoc @ContaineeSynthDoc @ContaineeSynthDoc
+public class C {
+
+ @ContainerSynthDoc(value={@ContaineeSynthDoc})
+ public void test1() {}
+
+ @ContaineeSynthDoc @ContaineeSynthDoc
+ public void test2() {}
+}
diff --git a/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/ContaineeRegDoc.java b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/ContaineeRegDoc.java
new file mode 100644
index 00000000000..9f3a6b9c0ca
--- /dev/null
+++ b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/ContaineeRegDoc.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2012, 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 pkg;
+
+import java.lang.annotation.*;
+
+/**
+ * This annotation is a documented annotation contained by ContainerRegDoc.
+ * It will be used to annotate Class C using a non-synthesized form.
+ *
+ * @author Bhavesh Patel
+ */
+@Documented
+public @interface ContaineeRegDoc {
+}
diff --git a/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/ContaineeSynthDoc.java b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/ContaineeSynthDoc.java
new file mode 100644
index 00000000000..8499ffb5e8b
--- /dev/null
+++ b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/ContaineeSynthDoc.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2012, 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 pkg;
+
+import java.lang.annotation.*;
+
+/**
+ * This annotation is a documented synthesized annotation contained by ContainerSynthDoc.
+ * It will be used to annotate Class C and a method in the class using a synthesized form.
+ *
+ * @author Bhavesh Patel
+ */
+@Documented
+@ContainedBy(ContainerSynthDoc.class)
+public @interface ContaineeSynthDoc {
+}
diff --git a/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/ContainerRegDoc.java b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/ContainerRegDoc.java
new file mode 100644
index 00000000000..fc52ac99358
--- /dev/null
+++ b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/ContainerRegDoc.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2012, 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 pkg;
+
+import java.lang.annotation.*;
+
+/**
+ * This annotation is a documented annotation container for ContaineeRegDoc.
+ * It will be used to annotate Class C using a non-synthesized form.
+ *
+ * @author Bhavesh Patel
+ */
+@Documented
+public @interface ContainerRegDoc {
+
+ ContaineeRegDoc[] value();
+}
diff --git a/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/ContainerRegNotDoc.java b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/ContainerRegNotDoc.java
new file mode 100644
index 00000000000..949349e640b
--- /dev/null
+++ b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/ContainerRegNotDoc.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2012, 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 pkg;
+
+import java.lang.annotation.*;
+
+/**
+ * This annotation is a non-documented annotation container for RegContaineeDoc.
+ * It will be used to annotate Class C using a non-synthesized form.
+ *
+ * @author Bhavesh Patel
+ */
+public @interface ContainerRegNotDoc {
+
+ RegContaineeDoc[] value();
+}
diff --git a/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/ContainerSynthDoc.java b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/ContainerSynthDoc.java
new file mode 100644
index 00000000000..950b923d357
--- /dev/null
+++ b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/ContainerSynthDoc.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2012, 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 pkg;
+
+import java.lang.annotation.*;
+
+/**
+ * This annotation is a documented synthesized annotation container for ContaineeSynthDoc.
+ * It will be used to annotate Class C and a method in the class using a synthesized form.
+ *
+ * @author Bhavesh Patel
+ */
+@Documented
+@ContainerFor(ContaineeSynthDoc.class)
+public @interface ContainerSynthDoc {
+
+ ContaineeSynthDoc[] value();
+}
diff --git a/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/D.java b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/D.java
new file mode 100644
index 00000000000..6ce15902419
--- /dev/null
+++ b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/D.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2012, 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 pkg;
+
+@RegDoc(x=1)
+public class D {
+
+ @RegArryDoc(y={1})
+ public void test1() {}
+
+ @RegArryDoc(y={1,2})
+ public void test2() {}
+
+ @NonSynthDocContainer(value={@RegArryDoc})
+ public void test3() {}
+}
diff --git a/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/NonSynthDocContainer.java b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/NonSynthDocContainer.java
new file mode 100644
index 00000000000..838063b38ba
--- /dev/null
+++ b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/NonSynthDocContainer.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2012, 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 pkg;
+
+import java.lang.annotation.*;
+
+/**
+ * This annotation is a documented annotation.
+ * It will be used to annotate methods in class D.
+ *
+ * @author Bhavesh Patel
+ */
+@Documented
+public @interface NonSynthDocContainer {
+
+ RegArryDoc[] value();
+}
diff --git a/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/RegArryDoc.java b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/RegArryDoc.java
new file mode 100644
index 00000000000..ec96fc07267
--- /dev/null
+++ b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/RegArryDoc.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2012, 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 pkg;
+
+import java.lang.annotation.*;
+
+/**
+ * This annotation is a documented annotation.
+ * It will be used to annotate methods in Class D.
+ *
+ * @author Bhavesh Patel
+ */
+@Documented
+public @interface RegArryDoc {
+
+ int[] y();
+}
diff --git a/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/RegContaineeDoc.java b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/RegContaineeDoc.java
new file mode 100644
index 00000000000..06ec88fbb15
--- /dev/null
+++ b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/RegContaineeDoc.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2012, 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 pkg;
+
+import java.lang.annotation.*;
+
+/**
+ * This annotation is a documented annotation contained by ContainerRegNotDoc.
+ * It will be used to annotate Class C using a non-synthesized form.
+ *
+ * @author Bhavesh Patel
+ */
+@Documented
+public @interface RegContaineeDoc {
+}
diff --git a/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/RegContaineeNotDoc.java b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/RegContaineeNotDoc.java
new file mode 100644
index 00000000000..0d96d1c5935
--- /dev/null
+++ b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/RegContaineeNotDoc.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2012, 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 pkg;
+
+import java.lang.annotation.*;
+
+/**
+ * This annotation is a non-documented annotation contained by RegContainerNotDoc
+ * and RegContainerDoc.
+ * It will be used to annotate Class C using a non-synthesized form.
+ *
+ * @author Bhavesh Patel
+ */
+public @interface RegContaineeNotDoc {
+}
diff --git a/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/RegContainerDoc.java b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/RegContainerDoc.java
new file mode 100644
index 00000000000..30b952e23da
--- /dev/null
+++ b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/RegContainerDoc.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2012, 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 pkg;
+
+import java.lang.annotation.*;
+
+/**
+ * This annotation is a documented annotation container for RegContainerDoc.
+ * It will be used to annotate Class C using a non-synthesized form.
+ *
+ * @author Bhavesh Patel
+ */
+@Documented
+public @interface RegContainerDoc {
+
+ RegContaineeNotDoc[] value();
+}
diff --git a/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/RegContainerNotDoc.java b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/RegContainerNotDoc.java
new file mode 100644
index 00000000000..c26fec48ed6
--- /dev/null
+++ b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/RegContainerNotDoc.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2012, 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 pkg;
+
+import java.lang.annotation.*;
+
+/**
+ * This annotation is a non-documented annotation container for RegContaineeNotDoc.
+ * It will be used to annotate Class C using a non-synthesized form.
+ *
+ * @author Bhavesh Patel
+ */
+public @interface RegContainerNotDoc {
+
+ RegContaineeNotDoc[] value();
+}
diff --git a/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/RegDoc.java b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/RegDoc.java
new file mode 100644
index 00000000000..289c35332f2
--- /dev/null
+++ b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg/RegDoc.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2012, 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 pkg;
+
+import java.lang.annotation.*;
+
+/**
+ * This annotation is a documented annotation.
+ * It will be used to annotate Class D.
+ *
+ * @author Bhavesh Patel
+ */
+@Documented
+public @interface RegDoc {
+
+ int x();
+}
diff --git a/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/C.java b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/C.java
new file mode 100644
index 00000000000..de10e08305b
--- /dev/null
+++ b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/C.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2012, 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 pkg1;
+
+@ContainerSynthNotDoc(value={@ContaineeSynthDoc,@ContaineeSynthDoc})
+@RegContainerValDoc(value={@RegContaineeNotDoc,@RegContaineeNotDoc},y=3)
+@ContainerValDoc(value={@ContaineeNotDoc,@ContaineeNotDoc},x=1)
+@RegContainerValNotDoc(value={@RegContaineeDoc,@RegContaineeDoc},y=4)
+@ContainerValNotDoc(value={@ContaineeNotDoc,@ContaineeNotDoc},x=2)
+public class C {
+
+ @ContainerSynthNotDoc(value={@ContaineeSynthDoc})
+ public void test1() {}
+
+ @ContaineeSynthDoc @ContaineeSynthDoc
+ public void test2() {}
+}
diff --git a/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/ContaineeNotDoc.java b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/ContaineeNotDoc.java
new file mode 100644
index 00000000000..73b1b06b845
--- /dev/null
+++ b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/ContaineeNotDoc.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2012, 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 pkg1;
+
+import java.lang.annotation.*;
+
+/**
+ * This annotation is a non-documented annotation contained by ContainerValNotDoc
+ * and ContainerValDoc.
+ * It will be used to annotate Class C using a non-synthesized form.
+ *
+ * @author Bhavesh Patel
+ */
+public @interface ContaineeNotDoc {
+}
diff --git a/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/ContaineeSynthDoc.java b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/ContaineeSynthDoc.java
new file mode 100644
index 00000000000..15722e3324e
--- /dev/null
+++ b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/ContaineeSynthDoc.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2012, 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 pkg1;
+
+import java.lang.annotation.*;
+
+/**
+ * This annotation is a documented synthesized annotation contained by ContainerSynthNotDoc.
+ * It will be used to annotate Class C and methods in the class using a synthesized form.
+ *
+ * @author Bhavesh Patel
+ */
+@Documented
+@ContainedBy(ContainerSynthNotDoc.class)
+public @interface ContaineeSynthDoc {
+}
diff --git a/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/ContainerSynthNotDoc.java b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/ContainerSynthNotDoc.java
new file mode 100644
index 00000000000..fbdfc272b18
--- /dev/null
+++ b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/ContainerSynthNotDoc.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2012, 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 pkg1;
+
+import java.lang.annotation.*;
+
+/**
+ * This annotation is a non-documented synthesized annotation container for ContaineeSynthDoc.
+ * It will be used to annotate Class C and methods in the class using a synthesized form.
+ *
+ * @author Bhavesh Patel
+ */
+@ContainerFor(ContaineeSynthDoc.class)
+public @interface ContainerSynthNotDoc {
+
+ ContaineeSynthDoc[] value();
+}
diff --git a/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/ContainerValDoc.java b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/ContainerValDoc.java
new file mode 100644
index 00000000000..0f39182228a
--- /dev/null
+++ b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/ContainerValDoc.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2012, 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 pkg1;
+
+import java.lang.annotation.*;
+
+/**
+ * This annotation is a documented annotation container for ContaineeNotDoc.
+ * It will be used to annotate Class C using a non-synthesized form.
+ *
+ * @author Bhavesh Patel
+ */
+@Documented
+public @interface ContainerValDoc {
+
+ ContaineeNotDoc[] value();
+
+ int x();
+}
diff --git a/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/ContainerValNotDoc.java b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/ContainerValNotDoc.java
new file mode 100644
index 00000000000..8e0b2b0b6d9
--- /dev/null
+++ b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/ContainerValNotDoc.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2012, 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 pkg1;
+
+import java.lang.annotation.*;
+
+/**
+ * This annotation is a non-documented annotation container for ContaineeNotDoc.
+ * It will be used to annotate Class C using a non-synthesized form.
+ *
+ * @author Bhavesh Patel
+ */
+public @interface ContainerValNotDoc {
+
+ ContaineeNotDoc[] value();
+
+ int x();
+}
diff --git a/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/RegContaineeDoc.java b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/RegContaineeDoc.java
new file mode 100644
index 00000000000..41d8db30d41
--- /dev/null
+++ b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/RegContaineeDoc.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2012, 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 pkg1;
+
+import java.lang.annotation.*;
+
+/**
+ * This annotation is a documented annotation contained by RegContainerValNotDoc.
+ * It will be used to annotate Class C using a non-synthesized form.
+ *
+ * @author Bhavesh Patel
+ */
+@Documented
+public @interface RegContaineeDoc {
+}
diff --git a/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/RegContaineeNotDoc.java b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/RegContaineeNotDoc.java
new file mode 100644
index 00000000000..ecda76794e4
--- /dev/null
+++ b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/RegContaineeNotDoc.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2012, 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 pkg1;
+
+import java.lang.annotation.*;
+
+/**
+ * This annotation is a non-documented annotation contained by RegContainerValDoc.
+ * It will be used to annotate Class C using a non-synthesized form.
+ *
+ * @author Bhavesh Patel
+ */
+public @interface RegContaineeNotDoc {
+}
diff --git a/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/RegContainerValDoc.java b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/RegContainerValDoc.java
new file mode 100644
index 00000000000..c9f212041de
--- /dev/null
+++ b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/RegContainerValDoc.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2012, 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 pkg1;
+
+import java.lang.annotation.*;
+
+/**
+ * This annotation is a documented annotation container for RegContaineeNotDoc.
+ * It will be used to annotate Class C using a non-synthesized form.
+ *
+ * @author Bhavesh Patel
+ */
+@Documented
+public @interface RegContainerValDoc {
+
+ RegContaineeNotDoc[] value();
+
+ int y();
+}
diff --git a/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/RegContainerValNotDoc.java b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/RegContainerValNotDoc.java
new file mode 100644
index 00000000000..ce67af79860
--- /dev/null
+++ b/langtools/test/com/sun/javadoc/testRepeatedAnnotations/pkg1/RegContainerValNotDoc.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2012, 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 pkg1;
+
+import java.lang.annotation.*;
+
+/**
+ * This annotation is a non-documented annotation container for RegContaineeDoc.
+ * It will be used to annotate Class C using a non-synthesized form.
+ *
+ * @author Bhavesh Patel
+ */
+public @interface RegContainerValNotDoc {
+
+ RegContaineeDoc[] value();
+
+ int y();
+}
From f4c27e0ba1f1d5adf09a9c50e0c61ef1f0adcccb Mon Sep 17 00:00:00 2001
From: Chris Hegarty
Date: Sat, 5 Jan 2013 17:06:54 +0000
Subject: [PATCH 20/53] 8005709: Add at since tags to new FJP
getCommonPoolParallelism and commonPool
Reviewed-by: dl
---
jdk/src/share/classes/java/util/concurrent/ForkJoinPool.java | 2 ++
1 file changed, 2 insertions(+)
diff --git a/jdk/src/share/classes/java/util/concurrent/ForkJoinPool.java b/jdk/src/share/classes/java/util/concurrent/ForkJoinPool.java
index a8940a3ddee..86bb3b59ebc 100644
--- a/jdk/src/share/classes/java/util/concurrent/ForkJoinPool.java
+++ b/jdk/src/share/classes/java/util/concurrent/ForkJoinPool.java
@@ -2611,6 +2611,7 @@ public class ForkJoinPool extends AbstractExecutorService {
* {@link #shutdown} or {@link #shutdownNow}.
*
* @return the common pool instance
+ * @since 1.8
*/
public static ForkJoinPool commonPool() {
// assert commonPool != null : "static init error";
@@ -2793,6 +2794,7 @@ public class ForkJoinPool extends AbstractExecutorService {
* Returns the targeted parallelism level of the common pool.
*
* @return the targeted parallelism level of the common pool
+ * @since 1.8
*/
public static int getCommonPoolParallelism() {
return commonPoolParallelism;
From 259f5d7cc829787e194aa4cf6c1c5f3dfcffc28a Mon Sep 17 00:00:00 2001
From: Jim Holmlund
Date: Mon, 7 Jan 2013 17:51:05 +0000
Subject: [PATCH 21/53] 8005647:
langtools/test/tools/javap/MethodParameters.java fails on windows
Fix javap to not output \r\r\n
Reviewed-by: jjg
---
.../share/classes/com/sun/tools/javap/ClassWriter.java | 9 ++++-----
langtools/test/tools/javac/MethodParameters.java | 1 +
langtools/test/tools/javap/MethodParameters.java | 1 +
3 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/langtools/src/share/classes/com/sun/tools/javap/ClassWriter.java b/langtools/src/share/classes/com/sun/tools/javap/ClassWriter.java
index 331a7b9e955..bc20ba3df90 100644
--- a/langtools/src/share/classes/com/sun/tools/javap/ClassWriter.java
+++ b/langtools/src/share/classes/com/sun/tools/javap/ClassWriter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2013, 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
@@ -206,7 +206,7 @@ public class ClassWriter extends BasicWriter {
println("minor version: " + cf.minor_version);
println("major version: " + cf.major_version);
if (!options.compat)
- writeList("flags: ", flags.getClassFlags(), NEWLINE);
+ writeList("flags: ", flags.getClassFlags(), "\n");
indent(-1);
constantWriter.writeConstantPool();
} else {
@@ -383,7 +383,7 @@ public class ClassWriter extends BasicWriter {
println("Signature: " + getValue(f.descriptor));
if (options.verbose && !options.compat)
- writeList("flags: ", flags.getFieldFlags(), NEWLINE);
+ writeList("flags: ", flags.getFieldFlags(), "\n");
if (options.showAllAttrs) {
for (Attribute attr: f.attributes)
@@ -480,7 +480,7 @@ public class ClassWriter extends BasicWriter {
}
if (options.verbose && !options.compat) {
- writeList("flags: ", flags.getMethodFlags(), NEWLINE);
+ writeList("flags: ", flags.getMethodFlags(), "\n");
}
Code_attribute code = null;
@@ -749,5 +749,4 @@ public class ClassWriter extends BasicWriter {
private int size;
private ConstantPool constant_pool;
private Method method;
- private static final String NEWLINE = System.getProperty("line.separator", "\n");
}
diff --git a/langtools/test/tools/javac/MethodParameters.java b/langtools/test/tools/javac/MethodParameters.java
index 74357fa9d00..82370e079c4 100644
--- a/langtools/test/tools/javac/MethodParameters.java
+++ b/langtools/test/tools/javac/MethodParameters.java
@@ -23,6 +23,7 @@
/*
* @test
+ * @bug 8004727
* @summary javac should generate method parameters correctly.
*/
// key: opt.arg.parameters
diff --git a/langtools/test/tools/javap/MethodParameters.java b/langtools/test/tools/javap/MethodParameters.java
index 500f7417d7a..3741bc442b9 100644
--- a/langtools/test/tools/javap/MethodParameters.java
+++ b/langtools/test/tools/javap/MethodParameters.java
@@ -23,6 +23,7 @@
/*
* @test
+ * @bug 8004727 8005647
* @summary javac should generate method parameters correctly.
*/
From 1381be8b23a373dfeb479102ba47b6c65ad30de0 Mon Sep 17 00:00:00 2001
From: David Dehaven
Date: Mon, 7 Jan 2013 09:58:48 -0800
Subject: [PATCH 22/53] 8004547: Extend JavaFX launcher support to allow full
JavaFX launch feature set
Reviewed-by: mchung, kcr, ksrini
---
.../classes/sun/launcher/LauncherHelper.java | 131 ++++++++-----
.../launcher/resources/launcher.properties | 3 +
jdk/test/tools/launcher/FXLauncherTest.java | 172 ++++++++++++++----
3 files changed, 231 insertions(+), 75 deletions(-)
diff --git a/jdk/src/share/classes/sun/launcher/LauncherHelper.java b/jdk/src/share/classes/sun/launcher/LauncherHelper.java
index 3b899bcca4d..2fc42a6962b 100644
--- a/jdk/src/share/classes/sun/launcher/LauncherHelper.java
+++ b/jdk/src/share/classes/sun/launcher/LauncherHelper.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2013, 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
@@ -409,6 +409,15 @@ public enum LauncherHelper {
if (mainValue == null) {
abort(null, "java.launcher.jar.error3", jarname);
}
+ /*
+ * Hand off to FXHelper if it detects a JavaFX application
+ * This must be done after ensuring a Main-Class entry
+ * exists to enforce compliance with the jar specification
+ */
+ if (mainAttrs.containsKey(
+ new Attributes.Name(FXHelper.JAVAFX_APPLICATION_MARKER))) {
+ return FXHelper.class.getName();
+ }
return mainValue.trim();
} catch (IOException ioe) {
abort(ioe, "java.launcher.jar.error1", jarname);
@@ -483,26 +492,23 @@ public enum LauncherHelper {
} catch (NoClassDefFoundError | ClassNotFoundException cnfe) {
abort(cnfe, "java.launcher.cls.error1", cn);
}
- // set to mainClass, FXHelper may return something else
+ // set to mainClass
appClass = mainClass;
- Method m = getMainMethod(mainClass);
- if (m != null) {
- // this will abort if main method has the wrong signature
- validateMainMethod(m);
- return mainClass;
+ /*
+ * Check if FXHelper can launch it using the FX launcher. In an FX app,
+ * the main class may or may not have a main method, so do this before
+ * validating the main class.
+ */
+ if (mainClass.equals(FXHelper.class) ||
+ FXHelper.doesExtendFXApplication(mainClass)) {
+ // Will abort() if there are problems with the FX runtime
+ FXHelper.setFXLaunchParameters(what, mode);
+ return FXHelper.class;
}
- // Check if FXHelper can launch it using the FX launcher
- Class> fxClass = FXHelper.getFXMainClass(mainClass);
- if (fxClass != null) {
- return fxClass;
- }
-
- // not an FX application either, abort with an error
- abort(null, "java.launcher.cls.error4", mainClass.getName(),
- FXHelper.JAVAFX_APPLICATION_CLASS_NAME);
- return null; // avoid compiler error...
+ validateMainClass(mainClass);
+ return mainClass;
}
/*
@@ -515,16 +521,18 @@ public enum LauncherHelper {
return appClass;
}
- // Check for main method or return null if not found
- static Method getMainMethod(Class> clazz) {
+ // Check the existence and signature of main and abort if incorrect
+ static void validateMainClass(Class> mainClass) {
+ Method mainMethod;
try {
- return clazz.getMethod("main", String[].class);
- } catch (NoSuchMethodException nsme) {}
- return null;
- }
+ mainMethod = mainClass.getMethod("main", String[].class);
+ } catch (NoSuchMethodException nsme) {
+ // invalid main or not FX application, abort with an error
+ abort(null, "java.launcher.cls.error4", mainClass.getName(),
+ FXHelper.JAVAFX_APPLICATION_CLASS_NAME);
+ return; // Avoid compiler issues
+ }
- // Check the signature of main and abort if it's incorrect
- static void validateMainMethod(Method mainMethod) {
/*
* getMethod (above) will choose the correct method, based
* on its name and parameter type, however, we still have to
@@ -644,41 +652,78 @@ public enum LauncherHelper {
}
static final class FXHelper {
+ // Marker entry in jar manifest that designates a JavaFX application jar
+ private static final String JAVAFX_APPLICATION_MARKER =
+ "JavaFX-Application-Class";
private static final String JAVAFX_APPLICATION_CLASS_NAME =
"javafx.application.Application";
private static final String JAVAFX_LAUNCHER_CLASS_NAME =
"com.sun.javafx.application.LauncherImpl";
+ /*
+ * The launch method used to invoke the JavaFX launcher. These must
+ * match the strings used in the launchApplication method.
+ *
+ * Command line JavaFX-App-Class Launch mode FX Launch mode
+ * java -cp fxapp.jar FXClass N/A LM_CLASS "LM_CLASS"
+ * java -cp somedir FXClass N/A LM_CLASS "LM_CLASS"
+ * java -jar fxapp.jar Present LM_JAR "LM_JAR"
+ * java -jar fxapp.jar Not Present LM_JAR "LM_JAR"
+ */
+ private static final String JAVAFX_LAUNCH_MODE_CLASS = "LM_CLASS";
+ private static final String JAVAFX_LAUNCH_MODE_JAR = "LM_JAR";
+
/*
* FX application launcher and launch method, so we can launch
* applications with no main method.
*/
+ private static String fxLaunchName = null;
+ private static String fxLaunchMode = null;
+
private static Class> fxLauncherClass = null;
private static Method fxLauncherMethod = null;
/*
- * We can assume that the class does NOT have a main method or it would
- * have been handled already. We do, however, need to check if the class
- * extends Application and the launcher is available and abort with an
- * error if it's not.
+ * Set the launch params according to what was passed to LauncherHelper
+ * so we can use the same launch mode for FX. Abort if there is any
+ * issue with loading the FX runtime or with the launcher method.
*/
- private static Class> getFXMainClass(Class> mainClass) {
- // Check if mainClass extends Application
- if (!doesExtendFXApplication(mainClass)) {
- return null;
- }
-
+ private static void setFXLaunchParameters(String what, int mode) {
// Check for the FX launcher classes
try {
fxLauncherClass = scloader.loadClass(JAVAFX_LAUNCHER_CLASS_NAME);
+ /*
+ * signature must be:
+ * public static void launchApplication(String launchName,
+ * String launchMode, String[] args);
+ */
fxLauncherMethod = fxLauncherClass.getMethod("launchApplication",
- Class.class, String[].class);
+ String.class, String.class, String[].class);
+
+ // verify launcher signature as we do when validating the main method
+ int mod = fxLauncherMethod.getModifiers();
+ if (!Modifier.isStatic(mod)) {
+ abort(null, "java.launcher.javafx.error1");
+ }
+ if (fxLauncherMethod.getReturnType() != java.lang.Void.TYPE) {
+ abort(null, "java.launcher.javafx.error1");
+ }
} catch (ClassNotFoundException | NoSuchMethodException ex) {
abort(ex, "java.launcher.cls.error5", ex);
}
- // That's all, return this class so we can launch later
- return FXHelper.class;
+ fxLaunchName = what;
+ switch (mode) {
+ case LM_CLASS:
+ fxLaunchMode = JAVAFX_LAUNCH_MODE_CLASS;
+ break;
+ case LM_JAR:
+ fxLaunchMode = JAVAFX_LAUNCH_MODE_JAR;
+ break;
+ default:
+ // should not have gotten this far...
+ throw new InternalError(mode + ": Unknown launch mode");
+ }
}
/*
@@ -696,11 +741,15 @@ public enum LauncherHelper {
return false;
}
- // preloader ?
public static void main(String... args) throws Exception {
+ if (fxLauncherMethod == null
+ || fxLaunchMode == null
+ || fxLaunchName == null) {
+ throw new RuntimeException("Invalid JavaFX launch parameters");
+ }
// launch appClass via fxLauncherMethod
- fxLauncherMethod.invoke(null, new Object[] {appClass, args});
+ fxLauncherMethod.invoke(null,
+ new Object[] {fxLaunchName, fxLaunchMode, args});
}
}
}
-
diff --git a/jdk/src/share/classes/sun/launcher/resources/launcher.properties b/jdk/src/share/classes/sun/launcher/resources/launcher.properties
index bfa05181784..8fbefacf8da 100644
--- a/jdk/src/share/classes/sun/launcher/resources/launcher.properties
+++ b/jdk/src/share/classes/sun/launcher/resources/launcher.properties
@@ -140,3 +140,6 @@ java.launcher.jar.error1=\
java.launcher.jar.error2=manifest not found in {0}
java.launcher.jar.error3=no main manifest attribute, in {0}
java.launcher.init.error=initialization error
+java.launcher.javafx.error1=\
+ Error: The JavaFX launchApplication method has the wrong signature, it\n\
+ must be declared static and return a value of type void
diff --git a/jdk/test/tools/launcher/FXLauncherTest.java b/jdk/test/tools/launcher/FXLauncherTest.java
index 9b58c0846c0..1ed251bad19 100644
--- a/jdk/test/tools/launcher/FXLauncherTest.java
+++ b/jdk/test/tools/launcher/FXLauncherTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 8001533
+ * @bug 8001533 8004547
* @summary Test launching FX application with java -jar
* Test uses main method and blank main method, a jfx app class and an incorrest
* jfx app class, a main-class for the manifest, a bogus one and none.
@@ -47,6 +47,8 @@ public class FXLauncherTest extends TestHelper {
/* standard main class can be used as java main for fx app class */
static final String StdMainClass = "helloworld.HelloWorld";
+ static final String ExtMainClass = "helloworld.ExtHello";
+ static final String NonFXMainClass = "helloworld.HelloJava";
static int testcount = 0;
/* a main method and a blank. */
@@ -107,9 +109,7 @@ public class FXLauncherTest extends TestHelper {
}
/*
- * Create class to extend fx java file for test application
- * TODO: make test to create java file and this extension of the java file
- * and jar them together an run app via this java class.
+ * Create class that extends HelloWorld instead of Application
*/
static void createExtJavaFile(String mainmethod) {
try {
@@ -125,16 +125,48 @@ public class FXLauncherTest extends TestHelper {
compile("-cp", ".", "-d", ".", mainClass + JAVA_FILE_EXT);
} catch (java.io.IOException ioe) {
ioe.printStackTrace();
- throw new RuntimeException("Failed creating HelloWorld.");
+ throw new RuntimeException("Failed creating ExtHello.");
+ }
+ }
+
+ /*
+ * Create non-JavaFX class for testing if jfxrt.jar is being loaded
+ * when it shouldn't be
+ */
+ static void createNonFXJavaFile() {
+ try {
+ String mainClass = "HelloJava";
+ List contents = new ArrayList<>();
+ contents.add("package helloworld;");
+ contents.add("public class HelloJava {");
+ contents.add(" public static void main(String[] args) {");
+ contents.add(" for(String aa : args)");
+ contents.add(" System.out.println(\"arg: \" + aa);" );
+ contents.add(" }");
+ contents.add("}");
+ // Create and compile java source.
+ MainJavaFile = new File(mainClass + JAVA_FILE_EXT);
+ createFile(MainJavaFile, contents);
+ compile("-cp", ".", "-d", ".", mainClass + JAVA_FILE_EXT);
+ } catch (java.io.IOException ioe) {
+ ioe.printStackTrace();
+ throw new RuntimeException("Failed creating HelloJava.");
}
}
// Create manifest for test fx application
- static List createManifestContents(String mainclassentry) {
+ static List createManifestContents(String mainClassEntry, String fxMainEntry) {
List mcontents = new ArrayList<>();
mcontents.add("Manifest-Version: 1.0");
mcontents.add("Created-By: FXLauncherTest");
- mcontents.add("Main-Class: " + mainclassentry);
+ if (mainClassEntry != null) {
+ mcontents.add("Main-Class: " + mainClassEntry);
+ System.out.println("Main-Class: " + mainClassEntry);
+ }
+ if (fxMainEntry != null) {
+ mcontents.add("JavaFX-Application-Class: " + fxMainEntry);
+ System.out.println("JavaFX-Application-Class: " + fxMainEntry);
+ }
return mcontents;
}
@@ -175,31 +207,41 @@ public class FXLauncherTest extends TestHelper {
/*
* Set Main-Class and iterate main_methods.
- * Try launching with both -jar and -cp methods.
+ * Try launching with both -jar and -cp methods, with and without FX main
+ * class manifest entry.
* All cases should run.
+ *
+ * See sun.launcher.LauncherHelper$FXHelper for more details on how JavaFX
+ * applications are launched.
*/
@Test
static void testBasicFXApp() throws Exception {
- testBasicFXApp(true);
- testBasicFXApp(false);
+ testBasicFXApp(true, false); // -cp, no JAC
+ testBasicFXApp(false, true); // -jar, with JAC
+ testBasicFXApp(false, false); // -jar, no JAC
}
- static void testBasicFXApp(boolean useCP) throws Exception {
+ static void testBasicFXApp(boolean useCP, boolean setFXMainClass) throws Exception {
String testname = "testBasicFXApp";
+ if (useCP) {
+ testname = testname.concat("_useCP");
+ }
+ String fxMC = StdMainClass;
+ if (!setFXMainClass) {
+ testname = testname.concat("_noJAC");
+ fxMC = null;
+ }
for (String mm : MAIN_METHODS) {
testcount++;
line();
- System.out.println("test# " + testcount +
- "- Main method: " + mm +
- "; MF main class: " + StdMainClass);
+ System.out.println("test# " + testcount + "- Main method: " + mm);
createJavaFile(mm);
- createFile(ManifestFile, createManifestContents(StdMainClass));
+ createFile(ManifestFile, createManifestContents(StdMainClass, fxMC));
createJar(FXtestJar, ManifestFile);
String sTestJar = FXtestJar.getAbsolutePath();
TestResult tr;
if (useCP) {
tr = doExec(javaCmd, "-cp", sTestJar, StdMainClass, APP_PARMS[0], APP_PARMS[1]);
- testname = testname.concat("_useCP");
} else {
tr = doExec(javaCmd, "-jar", sTestJar, APP_PARMS[0], APP_PARMS[1]);
}
@@ -224,26 +266,33 @@ public class FXLauncherTest extends TestHelper {
*/
@Test
static void testExtendFXApp() throws Exception {
- testExtendFXApp(true);
- testExtendFXApp(false);
+ testExtendFXApp(true, false); // -cp, no JAC
+ testExtendFXApp(false, true); // -jar, with JAC
+ testExtendFXApp(false, false); // -jar, no JAC
}
- static void testExtendFXApp(boolean useCP) throws Exception {
+ static void testExtendFXApp(boolean useCP, boolean setFXMainClass) throws Exception {
String testname = "testExtendFXApp";
+ if (useCP) {
+ testname = testname.concat("_useCP");
+ }
+ String fxMC = ExtMainClass;
+ if (!setFXMainClass) {
+ testname = testname.concat("_noJAC");
+ fxMC = null;
+ }
for (String mm : MAIN_METHODS) {
testcount++;
line();
- System.out.println("test# " + testcount +
- "- Main method: " + mm + "; MF main class: " + StdMainClass);
+ System.out.println("test# " + testcount + "- Main method: " + mm);
createJavaFile(mm);
createExtJavaFile(mm);
- createFile(ManifestFile, createManifestContents(StdMainClass));
+ createFile(ManifestFile, createManifestContents(ExtMainClass, fxMC));
createJar(FXtestJar, ManifestFile);
String sTestJar = FXtestJar.getAbsolutePath();
TestResult tr;
if (useCP) {
- tr = doExec(javaCmd, "-cp", sTestJar, StdMainClass, APP_PARMS[0], APP_PARMS[1]);
- testname = testname.concat("_useCP");
+ tr = doExec(javaCmd, "-cp", sTestJar, ExtMainClass, APP_PARMS[0], APP_PARMS[1]);
} else {
tr = doExec(javaCmd, "-jar", sTestJar, APP_PARMS[0], APP_PARMS[1]);
}
@@ -256,27 +305,82 @@ public class FXLauncherTest extends TestHelper {
}
}
}
- checkStatus(tr, testname, testcount, StdMainClass);
+ checkStatus(tr, testname, testcount, ExtMainClass);
}
}
+ /*
+ * Ensure we can NOT launch a FX app jar with no Main-Class manifest entry
+ */
+ @Test
+ static void testMissingMC() throws Exception {
+ String testname = "testMissingMC";
+ testcount++;
+ line();
+ System.out.println("test# " + testcount + ": abort on missing Main-Class");
+ createJavaFile(" "); // no main() needed
+ createFile(ManifestFile, createManifestContents(null, StdMainClass)); // No MC, but supply JAC
+ createJar(FXtestJar, ManifestFile);
+ String sTestJar = FXtestJar.getAbsolutePath();
+ TestResult tr = doExec(javaCmd, "-jar", sTestJar, APP_PARMS[0], APP_PARMS[1]);
+ tr.checkNegative(); // should abort if no Main-Class
+ if (tr.testStatus) {
+ if (!tr.contains("no main manifest attribute")) {
+ System.err.println("ERROR: launcher did not abort properly");
+ }
+ } else {
+ System.err.println("ERROR: jar executed with no Main-Class!");
+ }
+ checkStatus(tr, testname, testcount, StdMainClass);
+ }
+
/*
* test to ensure that we don't load any extraneous fx jars when
* launching a standard java application
+ * Test both -cp and -jar methods since they use different code paths.
+ * Neither case should cause jfxrt.jar to be loaded.
*/
@Test
- static void testExtraneousJars()throws Exception {
+ static void testExtraneousJars() throws Exception {
+ testExtraneousJars(true);
+ testExtraneousJars(false);
+ }
+
+ static void testExtraneousJars(boolean useCP) throws Exception {
String testname = "testExtraneousJars";
+ if (useCP) {
+ testname = testname.concat("_useCP");
+ }
testcount++;
line();
- System.out.println("test# " + testcount);
- TestResult tr = doExec(javacCmd, "-J-verbose:class", "-version");
- if (!tr.notContains("jfxrt.jar")) {
- System.out.println("testing for extraneous jfxrt jar");
- System.out.println(tr);
- throw new Exception("jfxrt.jar is being loaded by javac!!!");
+ System.out.println("test# " + testcount
+ + ": test for erroneous jfxrt.jar loading");
+ createNonFXJavaFile();
+ createFile(ManifestFile, createManifestContents(NonFXMainClass, null));
+ createJar(FXtestJar, ManifestFile);
+ String sTestJar = FXtestJar.getAbsolutePath();
+ TestResult tr;
+
+ if (useCP) {
+ tr = doExec(javaCmd, "-verbose:class", "-cp", sTestJar, NonFXMainClass, APP_PARMS[0], APP_PARMS[1]);
+ } else {
+ tr = doExec(javaCmd, "-verbose:class", "-jar", sTestJar, APP_PARMS[0], APP_PARMS[1]);
}
- checkStatus(tr, testname, testcount, StdMainClass);
+ tr.checkPositive();
+ if (tr.testStatus) {
+ if (!tr.notContains("jfxrt.jar")) {
+ System.out.println("testing for extraneous jfxrt jar");
+ System.out.println(tr);
+ throw new Exception("jfxrt.jar is being loaded, it should not be!");
+ }
+ for (String p : APP_PARMS) {
+ if (!tr.contains(p)) {
+ System.err.println("ERROR: Did not find "
+ + p + " in output!");
+ }
+ }
+ }
+ checkStatus(tr, testname, testcount, NonFXMainClass);
}
public static void main(String... args) throws Exception {
From 96c54994396b1f7ab483268e8c3b8d68a3d40d6b Mon Sep 17 00:00:00 2001
From: Valerie Peng
Date: Mon, 7 Jan 2013 11:11:54 -0800
Subject: [PATCH 23/53] 6996769: support AEAD cipher
Added implementation for GCM mode under AES cipher
Reviewed-by: weijun
---
.../com/sun/crypto/provider/AESCipher.java | 93 +++-
.../com/sun/crypto/provider/CipherCore.java | 445 +++++++++++-----
.../crypto/provider/CipherTextStealing.java | 14 +-
.../sun/crypto/provider/FeedbackCipher.java | 46 +-
.../sun/crypto/provider/GCMParameters.java | 146 +++++
.../classes/com/sun/crypto/provider/GCTR.java | 144 +++++
.../com/sun/crypto/provider/GHASH.java | 178 +++++++
.../crypto/provider/GaloisCounterMode.java | 501 ++++++++++++++++++
.../com/sun/crypto/provider/SunJCE.java | 17 +-
.../share/classes/javax/crypto/Cipher.java | 23 +-
.../javax/crypto/spec/GCMParameterSpec.java | 4 +-
.../provider/Cipher/AES/Test4512524.java | 17 +-
.../provider/Cipher/AES/Test4512704.java | 23 +-
.../provider/Cipher/AES/Test4517355.java | 44 +-
.../provider/Cipher/AES/Test4626070.java | 20 +-
.../Cipher/AES/TestGCMKeyAndIvCheck.java | 178 +++++++
.../provider/Cipher/AES/TestKATForGCM.java | 314 +++++++++++
jdk/test/javax/crypto/Cipher/GCMAPI.java | 8 +-
18 files changed, 2010 insertions(+), 205 deletions(-)
create mode 100644 jdk/src/share/classes/com/sun/crypto/provider/GCMParameters.java
create mode 100644 jdk/src/share/classes/com/sun/crypto/provider/GCTR.java
create mode 100644 jdk/src/share/classes/com/sun/crypto/provider/GHASH.java
create mode 100644 jdk/src/share/classes/com/sun/crypto/provider/GaloisCounterMode.java
create mode 100644 jdk/test/com/sun/crypto/provider/Cipher/AES/TestGCMKeyAndIvCheck.java
create mode 100644 jdk/test/com/sun/crypto/provider/Cipher/AES/TestKATForGCM.java
diff --git a/jdk/src/share/classes/com/sun/crypto/provider/AESCipher.java b/jdk/src/share/classes/com/sun/crypto/provider/AESCipher.java
index 0ae68957c43..32cb3e39d3d 100644
--- a/jdk/src/share/classes/com/sun/crypto/provider/AESCipher.java
+++ b/jdk/src/share/classes/com/sun/crypto/provider/AESCipher.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2013, 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
@@ -30,6 +30,7 @@ import java.security.spec.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import javax.crypto.BadPaddingException;
+import java.nio.ByteBuffer;
/**
* This class implements the AES algorithm in its various modes
@@ -127,6 +128,21 @@ abstract class AESCipher extends CipherSpi {
super(32, "CFB", "NOPADDING");
}
}
+ public static final class AES128_GCM_NoPadding extends OidImpl {
+ public AES128_GCM_NoPadding() {
+ super(16, "GCM", "NOPADDING");
+ }
+ }
+ public static final class AES192_GCM_NoPadding extends OidImpl {
+ public AES192_GCM_NoPadding() {
+ super(24, "GCM", "NOPADDING");
+ }
+ }
+ public static final class AES256_GCM_NoPadding extends OidImpl {
+ public AES256_GCM_NoPadding() {
+ super(32, "GCM", "NOPADDING");
+ }
+ }
// utility method used by AESCipher and AESWrapCipher
static final void checkKeySize(Key key, int fixedKeySize)
@@ -531,4 +547,79 @@ abstract class AESCipher extends CipherSpi {
return core.unwrap(wrappedKey, wrappedKeyAlgorithm,
wrappedKeyType);
}
+
+ /**
+ * Continues a multi-part update of the Additional Authentication
+ * Data (AAD), using a subset of the provided buffer.
+ *
+ * Calls to this method provide AAD to the cipher when operating in
+ * modes such as AEAD (GCM/CCM). If this cipher is operating in
+ * either GCM or CCM mode, all AAD must be supplied before beginning
+ * operations on the ciphertext (via the {@code update} and {@code
+ * doFinal} methods).
+ *
+ * @param src the buffer containing the AAD
+ * @param offset the offset in {@code src} where the AAD input starts
+ * @param len the number of AAD bytes
+ *
+ * @throws IllegalStateException if this cipher is in a wrong state
+ * (e.g., has not been initialized), does not accept AAD, or if
+ * operating in either GCM or CCM mode and one of the {@code update}
+ * methods has already been called for the active
+ * encryption/decryption operation
+ * @throws UnsupportedOperationException if this method
+ * has not been overridden by an implementation
+ *
+ * @since 1.8
+ */
+ @Override
+ protected void engineUpdateAAD(byte[] src, int offset, int len) {
+ core.updateAAD(src, offset, len);
+ }
+
+ /**
+ * Continues a multi-part update of the Additional Authentication
+ * Data (AAD).
+ *
+ * Calls to this method provide AAD to the cipher when operating in
+ * modes such as AEAD (GCM/CCM). If this cipher is operating in
+ * either GCM or CCM mode, all AAD must be supplied before beginning
+ * operations on the ciphertext (via the {@code update} and {@code
+ * doFinal} methods).
+ *
+ * All {@code src.remaining()} bytes starting at
+ * {@code src.position()} are processed.
+ * Upon return, the input buffer's position will be equal
+ * to its limit; its limit will not have changed.
+ *
+ * @param src the buffer containing the AAD
+ *
+ * @throws IllegalStateException if this cipher is in a wrong state
+ * (e.g., has not been initialized), does not accept AAD, or if
+ * operating in either GCM or CCM mode and one of the {@code update}
+ * methods has already been called for the active
+ * encryption/decryption operation
+ * @throws UnsupportedOperationException if this method
+ * has not been overridden by an implementation
+ *
+ * @since 1.8
+ */
+ @Override
+ protected void engineUpdateAAD(ByteBuffer src) {
+ if (src != null) {
+ int aadLen = src.limit() - src.position();
+ if (aadLen != 0) {
+ if (src.hasArray()) {
+ int aadOfs = src.arrayOffset() + src.position();
+ core.updateAAD(src.array(), aadOfs, aadLen);
+ src.position(src.limit());
+ } else {
+ byte[] aad = new byte[aadLen];
+ src.get(aad);
+ core.updateAAD(aad, 0, aadLen);
+ }
+ }
+ }
+ }
}
+
diff --git a/jdk/src/share/classes/com/sun/crypto/provider/CipherCore.java b/jdk/src/share/classes/com/sun/crypto/provider/CipherCore.java
index eb30879b0b9..5c47e7f1f72 100644
--- a/jdk/src/share/classes/com/sun/crypto/provider/CipherCore.java
+++ b/jdk/src/share/classes/com/sun/crypto/provider/CipherCore.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2013, 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
@@ -25,6 +25,7 @@
package com.sun.crypto.provider;
+import java.util.Arrays;
import java.util.Locale;
import java.security.*;
@@ -59,7 +60,7 @@ final class CipherCore {
private byte[] buffer = null;
/*
- * internal buffer
+ * block size of cipher in bytes
*/
private int blockSize = 0;
@@ -76,10 +77,12 @@ final class CipherCore {
/*
* minimum number of bytes in the buffer required for
* FeedbackCipher.encryptFinal()/decryptFinal() call.
- * update() must buffer this many bytes before before starting
+ * update() must buffer this many bytes before starting
* to encrypt/decrypt data.
- * currently, only CTS mode has a non-zero value due to its special
- * handling on the last two blocks (the last one may be incomplete).
+ * currently, only the following cases have non-zero values:
+ * 1) CTS mode - due to its special handling on the last two blocks
+ * (the last one may be incomplete).
+ * 2) GCM mode + decryption - due to its trailing tag bytes
*/
private int minBytes = 0;
@@ -121,6 +124,24 @@ final class CipherCore {
private static final int PCBC_MODE = 4;
private static final int CTR_MODE = 5;
private static final int CTS_MODE = 6;
+ private static final int GCM_MODE = 7;
+
+ /*
+ * variables used for performing the GCM (key+iv) uniqueness check.
+ * To use GCM mode safely, the cipher object must be re-initialized
+ * with a different combination of key + iv values for each
+ * encryption operation. However, checking all past key + iv values
+ * isn't feasible. Thus, we only do a per-instance check of the
+ * key + iv values used in previous encryption.
+ * For decryption operations, no checking is necessary.
+ * NOTE: this key+iv check have to be done inside CipherCore class
+ * since CipherCore class buffers potential tag bytes in GCM mode
+ * and may not call GaloisCounterMode when there isn't sufficient
+ * input to process.
+ */
+ private boolean requireReinit = false;
+ private byte[] lastEncKey = null;
+ private byte[] lastEncIv = null;
/**
* Creates an instance of CipherCore with default ECB mode and
@@ -149,7 +170,7 @@ final class CipherCore {
* @param mode the cipher mode
*
* @exception NoSuchAlgorithmException if the requested cipher mode does
- * not exist
+ * not exist for this cipher
*/
void setMode(String mode) throws NoSuchAlgorithmException {
if (mode == null)
@@ -165,30 +186,34 @@ final class CipherCore {
if (modeUpperCase.equals("CBC")) {
cipherMode = CBC_MODE;
cipher = new CipherBlockChaining(rawImpl);
- }
- else if (modeUpperCase.equals("CTS")) {
+ } else if (modeUpperCase.equals("CTS")) {
cipherMode = CTS_MODE;
cipher = new CipherTextStealing(rawImpl);
minBytes = blockSize+1;
padding = null;
- }
- else if (modeUpperCase.equals("CTR")) {
+ } else if (modeUpperCase.equals("CTR")) {
cipherMode = CTR_MODE;
cipher = new CounterMode(rawImpl);
unitBytes = 1;
padding = null;
- }
- else if (modeUpperCase.startsWith("CFB")) {
+ } else if (modeUpperCase.startsWith("GCM")) {
+ // can only be used for block ciphers w/ 128-bit block size
+ if (blockSize != 16) {
+ throw new NoSuchAlgorithmException
+ ("GCM mode can only be used for AES cipher");
+ }
+ cipherMode = GCM_MODE;
+ cipher = new GaloisCounterMode(rawImpl);
+ padding = null;
+ } else if (modeUpperCase.startsWith("CFB")) {
cipherMode = CFB_MODE;
unitBytes = getNumOfUnit(mode, "CFB".length(), blockSize);
cipher = new CipherFeedback(rawImpl, unitBytes);
- }
- else if (modeUpperCase.startsWith("OFB")) {
+ } else if (modeUpperCase.startsWith("OFB")) {
cipherMode = OFB_MODE;
unitBytes = getNumOfUnit(mode, "OFB".length(), blockSize);
cipher = new OutputFeedback(rawImpl, unitBytes);
- }
- else if (modeUpperCase.equals("PCBC")) {
+ } else if (modeUpperCase.equals("PCBC")) {
cipherMode = PCBC_MODE;
cipher = new PCBC(rawImpl);
}
@@ -219,6 +244,7 @@ final class CipherCore {
return result;
}
+
/**
* Sets the padding mechanism of this cipher.
*
@@ -242,11 +268,27 @@ final class CipherCore {
+ " not implemented");
}
if ((padding != null) &&
- ((cipherMode == CTR_MODE) || (cipherMode == CTS_MODE))) {
+ ((cipherMode == CTR_MODE) || (cipherMode == CTS_MODE)
+ || (cipherMode == GCM_MODE))) {
padding = null;
- throw new NoSuchPaddingException
- ((cipherMode == CTR_MODE? "CTR":"CTS") +
- " mode must be used with NoPadding");
+ String modeStr = null;
+ switch (cipherMode) {
+ case CTR_MODE:
+ modeStr = "CTR";
+ break;
+ case GCM_MODE:
+ modeStr = "GCM";
+ break;
+ case CTS_MODE:
+ modeStr = "CTS";
+ break;
+ default:
+ // should never happen
+ }
+ if (modeStr != null) {
+ throw new NoSuchPaddingException
+ (modeStr + " mode must be used with NoPadding");
+ }
}
}
@@ -257,7 +299,7 @@ final class CipherCore {
* inputLen (in bytes).
*
*
This call takes into account any unprocessed (buffered) data from a
- * previous update call, and padding.
+ * previous update call, padding, and AEAD tagging.
*
*
The actual output length of the next update or
* doFinal call may be smaller than the length returned by
@@ -270,23 +312,60 @@ final class CipherCore {
int getOutputSize(int inputLen) {
int totalLen = buffered + inputLen;
- if (padding == null)
- return totalLen;
+ // GCM: this call may be for either update() or doFinal(), so have to
+ // return the larger value of both
+ // Encryption: based on doFinal value: inputLen + tag
+ // Decryption: based on update value: inputLen
+ if (!decrypting && (cipherMode == GCM_MODE)) {
+ return (totalLen + ((GaloisCounterMode) cipher).getTagLen());
+ }
- if (decrypting)
+ if (padding == null) {
return totalLen;
+ }
+
+ if (decrypting) {
+ return totalLen;
+ }
if (unitBytes != blockSize) {
- if (totalLen < diffBlocksize)
+ if (totalLen < diffBlocksize) {
return diffBlocksize;
- else
+ } else {
return (totalLen + blockSize -
((totalLen - diffBlocksize) % blockSize));
+ }
} else {
return totalLen + padding.padLength(totalLen);
}
}
+ private int getOutputSizeByOperation(int inputLen, boolean isDoFinal) {
+ int totalLen = 0;
+ switch (cipherMode) {
+ case GCM_MODE:
+ totalLen = buffered + inputLen;
+ if (isDoFinal) {
+ int tagLen = ((GaloisCounterMode) cipher).getTagLen();
+ if (decrypting) {
+ // need to get the actual value from cipher??
+ // deduct tagLen
+ totalLen -= tagLen;
+ } else {
+ totalLen += tagLen;
+ }
+ }
+ if (totalLen < 0) {
+ totalLen = 0;
+ }
+ break;
+ default:
+ totalLen = getOutputSize(inputLen);
+ break;
+ }
+ return totalLen;
+ }
+
/**
* Returns the initialization vector (IV) in a new buffer.
*
@@ -318,34 +397,49 @@ final class CipherCore {
* does not use any parameters.
*/
AlgorithmParameters getParameters(String algName) {
+ if (cipherMode == ECB_MODE) {
+ return null;
+ }
AlgorithmParameters params = null;
- if (cipherMode == ECB_MODE) return null;
+ AlgorithmParameterSpec spec;
byte[] iv = getIV();
- if (iv != null) {
- AlgorithmParameterSpec ivSpec;
- if (algName.equals("RC2")) {
- RC2Crypt rawImpl = (RC2Crypt) cipher.getEmbeddedCipher();
- ivSpec = new RC2ParameterSpec(rawImpl.getEffectiveKeyBits(),
- iv);
+ if (iv == null) {
+ // generate spec using default value
+ if (cipherMode == GCM_MODE) {
+ iv = new byte[GaloisCounterMode.DEFAULT_IV_LEN];
} else {
- ivSpec = new IvParameterSpec(iv);
- }
- try {
- params = AlgorithmParameters.getInstance(algName, "SunJCE");
- } catch (NoSuchAlgorithmException nsae) {
- // should never happen
- throw new RuntimeException("Cannot find " + algName +
- " AlgorithmParameters implementation in SunJCE provider");
- } catch (NoSuchProviderException nspe) {
- // should never happen
- throw new RuntimeException("Cannot find SunJCE provider");
- }
- try {
- params.init(ivSpec);
- } catch (InvalidParameterSpecException ipse) {
- // should never happen
- throw new RuntimeException("IvParameterSpec not supported");
+ iv = new byte[blockSize];
}
+ SunJCE.RANDOM.nextBytes(iv);
+ }
+ if (cipherMode == GCM_MODE) {
+ algName = "GCM";
+ spec = new GCMParameterSpec
+ (((GaloisCounterMode) cipher).getTagLen()*8, iv);
+ } else {
+ if (algName.equals("RC2")) {
+ RC2Crypt rawImpl = (RC2Crypt) cipher.getEmbeddedCipher();
+ spec = new RC2ParameterSpec
+ (rawImpl.getEffectiveKeyBits(), iv);
+ } else {
+ spec = new IvParameterSpec(iv);
+ }
+ }
+ try {
+ params = AlgorithmParameters.getInstance(algName, "SunJCE");
+ } catch (NoSuchAlgorithmException nsae) {
+ // should never happen
+ throw new RuntimeException("Cannot find " + algName +
+ " AlgorithmParameters implementation in SunJCE provider");
+ } catch (NoSuchProviderException nspe) {
+ // should never happen
+ throw new RuntimeException("Cannot find SunJCE provider");
+ }
+ try {
+ params.init(spec);
+ } catch (InvalidParameterSpecException ipse) {
+ // should never happen
+ throw new RuntimeException(spec.getClass() + " not supported");
}
return params;
}
@@ -420,44 +514,63 @@ final class CipherCore {
|| (opmode == Cipher.UNWRAP_MODE);
byte[] keyBytes = getKeyBytes(key);
-
- byte[] ivBytes;
- if (params == null) {
- ivBytes = null;
- } else if (params instanceof IvParameterSpec) {
- ivBytes = ((IvParameterSpec)params).getIV();
- if ((ivBytes == null) || (ivBytes.length != blockSize)) {
- throw new InvalidAlgorithmParameterException
- ("Wrong IV length: must be " + blockSize +
- " bytes long");
+ int tagLen = -1;
+ byte[] ivBytes = null;
+ if (params != null) {
+ if (cipherMode == GCM_MODE) {
+ if (params instanceof GCMParameterSpec) {
+ tagLen = ((GCMParameterSpec)params).getTLen();
+ if (tagLen < 96 || tagLen > 128 || ((tagLen & 0x07) != 0)) {
+ throw new InvalidAlgorithmParameterException
+ ("Unsupported TLen value; must be one of " +
+ "{128, 120, 112, 104, 96}");
+ }
+ tagLen = tagLen >> 3;
+ ivBytes = ((GCMParameterSpec)params).getIV();
+ } else {
+ throw new InvalidAlgorithmParameterException
+ ("Unsupported parameter: " + params);
+ }
+ } else {
+ if (params instanceof IvParameterSpec) {
+ ivBytes = ((IvParameterSpec)params).getIV();
+ if ((ivBytes == null) || (ivBytes.length != blockSize)) {
+ throw new InvalidAlgorithmParameterException
+ ("Wrong IV length: must be " + blockSize +
+ " bytes long");
+ }
+ } else if (params instanceof RC2ParameterSpec) {
+ ivBytes = ((RC2ParameterSpec)params).getIV();
+ if ((ivBytes != null) && (ivBytes.length != blockSize)) {
+ throw new InvalidAlgorithmParameterException
+ ("Wrong IV length: must be " + blockSize +
+ " bytes long");
+ }
+ } else {
+ throw new InvalidAlgorithmParameterException
+ ("Unsupported parameter: " + params);
+ }
}
- } else if (params instanceof RC2ParameterSpec) {
- ivBytes = ((RC2ParameterSpec)params).getIV();
- if ((ivBytes != null) && (ivBytes.length != blockSize)) {
- throw new InvalidAlgorithmParameterException
- ("Wrong IV length: must be " + blockSize +
- " bytes long");
- }
- } else {
- throw new InvalidAlgorithmParameterException("Wrong parameter "
- + "type: IV "
- + "expected");
}
-
if (cipherMode == ECB_MODE) {
if (ivBytes != null) {
throw new InvalidAlgorithmParameterException
("ECB mode cannot use IV");
}
- } else if (ivBytes == null) {
+ } else if (ivBytes == null) {
if (decrypting) {
throw new InvalidAlgorithmParameterException("Parameters "
+ "missing");
}
+
if (random == null) {
random = SunJCE.RANDOM;
}
- ivBytes = new byte[blockSize];
+ if (cipherMode == GCM_MODE) {
+ ivBytes = new byte[GaloisCounterMode.DEFAULT_IV_LEN];
+ } else {
+ ivBytes = new byte[blockSize];
+ }
random.nextBytes(ivBytes);
}
@@ -466,23 +579,57 @@ final class CipherCore {
String algorithm = key.getAlgorithm();
- cipher.init(decrypting, algorithm, keyBytes, ivBytes);
+ // GCM mode needs additional handling
+ if (cipherMode == GCM_MODE) {
+ if(tagLen == -1) {
+ tagLen = GaloisCounterMode.DEFAULT_TAG_LEN;
+ }
+ if (decrypting) {
+ minBytes = tagLen;
+ } else {
+ // check key+iv for encryption in GCM mode
+ requireReinit =
+ Arrays.equals(ivBytes, lastEncIv) &&
+ Arrays.equals(keyBytes, lastEncKey);
+ if (requireReinit) {
+ throw new InvalidAlgorithmParameterException
+ ("Cannot reuse iv for GCM encryption");
+ }
+ lastEncIv = ivBytes;
+ lastEncKey = keyBytes;
+ }
+ ((GaloisCounterMode) cipher).init
+ (decrypting, algorithm, keyBytes, ivBytes, tagLen);
+ } else {
+ cipher.init(decrypting, algorithm, keyBytes, ivBytes);
+ }
+ // skip checking key+iv from now on until after doFinal()
+ requireReinit = false;
}
void init(int opmode, Key key, AlgorithmParameters params,
SecureRandom random)
throws InvalidKeyException, InvalidAlgorithmParameterException {
- IvParameterSpec ivSpec = null;
+ AlgorithmParameterSpec spec = null;
+ String paramType = null;
if (params != null) {
try {
- ivSpec = params.getParameterSpec(IvParameterSpec.class);
+ if (cipherMode == GCM_MODE) {
+ paramType = "GCM";
+ spec = params.getParameterSpec(GCMParameterSpec.class);
+ } else {
+ // NOTE: RC2 parameters are always handled through
+ // init(..., AlgorithmParameterSpec,...) method, so
+ // we can assume IvParameterSpec type here.
+ paramType = "IV";
+ spec = params.getParameterSpec(IvParameterSpec.class);
+ }
} catch (InvalidParameterSpecException ipse) {
- throw new InvalidAlgorithmParameterException("Wrong parameter "
- + "type: IV "
- + "expected");
+ throw new InvalidAlgorithmParameterException
+ ("Wrong parameter type: " + paramType + " expected");
}
}
- init(opmode, key, ivSpec, random);
+ init(opmode, key, spec, random);
}
/**
@@ -504,6 +651,7 @@ final class CipherCore {
return keyBytes;
}
+
/**
* Continues a multiple-part encryption or decryption operation
* (depending on how this cipher was initialized), processing another data
@@ -524,22 +672,25 @@ final class CipherCore {
* (e.g., has not been initialized)
*/
byte[] update(byte[] input, int inputOffset, int inputLen) {
+ if (requireReinit) {
+ throw new IllegalStateException
+ ("Must use either different key or iv for GCM encryption");
+ }
+
byte[] output = null;
- byte[] out = null;
try {
- output = new byte[getOutputSize(inputLen)];
+ output = new byte[getOutputSizeByOperation(inputLen, false)];
int len = update(input, inputOffset, inputLen, output,
0);
if (len == output.length) {
- out = output;
+ return output;
} else {
- out = new byte[len];
- System.arraycopy(output, 0, out, 0, len);
+ return Arrays.copyOf(output, len);
}
} catch (ShortBufferException e) {
- // never thrown
+ // should never happen
+ throw new ProviderException("Unexpected exception", e);
}
- return out;
}
/**
@@ -567,6 +718,11 @@ final class CipherCore {
*/
int update(byte[] input, int inputOffset, int inputLen, byte[] output,
int outputOffset) throws ShortBufferException {
+ if (requireReinit) {
+ throw new IllegalStateException
+ ("Must use either different key or iv for GCM encryption");
+ }
+
// figure out how much can be sent to crypto function
int len = buffered + inputLen - minBytes;
if (padding != null && decrypting) {
@@ -582,6 +738,7 @@ final class CipherCore {
+ "(at least) " + len
+ " bytes long");
}
+
if (len != 0) {
// there is some work to do
byte[] in = new byte[len];
@@ -600,7 +757,6 @@ final class CipherCore {
System.arraycopy(input, inputOffset, in,
bufferedConsumed, inputConsumed);
}
-
if (decrypting) {
cipher.decrypt(in, 0, len, output, outputOffset);
} else {
@@ -611,11 +767,12 @@ final class CipherCore {
// the total input length a multiple of blocksize when
// padding is applied
if (unitBytes != blockSize) {
- if (len < diffBlocksize)
+ if (len < diffBlocksize) {
diffBlocksize -= len;
- else
+ } else {
diffBlocksize = blockSize -
((len - diffBlocksize) % blockSize);
+ }
}
inputLen -= inputConsumed;
@@ -669,21 +826,18 @@ final class CipherCore {
byte[] doFinal(byte[] input, int inputOffset, int inputLen)
throws IllegalBlockSizeException, BadPaddingException {
byte[] output = null;
- byte[] out = null;
try {
- output = new byte[getOutputSize(inputLen)];
+ output = new byte[getOutputSizeByOperation(inputLen, true)];
int len = doFinal(input, inputOffset, inputLen, output, 0);
if (len < output.length) {
- out = new byte[len];
- if (len != 0)
- System.arraycopy(output, 0, out, 0, len);
+ return Arrays.copyOf(output, len);
} else {
- out = output;
+ return output;
}
} catch (ShortBufferException e) {
// never thrown
+ throw new ProviderException("Unexpected exception", e);
}
- return out;
}
/**
@@ -726,6 +880,10 @@ final class CipherCore {
int outputOffset)
throws IllegalBlockSizeException, ShortBufferException,
BadPaddingException {
+ if (requireReinit) {
+ throw new IllegalStateException
+ ("Must use either different key or iv for GCM encryption");
+ }
// calculate the total input length
int totalLen = buffered + inputLen;
@@ -752,8 +910,9 @@ final class CipherCore {
}
// if encrypting and padding not null, add padding
- if (!decrypting && padding != null)
+ if (!decrypting && padding != null) {
paddedLen += paddingLen;
+ }
// check output buffer capacity.
// if we are decrypting with padding applied, we can perform this
@@ -763,8 +922,8 @@ final class CipherCore {
throw new ShortBufferException("Output buffer is null");
}
int outputCapacity = output.length - outputOffset;
- if (((!decrypting) || (padding == null)) &&
- (outputCapacity < paddedLen) ||
+
+ if (((!decrypting) && (outputCapacity < paddedLen)) ||
(decrypting && (outputCapacity < (paddedLen - blockSize)))) {
throw new ShortBufferException("Output buffer too short: "
+ outputCapacity + " bytes given, "
@@ -812,6 +971,7 @@ final class CipherCore {
}
totalLen = padStart;
}
+
if ((output.length - outputOffset) < totalLen) {
// restore so users can retry with a larger buffer
cipher.restore();
@@ -824,8 +984,13 @@ final class CipherCore {
output[outputOffset + i] = outWithPadding[i];
}
} else { // encrypting
- totalLen = finalNoPadding(finalBuf, finalOffset, output,
- outputOffset, paddedLen);
+ try {
+ totalLen = finalNoPadding(finalBuf, finalOffset, output,
+ outputOffset, paddedLen);
+ } finally {
+ // reset after doFinal() for GCM encryption
+ requireReinit = (cipherMode == GCM_MODE);
+ }
}
buffered = 0;
@@ -836,33 +1001,33 @@ final class CipherCore {
return totalLen;
}
- private int finalNoPadding(byte[] in, int inOff, byte[] out, int outOff,
+ private int finalNoPadding(byte[] in, int inOfs, byte[] out, int outOfs,
int len)
- throws IllegalBlockSizeException
- {
- if (in == null || len == 0)
+ throws IllegalBlockSizeException, AEADBadTagException {
+
+ if ((cipherMode != GCM_MODE) && (in == null || len == 0)) {
return 0;
-
- if ((cipherMode != CFB_MODE) && (cipherMode != OFB_MODE)
- && ((len % unitBytes) != 0) && (cipherMode != CTS_MODE)) {
- if (padding != null) {
- throw new IllegalBlockSizeException
- ("Input length (with padding) not multiple of " +
- unitBytes + " bytes");
- } else {
- throw new IllegalBlockSizeException
- ("Input length not multiple of " + unitBytes
- + " bytes");
- }
}
-
+ if ((cipherMode != CFB_MODE) && (cipherMode != OFB_MODE) &&
+ (cipherMode != GCM_MODE) &&
+ ((len % unitBytes) != 0) && (cipherMode != CTS_MODE)) {
+ if (padding != null) {
+ throw new IllegalBlockSizeException
+ ("Input length (with padding) not multiple of " +
+ unitBytes + " bytes");
+ } else {
+ throw new IllegalBlockSizeException
+ ("Input length not multiple of " + unitBytes
+ + " bytes");
+ }
+ }
+ int outLen = 0;
if (decrypting) {
- cipher.decryptFinal(in, inOff, len, out, outOff);
+ outLen = cipher.decryptFinal(in, inOfs, len, out, outOfs);
} else {
- cipher.encryptFinal(in, inOff, len, out, outOff);
+ outLen = cipher.encryptFinal(in, inOfs, len, out, outOfs);
}
-
- return len;
+ return outLen;
}
// Note: Wrap() and Unwrap() are the same in
@@ -939,4 +1104,36 @@ final class CipherCore {
return ConstructKeys.constructKey(encodedKey, wrappedKeyAlgorithm,
wrappedKeyType);
}
+
+ /**
+ * Continues a multi-part update of the Additional Authentication
+ * Data (AAD), using a subset of the provided buffer.
+ *
+ * Calls to this method provide AAD to the cipher when operating in
+ * modes such as AEAD (GCM/CCM). If this cipher is operating in
+ * either GCM or CCM mode, all AAD must be supplied before beginning
+ * operations on the ciphertext (via the {@code update} and {@code
+ * doFinal} methods).
+ *
+ * @param src the buffer containing the AAD
+ * @param offset the offset in {@code src} where the AAD input starts
+ * @param len the number of AAD bytes
+ *
+ * @throws IllegalStateException if this cipher is in a wrong state
+ * (e.g., has not been initialized), does not accept AAD, or if
+ * operating in either GCM or CCM mode and one of the {@code update}
+ * methods has already been called for the active
+ * encryption/decryption operation
+ * @throws UnsupportedOperationException if this method
+ * has not been overridden by an implementation
+ *
+ * @since 1.8
+ */
+ void updateAAD(byte[] src, int offset, int len) {
+ if (requireReinit) {
+ throw new IllegalStateException
+ ("Must use either different key or iv for GCM encryption");
+ }
+ cipher.updateAAD(src, offset, len);
+ }
}
diff --git a/jdk/src/share/classes/com/sun/crypto/provider/CipherTextStealing.java b/jdk/src/share/classes/com/sun/crypto/provider/CipherTextStealing.java
index ef77d3e5360..630f8707fde 100644
--- a/jdk/src/share/classes/com/sun/crypto/provider/CipherTextStealing.java
+++ b/jdk/src/share/classes/com/sun/crypto/provider/CipherTextStealing.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2013, 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
@@ -83,9 +83,10 @@ final class CipherTextStealing extends CipherBlockChaining {
* @param plainLen the length of the input data
* @param cipher the buffer for the result
* @param cipherOffset the offset in cipher
+ * @return the number of bytes placed into cipher
*/
- void encryptFinal(byte[] plain, int plainOffset, int plainLen,
- byte[] cipher, int cipherOffset)
+ int encryptFinal(byte[] plain, int plainOffset, int plainLen,
+ byte[] cipher, int cipherOffset)
throws IllegalBlockSizeException {
if (plainLen < blockSize) {
@@ -134,6 +135,7 @@ final class CipherTextStealing extends CipherBlockChaining {
embeddedCipher.encryptBlock(tmp2, 0, cipher, cipherOffset);
}
}
+ return plainLen;
}
/**
@@ -158,9 +160,10 @@ final class CipherTextStealing extends CipherBlockChaining {
* @param cipherLen the length of the input data
* @param plain the buffer for the result
* @param plainOffset the offset in plain
+ * @return the number of bytes placed into plain
*/
- void decryptFinal(byte[] cipher, int cipherOffset, int cipherLen,
- byte[] plain, int plainOffset)
+ int decryptFinal(byte[] cipher, int cipherOffset, int cipherLen,
+ byte[] plain, int plainOffset)
throws IllegalBlockSizeException {
if (cipherLen < blockSize) {
throw new IllegalBlockSizeException("input is too short!");
@@ -211,5 +214,6 @@ final class CipherTextStealing extends CipherBlockChaining {
}
}
}
+ return cipherLen;
}
}
diff --git a/jdk/src/share/classes/com/sun/crypto/provider/FeedbackCipher.java b/jdk/src/share/classes/com/sun/crypto/provider/FeedbackCipher.java
index 34b83ae928b..c27332457f3 100644
--- a/jdk/src/share/classes/com/sun/crypto/provider/FeedbackCipher.java
+++ b/jdk/src/share/classes/com/sun/crypto/provider/FeedbackCipher.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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
@@ -26,7 +26,7 @@
package com.sun.crypto.provider;
import java.security.InvalidKeyException;
-import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.*;
/**
* This class represents a block cipher in one of its modes. It wraps
@@ -150,11 +150,13 @@ abstract class FeedbackCipher {
* @param plainLen the length of the input data
* @param cipher the buffer for the encryption result
* @param cipherOffset the offset in cipher
+ * @return the number of bytes placed into cipher
*/
- void encryptFinal(byte[] plain, int plainOffset, int plainLen,
- byte[] cipher, int cipherOffset)
+ int encryptFinal(byte[] plain, int plainOffset, int plainLen,
+ byte[] cipher, int cipherOffset)
throws IllegalBlockSizeException {
encrypt(plain, plainOffset, plainLen, cipher, cipherOffset);
+ return plainLen;
}
/**
* Performs decryption operation.
@@ -190,10 +192,40 @@ abstract class FeedbackCipher {
* @param cipherLen the length of the input data
* @param plain the buffer for the decryption result
* @param plainOffset the offset in plain
+ * @return the number of bytes placed into plain
*/
- void decryptFinal(byte[] cipher, int cipherOffset, int cipherLen,
- byte[] plain, int plainOffset)
- throws IllegalBlockSizeException {
+ int decryptFinal(byte[] cipher, int cipherOffset, int cipherLen,
+ byte[] plain, int plainOffset)
+ throws IllegalBlockSizeException, AEADBadTagException {
decrypt(cipher, cipherOffset, cipherLen, plain, plainOffset);
+ return cipherLen;
}
+
+ /**
+ * Continues a multi-part update of the Additional Authentication
+ * Data (AAD), using a subset of the provided buffer. If this
+ * cipher is operating in either GCM or CCM mode, all AAD must be
+ * supplied before beginning operations on the ciphertext (via the
+ * {@code update} and {@code doFinal} methods).
+ *
+ * NOTE: Given most modes do not accept AAD, default impl for this
+ * method throws IllegalStateException.
+ *
+ * @param src the buffer containing the AAD
+ * @param offset the offset in {@code src} where the AAD input starts
+ * @param len the number of AAD bytes
+ *
+ * @throws IllegalStateException if this cipher is in a wrong state
+ * (e.g., has not been initialized), does not accept AAD, or if
+ * operating in either GCM or CCM mode and one of the {@code update}
+ * methods has already been called for the active
+ * encryption/decryption operation
+ * @throws UnsupportedOperationException if this method
+ * has not been overridden by an implementation
+ *
+ * @since 1.8
+ */
+ void updateAAD(byte[] src, int offset, int len) {
+ throw new IllegalStateException("No AAD accepted");
+ }
}
diff --git a/jdk/src/share/classes/com/sun/crypto/provider/GCMParameters.java b/jdk/src/share/classes/com/sun/crypto/provider/GCMParameters.java
new file mode 100644
index 00000000000..4ae729204a6
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/crypto/provider/GCMParameters.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2013, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 com.sun.crypto.provider;
+
+import java.io.IOException;
+import java.security.AlgorithmParametersSpi;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import javax.crypto.spec.GCMParameterSpec;
+import sun.misc.HexDumpEncoder;
+import sun.security.util.*;
+
+/**
+ * This class implements the parameter set used with
+ * GCM encryption, which is defined in RFC 5084 as follows:
+ *
+ *
+ * GCMParameters ::= SEQUENCE {
+ * aes-iv OCTET STRING, -- recommended size is 12 octets
+ * aes-tLen AES-GCM-ICVlen DEFAULT 12 }
+ *
+ * AES-GCM-ICVlen ::= INTEGER (12 | 13 | 14 | 15 | 16)
+ *
+ *
+ *
+ * @author Valerie Peng
+ * @since 1.8
+ */
+public final class GCMParameters extends AlgorithmParametersSpi {
+
+ // the iv
+ private byte[] iv;
+ // the tag length in bytes
+ private int tLen;
+
+ public GCMParameters() {}
+
+ protected void engineInit(AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException {
+
+ if (!(paramSpec instanceof GCMParameterSpec)) {
+ throw new InvalidParameterSpecException
+ ("Inappropriate parameter specification");
+ }
+ GCMParameterSpec gps = (GCMParameterSpec) paramSpec;
+ // need to convert from bits to bytes for ASN.1 encoding
+ this.tLen = gps.getTLen()/8;
+ this.iv = gps.getIV();
+ }
+
+ protected void engineInit(byte[] encoded) throws IOException {
+ DerValue val = new DerValue(encoded);
+ // check if IV or params
+ if (val.tag == DerValue.tag_Sequence) {
+ byte[] iv = val.data.getOctetString();
+ int tLen;
+ if (val.data.available() != 0) {
+ tLen = val.data.getInteger();
+ if (tLen < 12 || tLen > 16 ) {
+ throw new IOException
+ ("GCM parameter parsing error: unsupported tag len: " +
+ tLen);
+ }
+ if (val.data.available() != 0) {
+ throw new IOException
+ ("GCM parameter parsing error: extra data");
+ }
+ } else {
+ tLen = 12;
+ }
+ this.iv = iv.clone();
+ this.tLen = tLen;
+ } else {
+ throw new IOException("GCM parameter parsing error: no SEQ tag");
+ }
+ }
+
+ protected void engineInit(byte[] encoded, String decodingMethod)
+ throws IOException {
+ engineInit(encoded);
+ }
+
+ protected
+ T engineGetParameterSpec(Class paramSpec)
+ throws InvalidParameterSpecException {
+
+ if (GCMParameterSpec.class.isAssignableFrom(paramSpec)) {
+ return paramSpec.cast(new GCMParameterSpec(tLen * 8, iv));
+ } else {
+ throw new InvalidParameterSpecException
+ ("Inappropriate parameter specification");
+ }
+ }
+
+ protected byte[] engineGetEncoded() throws IOException {
+ DerOutputStream out = new DerOutputStream();
+ DerOutputStream bytes = new DerOutputStream();
+
+ bytes.putOctetString(iv);
+ bytes.putInteger(tLen);
+ out.write(DerValue.tag_Sequence, bytes);
+ return out.toByteArray();
+ }
+
+ protected byte[] engineGetEncoded(String encodingMethod)
+ throws IOException {
+ return engineGetEncoded();
+ }
+
+ /*
+ * Returns a formatted string describing the parameters.
+ */
+ protected String engineToString() {
+ String LINE_SEP = System.getProperty("line.separator");
+ HexDumpEncoder encoder = new HexDumpEncoder();
+ StringBuilder sb
+ = new StringBuilder(LINE_SEP + " iv:" + LINE_SEP + "["
+ + encoder.encodeBuffer(iv) + "]");
+
+ sb.append(LINE_SEP + "tLen(bits):" + LINE_SEP + tLen*8 + LINE_SEP);
+ return sb.toString();
+ }
+}
diff --git a/jdk/src/share/classes/com/sun/crypto/provider/GCTR.java b/jdk/src/share/classes/com/sun/crypto/provider/GCTR.java
new file mode 100644
index 00000000000..74d3555cc58
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/crypto/provider/GCTR.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2013, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+/*
+ * (C) Copyright IBM Corp. 2013
+ */
+
+package com.sun.crypto.provider;
+
+import java.security.*;
+import javax.crypto.*;
+import static com.sun.crypto.provider.AESConstants.AES_BLOCK_SIZE;
+
+/**
+ * This class represents the GCTR function defined in NIST 800-38D
+ * under section 6.5. It needs to be constructed w/ an initialized
+ * cipher object, and initial counter block(ICB). Given an input X
+ * of arbitrary length, it processes and returns an output which has
+ * the same length as X.
+ *
+ * This function is used in the implementation of GCM mode.
+ *
+ * @since 1.8
+ */
+final class GCTR {
+
+ // these fields should not change after the object has been constructed
+ private final SymmetricCipher aes;
+ private final byte[] icb;
+
+ // the current counter value
+ private byte[] counter;
+
+ // needed for save/restore calls
+ private byte[] counterSave;
+
+ // NOTE: cipher should already be initialized
+ GCTR(SymmetricCipher cipher, byte[] initialCounterBlk) {
+ this.aes = cipher;
+ this.icb = initialCounterBlk;
+ this.counter = icb.clone();
+ }
+
+ // input must be multiples of 128-bit blocks when calling update
+ int update(byte[] in, int inOfs, int inLen, byte[] out, int outOfs) {
+ if (inLen - inOfs > in.length) {
+ throw new RuntimeException("input length out of bound");
+ }
+ if (inLen < 0 || inLen % AES_BLOCK_SIZE != 0) {
+ throw new RuntimeException("input length unsupported");
+ }
+ if (out.length - outOfs < inLen) {
+ throw new RuntimeException("output buffer too small");
+ }
+
+ byte[] encryptedCntr = new byte[AES_BLOCK_SIZE];
+
+ int numOfCompleteBlocks = inLen / AES_BLOCK_SIZE;
+ for (int i = 0; i < numOfCompleteBlocks; i++) {
+ aes.encryptBlock(counter, 0, encryptedCntr, 0);
+ for (int n = 0; n < AES_BLOCK_SIZE; n++) {
+ int index = (i * AES_BLOCK_SIZE + n);
+ out[outOfs + index] =
+ (byte) ((in[inOfs + index] ^ encryptedCntr[n]));
+ }
+ GaloisCounterMode.increment32(counter);
+ }
+ return inLen;
+ }
+
+ // input can be arbitrary size when calling doFinal
+ protected int doFinal(byte[] in, int inOfs, int inLen, byte[] out,
+ int outOfs) throws IllegalBlockSizeException {
+ try {
+ if (inLen < 0) {
+ throw new IllegalBlockSizeException("Negative input size!");
+ } else if (inLen > 0) {
+ int lastBlockSize = inLen % AES_BLOCK_SIZE;
+ // process the complete blocks first
+ update(in, inOfs, inLen - lastBlockSize, out, outOfs);
+ if (lastBlockSize != 0) {
+ // do the last partial block
+ byte[] encryptedCntr = new byte[AES_BLOCK_SIZE];
+ aes.encryptBlock(counter, 0, encryptedCntr, 0);
+
+ int processed = inLen - lastBlockSize;
+ for (int n = 0; n < lastBlockSize; n++) {
+ out[outOfs + processed + n] =
+ (byte) ((in[inOfs + processed + n] ^
+ encryptedCntr[n]));
+ }
+ }
+ }
+ } finally {
+ reset();
+ }
+ return inLen;
+ }
+
+ /**
+ * Resets the current counter to its initial value.
+ * This is used after the doFinal() is called so this object can be
+ * reused w/o explicit re-initialization.
+ */
+ void reset() {
+ System.arraycopy(icb, 0, counter, 0, icb.length);
+ }
+
+ /**
+ * Save the current content of this object.
+ */
+ void save() {
+ this.counterSave = this.counter.clone();
+ }
+
+ /**
+ * Restores the content of this object to the previous saved one.
+ */
+ void restore() {
+ this.counter = this.counterSave;
+ }
+}
diff --git a/jdk/src/share/classes/com/sun/crypto/provider/GHASH.java b/jdk/src/share/classes/com/sun/crypto/provider/GHASH.java
new file mode 100644
index 00000000000..8b0ba28e898
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/crypto/provider/GHASH.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2013, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+/*
+ * (C) Copyright IBM Corp. 2013
+ */
+
+package com.sun.crypto.provider;
+
+import java.util.Arrays;
+import java.security.*;
+import static com.sun.crypto.provider.AESConstants.AES_BLOCK_SIZE;
+
+/**
+ * This class represents the GHASH function defined in NIST 800-38D
+ * under section 6.4. It needs to be constructed w/ a hash subkey, i.e.
+ * block H. Given input of 128-bit blocks, it will process and output
+ * a 128-bit block.
+ *
+ *
This function is used in the implementation of GCM mode.
+ *
+ * @since 1.8
+ */
+final class GHASH {
+
+ private static final byte P128 = (byte) 0xe1; //reduction polynomial
+
+ private static boolean getBit(byte[] b, int pos) {
+ int p = pos / 8;
+ pos %= 8;
+ int i = (b[p] >>> (7 - pos)) & 1;
+ return i != 0;
+ }
+
+ private static void shift(byte[] b) {
+ byte temp, temp2;
+ temp2 = 0;
+ for (int i = 0; i < b.length; i++) {
+ temp = (byte) ((b[i] & 0x01) << 7);
+ b[i] = (byte) ((b[i] & 0xff) >>> 1);
+ b[i] = (byte) (b[i] | temp2);
+ temp2 = temp;
+ }
+ }
+
+ // Given block X and Y, returns the muliplication of X * Y
+ private static byte[] blockMult(byte[] x, byte[] y) {
+ if (x.length != AES_BLOCK_SIZE || y.length != AES_BLOCK_SIZE) {
+ throw new RuntimeException("illegal input sizes");
+ }
+ byte[] z = new byte[AES_BLOCK_SIZE];
+ byte[] v = y.clone();
+ // calculate Z1-Z127 and V1-V127
+ for (int i = 0; i < 127; i++) {
+ // Zi+1 = Zi if bit i of x is 0
+ if (getBit(x, i)) {
+ for (int n = 0; n < z.length; n++) {
+ z[n] ^= v[n];
+ }
+ }
+ boolean lastBitOfV = getBit(v, 127);
+ shift(v);
+ if (lastBitOfV) v[0] ^= P128;
+ }
+ // calculate Z128
+ if (getBit(x, 127)) {
+ for (int n = 0; n < z.length; n++) {
+ z[n] ^= v[n];
+ }
+ }
+ return z;
+ }
+
+ // hash subkey H; should not change after the object has been constructed
+ private final byte[] subkeyH;
+
+ // buffer for storing hash
+ private byte[] state;
+
+ // variables for save/restore calls
+ private byte[] stateSave = null;
+
+ /**
+ * Initializes the cipher in the specified mode with the given key
+ * and iv.
+ *
+ * @param subkeyH the hash subkey
+ *
+ * @exception ProviderException if the given key is inappropriate for
+ * initializing this digest
+ */
+ GHASH(byte[] subkeyH) throws ProviderException {
+ if ((subkeyH == null) || subkeyH.length != AES_BLOCK_SIZE) {
+ throw new ProviderException("Internal error");
+ }
+ this.subkeyH = subkeyH;
+ this.state = new byte[AES_BLOCK_SIZE];
+ }
+
+ /**
+ * Resets the GHASH object to its original state, i.e. blank w/
+ * the same subkey H. Used after digest() is called and to re-use
+ * this object for different data w/ the same H.
+ */
+ void reset() {
+ Arrays.fill(state, (byte) 0);
+ }
+
+ /**
+ * Save the current snapshot of this GHASH object.
+ */
+ void save() {
+ stateSave = state.clone();
+ }
+
+ /**
+ * Restores this object using the saved snapshot.
+ */
+ void restore() {
+ state = stateSave;
+ }
+
+ private void processBlock(byte[] data, int ofs) {
+ if (data.length - ofs < AES_BLOCK_SIZE) {
+ throw new RuntimeException("need complete block");
+ }
+ for (int n = 0; n < state.length; n++) {
+ state[n] ^= data[ofs + n];
+ }
+ state = blockMult(state, subkeyH);
+ }
+
+ void update(byte[] in) {
+ update(in, 0, in.length);
+ }
+
+ void update(byte[] in, int inOfs, int inLen) {
+ if (inLen - inOfs > in.length) {
+ throw new RuntimeException("input length out of bound");
+ }
+ if (inLen % AES_BLOCK_SIZE != 0) {
+ throw new RuntimeException("input length unsupported");
+ }
+
+ for (int i = inOfs; i < (inOfs + inLen); i += AES_BLOCK_SIZE) {
+ processBlock(in, i);
+ }
+ }
+
+ byte[] digest() {
+ try {
+ return state.clone();
+ } finally {
+ reset();
+ }
+ }
+}
diff --git a/jdk/src/share/classes/com/sun/crypto/provider/GaloisCounterMode.java b/jdk/src/share/classes/com/sun/crypto/provider/GaloisCounterMode.java
new file mode 100644
index 00000000000..a2c6cfd82ef
--- /dev/null
+++ b/jdk/src/share/classes/com/sun/crypto/provider/GaloisCounterMode.java
@@ -0,0 +1,501 @@
+/*
+ * Copyright (c) 2013, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.S
+ *
+ * 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 com.sun.crypto.provider;
+
+import java.util.Arrays;
+import java.io.*;
+import java.security.*;
+import javax.crypto.*;
+import static com.sun.crypto.provider.AESConstants.AES_BLOCK_SIZE;
+
+/**
+ * This class represents ciphers in GaloisCounter (GCM) mode.
+ *
+ *
This mode currently should only be used w/ AES cipher.
+ * Although no checking is done here, caller should only
+ * pass AES Cipher to the constructor.
+ *
+ *
NOTE: This class does not deal with buffering or padding.
+ *
+ * @since 1.8
+ */
+final class GaloisCounterMode extends FeedbackCipher {
+
+ static int DEFAULT_TAG_LEN = AES_BLOCK_SIZE;
+ static int DEFAULT_IV_LEN = 12; // in bytes
+
+ // buffer for AAD data; if null, meaning update has been called
+ private ByteArrayOutputStream aadBuffer = new ByteArrayOutputStream();
+ private int sizeOfAAD = 0;
+
+ // in bytes; need to convert to bits (default value 128) when needed
+ private int tagLenBytes = DEFAULT_TAG_LEN;
+
+ // these following 2 fields can only be initialized after init() is
+ // called, e.g. after cipher key k is set, and STAY UNCHANGED
+ private byte[] subkeyH = null;
+ private byte[] preCounterBlock = null;
+
+ private GCTR gctrPAndC = null;
+ private GHASH ghashAllToS = null;
+
+ // length of total data, i.e. len(C)
+ private int processed = 0;
+
+ // additional variables for save/restore calls
+ private byte[] aadBufferSave = null;
+ private int sizeOfAADSave = 0;
+ private int processedSave = 0;
+
+ // value must be 16-byte long; used by GCTR and GHASH as well
+ static void increment32(byte[] value) {
+ if (value.length != AES_BLOCK_SIZE) {
+ throw new RuntimeException("Unexpected counter block length");
+ }
+ // start from last byte and only go over 4 bytes, i.e. total 32 bits
+ int n = value.length - 1;
+ while ((n >= value.length - 4) && (++value[n] == 0)) {
+ n--;
+ }
+ }
+
+ // ivLen in bits
+ private static byte[] getLengthBlock(int ivLen) {
+ byte[] out = new byte[AES_BLOCK_SIZE];
+ out[12] = (byte)(ivLen >>> 24);
+ out[13] = (byte)(ivLen >>> 16);
+ out[14] = (byte)(ivLen >>> 8);
+ out[15] = (byte)ivLen;
+ return out;
+ }
+
+ // aLen and cLen both in bits
+ private static byte[] getLengthBlock(int aLen, int cLen) {
+ byte[] out = new byte[AES_BLOCK_SIZE];
+ out[4] = (byte)(aLen >>> 24);
+ out[5] = (byte)(aLen >>> 16);
+ out[6] = (byte)(aLen >>> 8);
+ out[7] = (byte)aLen;
+ out[12] = (byte)(cLen >>> 24);
+ out[13] = (byte)(cLen >>> 16);
+ out[14] = (byte)(cLen >>> 8);
+ out[15] = (byte)cLen;
+ return out;
+ }
+
+ private static byte[] expandToOneBlock(byte[] in, int inOfs, int len) {
+ if (len > AES_BLOCK_SIZE) {
+ throw new ProviderException("input " + len + " too long");
+ }
+ if (len == AES_BLOCK_SIZE && inOfs == 0) {
+ return in;
+ } else {
+ byte[] paddedIn = new byte[AES_BLOCK_SIZE];
+ System.arraycopy(in, inOfs, paddedIn, 0, len);
+ return paddedIn;
+ }
+ }
+
+ private static byte[] getJ0(byte[] iv, byte[] subkeyH) {
+ byte[] j0;
+ if (iv.length == 12) { // 96 bits
+ j0 = expandToOneBlock(iv, 0, iv.length);
+ j0[AES_BLOCK_SIZE - 1] = 1;
+ } else {
+ GHASH g = new GHASH(subkeyH);
+ int lastLen = iv.length % AES_BLOCK_SIZE;
+ if (lastLen != 0) {
+ g.update(iv, 0, iv.length - lastLen);
+ byte[] padded =
+ expandToOneBlock(iv, iv.length - lastLen, lastLen);
+ g.update(padded);
+ } else {
+ g.update(iv);
+ }
+ byte[] lengthBlock = getLengthBlock(iv.length*8);
+ g.update(lengthBlock);
+ j0 = g.digest();
+ }
+ return j0;
+ }
+
+ GaloisCounterMode(SymmetricCipher embeddedCipher) {
+ super(embeddedCipher);
+ aadBuffer = new ByteArrayOutputStream();
+ }
+
+ /**
+ * Gets the name of the feedback mechanism
+ *
+ * @return the name of the feedback mechanism
+ */
+ String getFeedback() {
+ return "GCM";
+ }
+
+ /**
+ * Resets the cipher object to its original state.
+ * This is used when doFinal is called in the Cipher class, so that the
+ * cipher can be reused (with its original key and iv).
+ */
+ void reset() {
+ if (aadBuffer == null) {
+ aadBuffer = new ByteArrayOutputStream();
+ } else {
+ aadBuffer.reset();
+ }
+ if (gctrPAndC != null) gctrPAndC.reset();
+ if (ghashAllToS != null) ghashAllToS.reset();
+ processed = 0;
+ sizeOfAAD = 0;
+ }
+
+ /**
+ * Save the current content of this cipher.
+ */
+ void save() {
+ processedSave = processed;
+ sizeOfAADSave = sizeOfAAD;
+ aadBufferSave =
+ ((aadBuffer == null || aadBuffer.size() == 0)?
+ null : aadBuffer.toByteArray());
+ if (gctrPAndC != null) gctrPAndC.save();
+ if (ghashAllToS != null) ghashAllToS.save();
+ }
+
+ /**
+ * Restores the content of this cipher to the previous saved one.
+ */
+ void restore() {
+ processed = processedSave;
+ sizeOfAAD = sizeOfAADSave;
+ if (aadBuffer != null) {
+ aadBuffer.reset();
+ if (aadBufferSave != null) {
+ aadBuffer.write(aadBufferSave, 0, aadBufferSave.length);
+ }
+ }
+ if (gctrPAndC != null) gctrPAndC.restore();
+ if (ghashAllToS != null) ghashAllToS.restore();
+ }
+
+ /**
+ * Initializes the cipher in the specified mode with the given key
+ * and iv.
+ *
+ * @param decrypting flag indicating encryption or decryption
+ * @param algorithm the algorithm name
+ * @param key the key
+ * @param iv the iv
+ * @param tagLenBytes the length of tag in bytes
+ *
+ * @exception InvalidKeyException if the given key is inappropriate for
+ * initializing this cipher
+ */
+ void init(boolean decrypting, String algorithm, byte[] key, byte[] iv)
+ throws InvalidKeyException {
+ init(decrypting, algorithm, key, iv, DEFAULT_TAG_LEN);
+ }
+
+ /**
+ * Initializes the cipher in the specified mode with the given key
+ * and iv.
+ *
+ * @param decrypting flag indicating encryption or decryption
+ * @param algorithm the algorithm name
+ * @param key the key
+ * @param iv the iv
+ * @param tagLenBytes the length of tag in bytes
+ *
+ * @exception InvalidKeyException if the given key is inappropriate for
+ * initializing this cipher
+ */
+ void init(boolean decrypting, String algorithm, byte[] keyValue,
+ byte[] ivValue, int tagLenBytes)
+ throws InvalidKeyException {
+ if (keyValue == null || ivValue == null) {
+ throw new InvalidKeyException("Internal error");
+ }
+
+ // always encrypt mode for embedded cipher
+ this.embeddedCipher.init(false, algorithm, keyValue);
+ this.subkeyH = new byte[AES_BLOCK_SIZE];
+ this.embeddedCipher.encryptBlock(new byte[AES_BLOCK_SIZE], 0,
+ this.subkeyH, 0);
+
+ this.iv = ivValue.clone();
+ preCounterBlock = getJ0(iv, subkeyH);
+ byte[] j0Plus1 = preCounterBlock.clone();
+ increment32(j0Plus1);
+ gctrPAndC = new GCTR(embeddedCipher, j0Plus1);
+ ghashAllToS = new GHASH(subkeyH);
+
+ this.tagLenBytes = tagLenBytes;
+ if (aadBuffer == null) {
+ aadBuffer = new ByteArrayOutputStream();
+ } else {
+ aadBuffer.reset();
+ }
+ processed = 0;
+ sizeOfAAD = 0;
+ }
+
+ /**
+ * Continues a multi-part update of the Additional Authentication
+ * Data (AAD), using a subset of the provided buffer. If this
+ * cipher is operating in either GCM or CCM mode, all AAD must be
+ * supplied before beginning operations on the ciphertext (via the
+ * {@code update} and {@code doFinal} methods).
+ *
+ * NOTE: Given most modes do not accept AAD, default impl for this
+ * method throws IllegalStateException.
+ *
+ * @param src the buffer containing the AAD
+ * @param offset the offset in {@code src} where the AAD input starts
+ * @param len the number of AAD bytes
+ *
+ * @throws IllegalStateException if this cipher is in a wrong state
+ * (e.g., has not been initialized), does not accept AAD, or if
+ * operating in either GCM or CCM mode and one of the {@code update}
+ * methods has already been called for the active
+ * encryption/decryption operation
+ * @throws UnsupportedOperationException if this method
+ * has not been overridden by an implementation
+ *
+ * @since 1.8
+ */
+ void updateAAD(byte[] src, int offset, int len) {
+ if (aadBuffer != null) {
+ aadBuffer.write(src, offset, len);
+ } else {
+ // update has already been called
+ throw new IllegalStateException
+ ("Update has been called; no more AAD data");
+ }
+ }
+
+ // Feed the AAD data to GHASH, pad if necessary
+ void processAAD() {
+ if (aadBuffer != null) {
+ byte[] aad = aadBuffer.toByteArray();
+ sizeOfAAD = aad.length;
+ aadBuffer = null;
+
+ int lastLen = aad.length % AES_BLOCK_SIZE;
+ if (lastLen != 0) {
+ ghashAllToS.update(aad, 0, aad.length - lastLen);
+ byte[] padded = expandToOneBlock(aad, aad.length - lastLen,
+ lastLen);
+ ghashAllToS.update(padded);
+ } else {
+ ghashAllToS.update(aad);
+ }
+ }
+ }
+
+ // Utility to process the last block; used by encryptFinal and decryptFinal
+ void doLastBlock(byte[] in, int inOfs, int len, byte[] out, int outOfs,
+ boolean isEncrypt) throws IllegalBlockSizeException {
+ // process data in 'in'
+ gctrPAndC.doFinal(in, inOfs, len, out, outOfs);
+ processed += len;
+
+ byte[] ct;
+ int ctOfs;
+ if (isEncrypt) {
+ ct = out;
+ ctOfs = outOfs;
+ } else {
+ ct = in;
+ ctOfs = inOfs;
+ }
+ int lastLen = len % AES_BLOCK_SIZE;
+ if (lastLen != 0) {
+ ghashAllToS.update(ct, ctOfs, len - lastLen);
+ byte[] padded =
+ expandToOneBlock(ct, (ctOfs + len - lastLen), lastLen);
+ ghashAllToS.update(padded);
+ } else {
+ ghashAllToS.update(ct, ctOfs, len);
+ }
+ }
+
+
+ /**
+ * Performs encryption operation.
+ *
+ *
The input plain text in, starting at inOff
+ * and ending at (inOff + len - 1), is encrypted. The result
+ * is stored in out, starting at outOfs.
+ *
+ *
It is the application's responsibility to make sure that
+ * len is a multiple of the embedded cipher's block size,
+ * otherwise, a ProviderException will be thrown.
+ *
+ *
It is also the application's responsibility to make sure that
+ * init has been called before this method is called.
+ * (This check is omitted here, to avoid double checking.)
+ *
+ * @param in the buffer with the input data to be encrypted
+ * @param inOfs the offset in in
+ * @param len the length of the input data
+ * @param out the buffer for the result
+ * @param outOfs the offset in out
+ */
+ void encrypt(byte[] in, int inOfs, int len, byte[] out, int outOfs) {
+ processAAD();
+ if (len > 0) {
+ gctrPAndC.update(in, inOfs, len, out, outOfs);
+ processed += len;
+ ghashAllToS.update(out, outOfs, len);
+ }
+ }
+
+ /**
+ * Performs encryption operation for the last time.
+ *
+ *
NOTE: len may not be multiple of the embedded
+ * cipher's block size for this call.
+ *
+ * @param in the input buffer with the data to be encrypted
+ * @param inOfs the offset in in
+ * @param len the length of the input data
+ * @param out the buffer for the encryption result
+ * @param outOfs the offset in out
+ * @return the number of bytes placed into the out buffer
+ */
+ int encryptFinal(byte[] in, int inOfs, int len, byte[] out, int outOfs)
+ throws IllegalBlockSizeException {
+ if (out.length - outOfs < (len + tagLenBytes)) {
+ throw new RuntimeException("Output buffer too small");
+ }
+
+ processAAD();
+ if (len > 0) {
+ //ByteUtil.dumpArray(Arrays.copyOfRange(in, inOfs, inOfs + len));
+ doLastBlock(in, inOfs, len, out, outOfs, true);
+ }
+
+ byte[] lengthBlock = getLengthBlock(sizeOfAAD*8, processed*8);
+ ghashAllToS.update(lengthBlock);
+ byte[] s = ghashAllToS.digest();
+ byte[] sOut = new byte[s.length];
+ GCTR gctrForSToTag = new GCTR(embeddedCipher, this.preCounterBlock);
+ gctrForSToTag.doFinal(s, 0, s.length, sOut, 0);
+
+ System.arraycopy(sOut, 0, out, (outOfs + len), tagLenBytes);
+ return (len + tagLenBytes);
+ }
+
+ /**
+ * Performs decryption operation.
+ *
+ *
The input cipher text in, starting at
+ * inOfs and ending at (inOfs + len - 1),
+ * is decrypted. The result is stored in out, starting at
+ * outOfs.
+ *
+ *
It is the application's responsibility to make sure that
+ * len is a multiple of the embedded cipher's block
+ * size, as any excess bytes are ignored.
+ *
+ *
It is also the application's responsibility to make sure that
+ * init has been called before this method is called.
+ * (This check is omitted here, to avoid double checking.)
+ *
+ * @param in the buffer with the input data to be decrypted
+ * @param inOfs the offset in in
+ * @param len the length of the input data
+ * @param out the buffer for the result
+ * @param outOfs the offset in out
+ */
+ void decrypt(byte[] in, int inOfs, int len, byte[] out, int outOfs) {
+ processAAD();
+
+ if (len > 0) { // must be at least AES_BLOCK_SIZE bytes long
+ gctrPAndC.update(in, inOfs, len, out, outOfs);
+ processed += len;
+ ghashAllToS.update(in, inOfs, len);
+ }
+ }
+
+ /**
+ * Performs decryption operation for the last time.
+ *
+ *
NOTE: For cipher feedback modes which does not perform
+ * special handling for the last few blocks, this is essentially
+ * the same as encrypt(...). Given most modes do
+ * not do special handling, the default impl for this method is
+ * to simply call decrypt(...).
+ *
+ * @param in the input buffer with the data to be decrypted
+ * @param inOfs the offset in cipher
+ * @param len the length of the input data
+ * @param out the buffer for the decryption result
+ * @param outOfs the offset in plain
+ * @return the number of bytes placed into the out buffer
+ */
+ int decryptFinal(byte[] in, int inOfs, int len,
+ byte[] out, int outOfs)
+ throws IllegalBlockSizeException, AEADBadTagException {
+ if (len < tagLenBytes) {
+ throw new RuntimeException("Input buffer too short - need tag");
+ }
+ if (out.length - outOfs < (len - tagLenBytes)) {
+ throw new RuntimeException("Output buffer too small");
+ }
+ processAAD();
+
+ int processedOld = processed;
+ byte[] tag = new byte[tagLenBytes];
+ // get the trailing tag bytes from 'in'
+ System.arraycopy(in, inOfs + len - tagLenBytes, tag, 0, tagLenBytes);
+ len -= tagLenBytes;
+
+ if (len > 0) {
+ doLastBlock(in, inOfs, len, out, outOfs, false);
+ }
+
+ byte[] lengthBlock = getLengthBlock(sizeOfAAD*8, processed*8);
+ ghashAllToS.update(lengthBlock);
+
+ byte[] s = ghashAllToS.digest();
+ byte[] sOut = new byte[s.length];
+ GCTR gctrForSToTag = new GCTR(embeddedCipher, this.preCounterBlock);
+ gctrForSToTag.doFinal(s, 0, s.length, sOut, 0);
+ for (int i = 0; i < tagLenBytes; i++) {
+ if (tag[i] != sOut[i]) {
+ throw new AEADBadTagException("Tag mismatch!");
+ }
+ }
+ return len;
+ }
+
+ // return tag length in bytes
+ int getTagLen() {
+ return this.tagLenBytes;
+ }
+}
diff --git a/jdk/src/share/classes/com/sun/crypto/provider/SunJCE.java b/jdk/src/share/classes/com/sun/crypto/provider/SunJCE.java
index 3edac42c6ba..9128495e40a 100644
--- a/jdk/src/share/classes/com/sun/crypto/provider/SunJCE.java
+++ b/jdk/src/share/classes/com/sun/crypto/provider/SunJCE.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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
@@ -57,6 +57,7 @@ import java.security.SecureRandom;
* - ARCFOUR (RC4 compatible)
*
* - Cipher modes ECB, CBC, CFB, OFB, PCBC, CTR, and CTS for all block ciphers
+ * and mode GCM for AES cipher
*
* - Cipher padding ISO10126Padding for non-PKCS#5 block ciphers and
* NoPadding and PKCS5Padding for all block ciphers
@@ -100,7 +101,7 @@ public final class SunJCE extends Provider {
"|CFB8|CFB16|CFB24|CFB32|CFB40|CFB48|CFB56|CFB64" +
"|OFB8|OFB16|OFB24|OFB32|OFB40|OFB48|OFB56|OFB64";
final String BLOCK_MODES128 = BLOCK_MODES +
- "|CFB72|CFB80|CFB88|CFB96|CFB104|CFB112|CFB120|CFB128" +
+ "|GCM|CFB72|CFB80|CFB88|CFB96|CFB104|CFB112|CFB120|CFB128" +
"|OFB72|OFB80|OFB88|OFB96|OFB104|OFB112|OFB120|OFB128";
final String BLOCK_PADS = "NOPADDING|PKCS5PADDING|ISO10126PADDING";
@@ -258,6 +259,9 @@ public final class SunJCE extends Provider {
put("Cipher.AES_128/CFB/NoPadding", "com.sun.crypto.provider.AESCipher$AES128_CFB_NoPadding");
put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.4", "AES_128/CFB/NoPadding");
put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.4", "AES_128/CFB/NoPadding");
+ put("Cipher.AES_128/GCM/NoPadding", "com.sun.crypto.provider.AESCipher$AES128_GCM_NoPadding");
+ put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.6", "AES_128/GCM/NoPadding");
+ put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.6", "AES_128/GCM/NoPadding");
put("Cipher.AES_192/ECB/NoPadding", "com.sun.crypto.provider.AESCipher$AES192_ECB_NoPadding");
put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.21", "AES_192/ECB/NoPadding");
@@ -271,7 +275,9 @@ public final class SunJCE extends Provider {
put("Cipher.AES_192/CFB/NoPadding", "com.sun.crypto.provider.AESCipher$AES192_CFB_NoPadding");
put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.24", "AES_192/CFB/NoPadding");
put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.24", "AES_192/CFB/NoPadding");
-
+ put("Cipher.AES_192/GCM/NoPadding", "com.sun.crypto.provider.AESCipher$AES192_GCM_NoPadding");
+ put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.26", "AES_192/GCM/NoPadding");
+ put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.26", "AES_192/GCM/NoPadding");
put("Cipher.AES_256/ECB/NoPadding", "com.sun.crypto.provider.AESCipher$AES256_ECB_NoPadding");
put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.41", "AES_256/ECB/NoPadding");
@@ -285,6 +291,9 @@ public final class SunJCE extends Provider {
put("Cipher.AES_256/CFB/NoPadding", "com.sun.crypto.provider.AESCipher$AES256_CFB_NoPadding");
put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.44", "AES_256/CFB/NoPadding");
put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.44", "AES_256/CFB/NoPadding");
+ put("Cipher.AES_256/GCM/NoPadding", "com.sun.crypto.provider.AESCipher$AES256_GCM_NoPadding");
+ put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.46", "AES_256/GCM/NoPadding");
+ put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.46", "AES_256/GCM/NoPadding");
put("Cipher.AESWrap", "com.sun.crypto.provider.AESWrapCipher$General");
put("Cipher.AESWrap SupportedModes", "ECB");
@@ -509,6 +518,8 @@ public final class SunJCE extends Provider {
put("AlgorithmParameters.AES",
"com.sun.crypto.provider.AESParameters");
put("Alg.Alias.AlgorithmParameters.Rijndael", "AES");
+ put("AlgorithmParameters.GCM",
+ "com.sun.crypto.provider.GCMParameters");
put("AlgorithmParameters.RC2",
diff --git a/jdk/src/share/classes/javax/crypto/Cipher.java b/jdk/src/share/classes/javax/crypto/Cipher.java
index 408d9b91172..bdbe2bcd98e 100644
--- a/jdk/src/share/classes/javax/crypto/Cipher.java
+++ b/jdk/src/share/classes/javax/crypto/Cipher.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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
@@ -104,17 +104,30 @@ import sun.security.jca.*;
* must be supplied to GCM/CCM implementations (via the {@code
* updateAAD} methods) before the ciphertext is processed (via
* the {@code update} and {@code doFinal} methods).
- *
+ *
+ * Note that GCM mode has a uniqueness requirement on IVs used in
+ * encryption with a given key. When IVs are repeated for GCM
+ * encryption, such usages are subject to forgery attacks. Thus, after
+ * each encryption operation using GCM mode, callers should re-initialize
+ * the cipher objects with GCM parameters which has a different IV value.
*
- * GCMParameterSpec s = new GCMParameterSpec(...);
+ * GCMParameterSpec s = ...;
* cipher.init(..., s);
*
- * // If the GCMParameterSpec is needed again
- * cipher.getParameters().getParameterSpec(GCMParameterSpec.class));
+ * // If the GCM parameters were generated by the provider, it can
+ * // be retrieved by:
+ * // cipher.getParameters().getParameterSpec(GCMParameterSpec.class);
*
* cipher.updateAAD(...); // AAD
* cipher.update(...); // Multi-part update
* cipher.doFinal(...); // conclusion of operation
+ *
+ * // Use a different IV value for every encryption
+ * byte[] newIv = ...;
+ * s = new GCMParameterSpec(s.getTLen(), newIv);
+ * cipher.init(..., s);
+ * ...
+ *
*
* Every implementation of the Java platform is required to support
* the following standard Cipher transformations with the keysizes
diff --git a/jdk/src/share/classes/javax/crypto/spec/GCMParameterSpec.java b/jdk/src/share/classes/javax/crypto/spec/GCMParameterSpec.java
index 01cb1cc7028..403205a298e 100644
--- a/jdk/src/share/classes/javax/crypto/spec/GCMParameterSpec.java
+++ b/jdk/src/share/classes/javax/crypto/spec/GCMParameterSpec.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2013, 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
@@ -43,7 +43,7 @@ import java.security.spec.AlgorithmParameterSpec;
* (Additional Authenticated Data (AAD), Keys, block ciphers,
* plain/ciphertext and authentication tags) are handled in the {@code
* Cipher} class.
-
+ *
* Please see RFC 5116
* for more information on the Authenticated Encryption with
* Associated Data (AEAD) algorithm, and
Date: Mon, 7 Jan 2013 13:19:03 -0800
Subject: [PATCH 24/53] 8003228: (props) sun.jnu.encoding should be set to
UTF-8 [macosx]
Hard-code sun.jnu.encoding to UTF-8 on Mac
Reviewed-by: naoto
---
jdk/src/share/native/java/lang/System.c | 8 ++
.../solaris/native/java/lang/java_props_md.c | 5 ++
.../MacJNUEncoding/ExpectedEncoding.java | 56 ++++++++++++
.../MacJNUEncoding/MacJNUEncoding.sh | 90 +++++++++++++++++++
4 files changed, 159 insertions(+)
create mode 100644 jdk/test/java/util/Properties/MacJNUEncoding/ExpectedEncoding.java
create mode 100644 jdk/test/java/util/Properties/MacJNUEncoding/MacJNUEncoding.sh
diff --git a/jdk/src/share/native/java/lang/System.c b/jdk/src/share/native/java/lang/System.c
index 84ae689b50f..8efd95e09b7 100644
--- a/jdk/src/share/native/java/lang/System.c
+++ b/jdk/src/share/native/java/lang/System.c
@@ -389,11 +389,19 @@ Java_java_lang_System_initProperties(JNIEnv *env, jclass cla, jobject props)
sprops->display_variant, sprops->format_variant, putID, getPropID);
GETPROP(props, "file.encoding", jVMVal);
if (jVMVal == NULL) {
+#ifdef MACOSX
+ /*
+ * Since sun_jnu_encoding is now hard-coded to UTF-8 on Mac, we don't
+ * want to use it to overwrite file.encoding
+ */
+ PUTPROP(props, "file.encoding", sprops->encoding);
+#else
if (fmtdefault) {
PUTPROP(props, "file.encoding", sprops->encoding);
} else {
PUTPROP(props, "file.encoding", sprops->sun_jnu_encoding);
}
+#endif
} else {
(*env)->DeleteLocalRef(env, jVMVal);
}
diff --git a/jdk/src/solaris/native/java/lang/java_props_md.c b/jdk/src/solaris/native/java/lang/java_props_md.c
index baba74fe897..c7d3ba6eff5 100644
--- a/jdk/src/solaris/native/java/lang/java_props_md.c
+++ b/jdk/src/solaris/native/java/lang/java_props_md.c
@@ -538,7 +538,12 @@ GetJavaProperties(JNIEnv *env)
sprops.display_script = sprops.script;
sprops.display_country = sprops.country;
sprops.display_variant = sprops.variant;
+
+#ifdef MACOSX
+ sprops.sun_jnu_encoding = "UTF-8";
+#else
sprops.sun_jnu_encoding = sprops.encoding;
+#endif
#ifdef _ALLBSD_SOURCE
#if BYTE_ORDER == _LITTLE_ENDIAN
diff --git a/jdk/test/java/util/Properties/MacJNUEncoding/ExpectedEncoding.java b/jdk/test/java/util/Properties/MacJNUEncoding/ExpectedEncoding.java
new file mode 100644
index 00000000000..b8835b8edb7
--- /dev/null
+++ b/jdk/test/java/util/Properties/MacJNUEncoding/ExpectedEncoding.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2012, 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.
+ */
+
+/**
+ * Check that the value of file.encoding and sun.jnu.encoding match the expected
+ * values passed in on the command-line.
+ */
+public class ExpectedEncoding {
+ public static void main(String[] args) {
+ boolean failed = false;
+ if (args.length != 2) {
+ System.out.println("Usage:");
+ System.out.println("$ java ExpectedEncoding ");
+ }
+ String expectFileEnc = args[0];
+ String expectSunJnuEnc = args[1];
+
+ String fileEnc = System.getProperty("file.encoding");
+ String jnuEnc = System.getProperty("sun.jnu.encoding");
+
+ if (fileEnc == null || !fileEnc.equals(expectFileEnc)) {
+ System.err.println("Expected file.encoding: " + expectFileEnc);
+ System.err.println("Actual file.encoding: " + fileEnc);
+ failed = true;
+ }
+ if (jnuEnc == null || !jnuEnc.equals(expectSunJnuEnc)) {
+ System.err.println("Expected sun.jnu.encoding: " + expectSunJnuEnc);
+ System.err.println("Actual sun.jnu.encoding: " + jnuEnc);
+ failed = true;
+ }
+ if (failed) {
+ System.err.println("Test Failed");
+ System.exit(1);
+ }
+ }
+}
diff --git a/jdk/test/java/util/Properties/MacJNUEncoding/MacJNUEncoding.sh b/jdk/test/java/util/Properties/MacJNUEncoding/MacJNUEncoding.sh
new file mode 100644
index 00000000000..0131467dba1
--- /dev/null
+++ b/jdk/test/java/util/Properties/MacJNUEncoding/MacJNUEncoding.sh
@@ -0,0 +1,90 @@
+#!/bin/sh
+
+#
+# Copyright (c) 2012 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 8003228
+# @summary Test the value of sun.jnu.encoding on Mac
+# @author Brent Christian
+#
+# @run shell MacJNUEncoding.sh
+
+# Only run test on Mac
+OS=`uname -s`
+case "$OS" in
+ Darwin ) ;;
+ * )
+ exit 0
+ ;;
+esac
+
+if [ "${TESTJAVA}" = "" ]
+then
+ echo "TESTJAVA not set. Test cannot execute. Failed."
+ exit 1
+fi
+
+if [ "${TESTSRC}" = "" ]
+then
+ echo "TESTSRC not set. Test cannot execute. Failed."
+ exit 1
+fi
+
+if [ "${TESTCLASSES}" = "" ]
+then
+ echo "TESTCLASSES not set. Test cannot execute. Failed."
+ exit 1
+fi
+
+JAVAC="${TESTJAVA}"/bin/javac
+JAVA="${TESTJAVA}"/bin/java
+
+echo "Building test classes..."
+"$JAVAC" -d "${TESTCLASSES}" "${TESTSRC}"/ExpectedEncoding.java
+
+echo ""
+echo "Running test for LANG=C"
+export LANG=C
+"${JAVA}" ${TESTVMOPTS} -classpath "${TESTCLASSES}" ExpectedEncoding US-ASCII UTF-8
+result1=$?
+
+echo ""
+echo "Running test for LANG=en_US.UTF-8"
+export LANG=en_US.UTF-8
+"${JAVA}" ${TESTVMOPTS} -classpath "${TESTCLASSES}" ExpectedEncoding UTF-8 UTF-8
+result2=$?
+
+echo ""
+echo "Cleanup"
+rm ${TESTCLASSES}/ExpectedEncoding.class
+
+if [ ${result1} -ne 0 ] ; then
+ echo "Test failed for LANG=C"
+ exit ${result1}
+fi
+if [ ${result2} -ne 0 ] ; then
+ echo "Test failed for LANG=en_US.UTF-8"
+ exit ${result2}
+fi
+exit 0
+
From f660de4e1e636b728346f59b54139b60eec73cc5 Mon Sep 17 00:00:00 2001
From: Stuart Marks
Date: Mon, 7 Jan 2013 18:09:07 -0800
Subject: [PATCH 25/53] 7187882: TEST_BUG:
java/rmi/activation/checkusage/CheckUsage.java fails intermittently
Tighten up JavaVM test library API, and adjust tests to match.
Reviewed-by: mchung, dmocek
---
jdk/test/ProblemList.txt | 5 +--
.../ShutdownGracefully.java | 8 ++---
.../rmi/activation/checkusage/CheckUsage.java | 24 +++++---------
.../AltSecurityManager.java | 5 ++-
.../rmi/registry/checkusage/CheckUsage.java | 28 ++++-------------
.../java/rmi/registry/reexport/Reexport.java | 8 ++---
jdk/test/java/rmi/testlibrary/JavaVM.java | 31 +++++++++++++++----
jdk/test/java/rmi/testlibrary/RMID.java | 4 +--
.../rmi/transport/checkFQDN/CheckFQDN.java | 8 ++---
.../checkLeaseInfoLeak/CheckLeaseLeak.java | 5 ++-
.../rmi/runtime/Log/4504153/Test4504153.java | 5 ++-
.../runtime/Log/6409194/NoConsoleOutput.java | 5 ++-
.../transport/tcp/DeadCachedConnection.java | 6 ++--
13 files changed, 62 insertions(+), 80 deletions(-)
diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt
index d2387317b5d..3aa7cfff170 100644
--- a/jdk/test/ProblemList.txt
+++ b/jdk/test/ProblemList.txt
@@ -1,6 +1,6 @@
###########################################################################
#
-# Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2009, 2013, 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
@@ -238,9 +238,6 @@ java/nio/channels/AsynchronousChannelGroup/Unbounded.java windows-amd64
# 7146541
java/rmi/transport/rapidExportUnexport/RapidExportUnexport.java linux-all
-# 7187882
-java/rmi/activation/checkusage/CheckUsage.java generic-all
-
# 7190106
java/rmi/reliability/benchmark/runRmiBench.sh generic-all
diff --git a/jdk/test/java/rmi/activation/Activatable/shutdownGracefully/ShutdownGracefully.java b/jdk/test/java/rmi/activation/Activatable/shutdownGracefully/ShutdownGracefully.java
index 64233bfd6f1..b6ede1d316a 100644
--- a/jdk/test/java/rmi/activation/Activatable/shutdownGracefully/ShutdownGracefully.java
+++ b/jdk/test/java/rmi/activation/Activatable/shutdownGracefully/ShutdownGracefully.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2013, 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
@@ -168,7 +168,7 @@ public class ShutdownGracefully
registering = null;
// Need to make sure that rmid goes away by itself
- Process rmidProcess = rmid.getVM();
+ JavaVM rmidProcess = rmid;
if (rmidProcess != null) {
try {
Runnable waitThread =
@@ -205,9 +205,9 @@ public class ShutdownGracefully
* class that waits for rmid to exit
*/
private static class ShutdownDetectThread implements Runnable {
- private Process rmidProcess = null;
+ private JavaVM rmidProcess = null;
- ShutdownDetectThread(Process rmidProcess) {
+ ShutdownDetectThread(JavaVM rmidProcess) {
this.rmidProcess = rmidProcess;
}
public void run() {
diff --git a/jdk/test/java/rmi/activation/checkusage/CheckUsage.java b/jdk/test/java/rmi/activation/checkusage/CheckUsage.java
index 2b514e1f370..c114928d201 100644
--- a/jdk/test/java/rmi/activation/checkusage/CheckUsage.java
+++ b/jdk/test/java/rmi/activation/checkusage/CheckUsage.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
/* @test
* @bug 4259564
+ * @summary RMID's usage message is incomplete and inconsistent with other tools
*
* @library ../../testlibrary
* @build TestLibrary JavaVM
@@ -37,23 +38,16 @@ import java.io.ByteArrayOutputStream;
*/
public class CheckUsage {
public static void main(String[] args) {
-
- System.err.println("\nregression test for 4259564\n");
-
- JavaVM rmidVM = null;
-
try {
- // make sure the registry exits with a proper usage statement
ByteArrayOutputStream berr = new ByteArrayOutputStream();
- // run a VM to start the registry
- rmidVM = new JavaVM("sun.rmi.server.Activation", "", "foo",
- System.out, berr);
+ // create rmid with incorrect command line args
+ JavaVM rmidVM = new JavaVM("sun.rmi.server.Activation", "", "foo",
+ System.out, berr);
System.err.println("starting rmid");
- rmidVM.start();
- // wait for registry exit
- int rmidVMExitStatus = rmidVM.getVM().waitFor();
+ // run the subprocess and wait for it to exit
+ int rmidVMExitStatus = rmidVM.execute();
System.err.println("rmid exited with status: " +
rmidVMExitStatus);
@@ -66,12 +60,8 @@ public class CheckUsage {
} else {
System.err.println("test passed");
}
-
} catch (Exception e) {
TestLibrary.bomb(e);
- } finally {
- rmidVM.destroy();
- rmidVM = null;
}
}
}
diff --git a/jdk/test/java/rmi/registry/altSecurityManager/AltSecurityManager.java b/jdk/test/java/rmi/registry/altSecurityManager/AltSecurityManager.java
index 08d030ec876..351042965de 100644
--- a/jdk/test/java/rmi/registry/altSecurityManager/AltSecurityManager.java
+++ b/jdk/test/java/rmi/registry/altSecurityManager/AltSecurityManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2013, 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
@@ -76,8 +76,7 @@ public class AltSecurityManager implements Runnable {
}
System.err.println("starting " + utilityToStart);
- vm.start();
- vm.getVM().waitFor();
+ vm.execute();
} catch (Exception e) {
TestLibrary.bomb(e);
diff --git a/jdk/test/java/rmi/registry/checkusage/CheckUsage.java b/jdk/test/java/rmi/registry/checkusage/CheckUsage.java
index 19dac5b600a..88d9a900cdd 100644
--- a/jdk/test/java/rmi/registry/checkusage/CheckUsage.java
+++ b/jdk/test/java/rmi/registry/checkusage/CheckUsage.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2013, 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
@@ -35,34 +35,21 @@ import java.io.ByteArrayOutputStream;
/**
* Make sure that the rmiregistry prints out a correct usage statement
- * when run with an incorrect command line; test written to conform to
- * new tighter bug fix/regression test guidelines.
+ * when run with an incorrect command line.
*/
public class CheckUsage {
public static void main(String[] args) {
- System.err.println("\nregression test for 4151966\n");
-
- JavaVM registryVM = null;
-
try {
- // make sure the registry exits with a proper usage statement
ByteArrayOutputStream berr = new ByteArrayOutputStream();
// run a VM to start the registry
- registryVM = new JavaVM("sun.rmi.registry.RegistryImpl",
- "", "foo",
- System.out, berr);
+ JavaVM registryVM = new JavaVM("sun.rmi.registry.RegistryImpl",
+ "", "foo",
+ System.out, berr);
System.err.println("starting registry");
- registryVM.start();
-
- // wait for registry exit
System.err.println(" registry exited with status: " +
- registryVM.getVM().waitFor());
- try {
- Thread.sleep(7000);
- } catch (InterruptedException ie) {
- }
+ registryVM.execute());
String usage = new String(berr.toByteArray());
@@ -75,9 +62,6 @@ public class CheckUsage {
}
} catch (Exception e) {
TestLibrary.bomb(e);
- } finally {
- registryVM.destroy();
- registryVM = null;
}
}
}
diff --git a/jdk/test/java/rmi/registry/reexport/Reexport.java b/jdk/test/java/rmi/registry/reexport/Reexport.java
index c209f7c55b8..3841178533e 100644
--- a/jdk/test/java/rmi/registry/reexport/Reexport.java
+++ b/jdk/test/java/rmi/registry/reexport/Reexport.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2013, 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
@@ -122,8 +122,7 @@ public class Reexport {
try {
JavaVM jvm = new JavaVM("RegistryRunner", "", Integer.toString(p));
jvm.start();
- Reexport.subreg = jvm.getVM();
-
+ Reexport.subreg = jvm;
} catch (IOException e) {
// one of these is summarily dropped, can't remember which one
System.out.println ("Test setup failed - cannot run rmiregistry");
@@ -135,7 +134,8 @@ public class Reexport {
} catch (Exception whatever) {
}
}
- private static Process subreg = null;
+
+ private static JavaVM subreg = null;
public static void killRegistry(int port) {
if (Reexport.subreg != null) {
diff --git a/jdk/test/java/rmi/testlibrary/JavaVM.java b/jdk/test/java/rmi/testlibrary/JavaVM.java
index 6ccae911a86..c363f8e4420 100644
--- a/jdk/test/java/rmi/testlibrary/JavaVM.java
+++ b/jdk/test/java/rmi/testlibrary/JavaVM.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2013, 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
@@ -41,6 +41,8 @@ public class JavaVM {
private OutputStream outputStream = System.out;
private OutputStream errorStream = System.err;
private String policyFileName = null;
+ private StreamPipe outPipe;
+ private StreamPipe errPipe;
private static void mesg(Object mesg) {
System.err.println("JAVAVM: " + mesg.toString());
@@ -145,13 +147,12 @@ public class JavaVM {
}
mesg("command = " + Arrays.asList(javaCommand).toString());
- System.err.println("");
vm = Runtime.getRuntime().exec(javaCommand);
/* output from the execed process may optionally be captured. */
- StreamPipe.plugTogether(vm.getInputStream(), this.outputStream);
- StreamPipe.plugTogether(vm.getErrorStream(), this.errorStream);
+ outPipe = StreamPipe.plugTogether(vm.getInputStream(), this.outputStream);
+ errPipe = StreamPipe.plugTogether(vm.getErrorStream(), this.errorStream);
}
public void destroy() {
@@ -161,7 +162,25 @@ public class JavaVM {
vm = null;
}
- protected Process getVM() {
- return vm;
+ /**
+ * Waits for the subprocess to exit, joins the pipe threads to ensure that
+ * all output is collected, and returns its exit status.
+ */
+ public int waitFor() throws InterruptedException {
+ if (vm == null)
+ throw new IllegalStateException("can't wait for JavaVM that hasn't started");
+
+ int status = vm.waitFor();
+ outPipe.join();
+ errPipe.join();
+ return status;
+ }
+
+ /**
+ * Starts the subprocess, waits for it to exit, and returns its exit status.
+ */
+ public int execute() throws IOException, InterruptedException {
+ start();
+ return waitFor();
}
}
diff --git a/jdk/test/java/rmi/testlibrary/RMID.java b/jdk/test/java/rmi/testlibrary/RMID.java
index e963c45c976..8b0f3e26bd4 100644
--- a/jdk/test/java/rmi/testlibrary/RMID.java
+++ b/jdk/test/java/rmi/testlibrary/RMID.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2013, 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
@@ -202,8 +202,6 @@ public class RMID extends JavaVM {
public void start(long waitTime) throws IOException {
- if (getVM() != null) return;
-
// if rmid is already running, then the test will fail with
// a well recognized exception (port already in use...).
diff --git a/jdk/test/java/rmi/transport/checkFQDN/CheckFQDN.java b/jdk/test/java/rmi/transport/checkFQDN/CheckFQDN.java
index 9660f532c39..deceb2795f9 100644
--- a/jdk/test/java/rmi/transport/checkFQDN/CheckFQDN.java
+++ b/jdk/test/java/rmi/transport/checkFQDN/CheckFQDN.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2013, 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
@@ -114,6 +114,7 @@ public class CheckFQDN extends UnicastRemoteObject
equal = "=";
}
+ // create a client to tell checkFQDN what its rmi name is.
JavaVM jvm = new JavaVM("CheckFQDNClient",
propOption + property +
equal +
@@ -125,10 +126,7 @@ public class CheckFQDN extends UnicastRemoteObject
propertyBeingTested=property;
propertyBeingTestedValue=propertyValue;
- // create a client to tell checkFQDN what its rmi name is. */
- jvm.start();
-
- if (jvm.getVM().waitFor() != 0 ) {
+ if (jvm.execute() != 0) {
TestLibrary.bomb("Test failed, error in client.");
}
diff --git a/jdk/test/java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java b/jdk/test/java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java
index 52fd7df9295..b32a8a51b0a 100644
--- a/jdk/test/java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java
+++ b/jdk/test/java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2013, 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
@@ -102,9 +102,8 @@ public class CheckLeaseLeak extends UnicastRemoteObject implements LeaseLeak {
" -Drmi.registry.port=" +
registryPort,
"");
- jvm.start();
- if (jvm.getVM().waitFor() == 1 ) {
+ if (jvm.execute() != 0) {
TestLibrary.bomb("Client process failed");
}
}
diff --git a/jdk/test/sun/rmi/runtime/Log/4504153/Test4504153.java b/jdk/test/sun/rmi/runtime/Log/4504153/Test4504153.java
index 090718083d7..946e9a9c0ac 100644
--- a/jdk/test/sun/rmi/runtime/Log/4504153/Test4504153.java
+++ b/jdk/test/sun/rmi/runtime/Log/4504153/Test4504153.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2013, 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
@@ -48,8 +48,7 @@ public class Test4504153 {
ByteArrayOutputStream err = new ByteArrayOutputStream();
JavaVM vm = new JavaVM(StartRegistry.class.getName(),
"-Dsun.rmi.transport.logLevel=v", "", out, err);
- vm.start();
- vm.getVM().waitFor();
+ vm.execute();
String errString = err.toString();
diff --git a/jdk/test/sun/rmi/runtime/Log/6409194/NoConsoleOutput.java b/jdk/test/sun/rmi/runtime/Log/6409194/NoConsoleOutput.java
index a4104f2d268..70505fab6f2 100644
--- a/jdk/test/sun/rmi/runtime/Log/6409194/NoConsoleOutput.java
+++ b/jdk/test/sun/rmi/runtime/Log/6409194/NoConsoleOutput.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2013, 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
@@ -65,8 +65,7 @@ public class NoConsoleOutput {
JavaVM vm = new JavaVM(DoRMIStuff.class.getName(),
"-Djava.util.logging.config.file=" + loggingPropertiesFile,
"", out, err);
- vm.start();
- vm.getVM().waitFor();
+ vm.execute();
/*
* Verify that the subprocess had no System.out or System.err
diff --git a/jdk/test/sun/rmi/transport/tcp/DeadCachedConnection.java b/jdk/test/sun/rmi/transport/tcp/DeadCachedConnection.java
index 7bcd5a71024..ebc92f61ef1 100644
--- a/jdk/test/sun/rmi/transport/tcp/DeadCachedConnection.java
+++ b/jdk/test/sun/rmi/transport/tcp/DeadCachedConnection.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2013, 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
@@ -104,7 +104,7 @@ public class DeadCachedConnection {
JavaVM jvm =
new JavaVM("sun.rmi.registry.RegistryImpl", "", Integer.toString(p));
jvm.start();
- DeadCachedConnection.subreg = jvm.getVM();
+ DeadCachedConnection.subreg = jvm;
} catch (IOException e) {
// one of these is summarily dropped, can't remember which one
@@ -117,7 +117,7 @@ public class DeadCachedConnection {
} catch (Exception whatever) {
}
}
- private static Process subreg = null;
+ private static JavaVM subreg = null;
public static void killRegistry() {
if (DeadCachedConnection.subreg != null) {
From d9c892c9fd2cb2a2400bae0b083cf29d61cafa71 Mon Sep 17 00:00:00 2001
From: Weijun Wang
Date: Tue, 8 Jan 2013 14:54:56 +0800
Subject: [PATCH 26/53] 8005447: default principal should act as anyone
Reviewed-by: valeriep
---
.../jgss/krb5/InitSecContextToken.java | 4 +-
.../jgss/krb5/Krb5AcceptCredential.java | 23 +-
.../sun/security/jgss/krb5/Krb5Context.java | 19 +-
.../security/jgss/krb5/Krb5MechFactory.java | 2 +-
.../sun/security/jgss/krb5/Krb5Util.java | 109 ---------
.../sun/security/jgss/krb5/ServiceCreds.java | 229 ++++++++++++++++++
.../sun/security/jgss/krb5/SubjectComber.java | 48 ++--
.../classes/sun/security/krb5/KrbApReq.java | 8 +-
.../security/krb5/internal/ktab/KeyTab.java | 8 +-
.../sun/security/ssl/krb5/Krb5ProxyImpl.java | 3 +-
.../krb5/ServiceCredsCombination.java | 133 ++++++++++
.../security/krb5/auto/AcceptPermissions.java | 147 +++++++++++
.../sun/security/krb5/auto/CleanState.java | 1 +
jdk/test/sun/security/krb5/auto/Context.java | 32 ++-
.../security/krb5/auto/DiffNameSameKey.java | 91 +++++++
.../sun/security/krb5/auto/DynamicKeytab.java | 1 +
jdk/test/sun/security/krb5/auto/KDC.java | 14 +-
.../sun/security/krb5/auto/KeyTabCompat.java | 2 +-
.../sun/security/krb5/auto/TwoOrThree.java | 82 +++++++
19 files changed, 787 insertions(+), 169 deletions(-)
create mode 100644 jdk/src/share/classes/sun/security/jgss/krb5/ServiceCreds.java
create mode 100644 jdk/test/sun/security/krb5/ServiceCredsCombination.java
create mode 100644 jdk/test/sun/security/krb5/auto/AcceptPermissions.java
create mode 100644 jdk/test/sun/security/krb5/auto/DiffNameSameKey.java
create mode 100644 jdk/test/sun/security/krb5/auto/TwoOrThree.java
diff --git a/jdk/src/share/classes/sun/security/jgss/krb5/InitSecContextToken.java b/jdk/src/share/classes/sun/security/jgss/krb5/InitSecContextToken.java
index edd4bcf7c45..ff2154ffce0 100644
--- a/jdk/src/share/classes/sun/security/jgss/krb5/InitSecContextToken.java
+++ b/jdk/src/share/classes/sun/security/jgss/krb5/InitSecContextToken.java
@@ -86,7 +86,7 @@ class InitSecContextToken extends InitialToken {
* For the context acceptor to call. It reads the bytes out of an
* InputStream and constructs an InitSecContextToken with them.
*/
- InitSecContextToken(Krb5Context context, EncryptionKey[] keys,
+ InitSecContextToken(Krb5Context context, Krb5AcceptCredential cred,
InputStream is)
throws IOException, GSSException, KrbException {
@@ -105,7 +105,7 @@ class InitSecContextToken extends InitialToken {
if (context.getChannelBinding() != null) {
addr = context.getChannelBinding().getInitiatorAddress();
}
- apReq = new KrbApReq(apReqBytes, keys, addr);
+ apReq = new KrbApReq(apReqBytes, cred, addr);
//debug("\nReceived AP-REQ and authenticated it.\n");
EncryptionKey sessionKey = apReq.getCreds().getSessionKey();
diff --git a/jdk/src/share/classes/sun/security/jgss/krb5/Krb5AcceptCredential.java b/jdk/src/share/classes/sun/security/jgss/krb5/Krb5AcceptCredential.java
index 0f65137cecf..4a4d0fca89c 100644
--- a/jdk/src/share/classes/sun/security/jgss/krb5/Krb5AcceptCredential.java
+++ b/jdk/src/share/classes/sun/security/jgss/krb5/Krb5AcceptCredential.java
@@ -45,13 +45,10 @@ import javax.security.auth.DestroyFailedException;
public class Krb5AcceptCredential
implements Krb5CredElement {
- private static final long serialVersionUID = 7714332137352567952L;
+ private final Krb5NameElement name;
+ private final ServiceCreds screds;
- private Krb5NameElement name;
-
- private Krb5Util.ServiceCreds screds;
-
- private Krb5AcceptCredential(Krb5NameElement name, Krb5Util.ServiceCreds creds) {
+ private Krb5AcceptCredential(Krb5NameElement name, ServiceCreds creds) {
/*
* Initialize this instance with the data from the acquired
* KerberosKey. This class needs to be a KerberosKey too
@@ -69,11 +66,11 @@ public class Krb5AcceptCredential
name.getKrb5PrincipalName().getName());
final AccessControlContext acc = AccessController.getContext();
- Krb5Util.ServiceCreds creds = null;
+ ServiceCreds creds = null;
try {
creds = AccessController.doPrivileged(
- new PrivilegedExceptionAction() {
- public Krb5Util.ServiceCreds run() throws Exception {
+ new PrivilegedExceptionAction() {
+ public ServiceCreds run() throws Exception {
return Krb5Util.getServiceCreds(
caller == GSSCaller.CALLER_UNKNOWN ? GSSCaller.CALLER_ACCEPT: caller,
serverPrinc, acc);
@@ -92,8 +89,10 @@ public class Krb5AcceptCredential
if (name == null) {
String fullName = creds.getName();
- name = Krb5NameElement.getInstance(fullName,
+ if (fullName != null) {
+ name = Krb5NameElement.getInstance(fullName,
Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL);
+ }
}
return new Krb5AcceptCredential(name, creds);
@@ -153,8 +152,8 @@ public class Krb5AcceptCredential
return Krb5MechFactory.PROVIDER;
}
- EncryptionKey[] getKrb5EncryptionKeys() {
- return screds.getEKeys();
+ public EncryptionKey[] getKrb5EncryptionKeys(PrincipalName princ) {
+ return screds.getEKeys(princ);
}
/**
diff --git a/jdk/src/share/classes/sun/security/jgss/krb5/Krb5Context.java b/jdk/src/share/classes/sun/security/jgss/krb5/Krb5Context.java
index be8074097c9..309c1814bf3 100644
--- a/jdk/src/share/classes/sun/security/jgss/krb5/Krb5Context.java
+++ b/jdk/src/share/classes/sun/security/jgss/krb5/Krb5Context.java
@@ -818,16 +818,23 @@ class Krb5Context implements GSSContextSpi {
}
myName = (Krb5NameElement) myCred.getName();
- checkPermission(myName.getKrb5PrincipalName().getName(),
- "accept");
-
- EncryptionKey[] secretKeys =
- ((Krb5AcceptCredential) myCred).getKrb5EncryptionKeys();
+ // If there is already a bound name, check now
+ if (myName != null) {
+ Krb5MechFactory.checkAcceptCredPermission(myName, myName);
+ }
InitSecContextToken token = new InitSecContextToken(this,
- secretKeys, is);
+ (Krb5AcceptCredential) myCred, is);
PrincipalName clientName = token.getKrbApReq().getClient();
peerName = Krb5NameElement.getInstance(clientName);
+
+ // If unbound, check after the bound name is found
+ if (myName == null) {
+ myName = Krb5NameElement.getInstance(
+ token.getKrbApReq().getCreds().getServer());
+ Krb5MechFactory.checkAcceptCredPermission(myName, myName);
+ }
+
if (getMutualAuthState()) {
retVal = new AcceptSecContextToken(this,
token.getKrbApReq()).encode();
diff --git a/jdk/src/share/classes/sun/security/jgss/krb5/Krb5MechFactory.java b/jdk/src/share/classes/sun/security/jgss/krb5/Krb5MechFactory.java
index d9552a1ec6a..a1995293314 100644
--- a/jdk/src/share/classes/sun/security/jgss/krb5/Krb5MechFactory.java
+++ b/jdk/src/share/classes/sun/security/jgss/krb5/Krb5MechFactory.java
@@ -158,7 +158,7 @@ public final class Krb5MechFactory implements MechanismFactory {
public static void checkAcceptCredPermission(Krb5NameElement name,
GSSNameSpi originalName) {
SecurityManager sm = System.getSecurityManager();
- if (sm != null) {
+ if (sm != null && name != null) {
ServicePermission perm = new ServicePermission
(name.getKrb5PrincipalName().getName(), "accept");
try {
diff --git a/jdk/src/share/classes/sun/security/jgss/krb5/Krb5Util.java b/jdk/src/share/classes/sun/security/jgss/krb5/Krb5Util.java
index ec5bc9ca43b..f0495eef872 100644
--- a/jdk/src/share/classes/sun/security/jgss/krb5/Krb5Util.java
+++ b/jdk/src/share/classes/sun/security/jgss/krb5/Krb5Util.java
@@ -186,114 +186,6 @@ public class Krb5Util {
return subject;
}
- /**
- * Credentials of a service, the private secret to authenticate its
- * identity, which can be:
- * 1. Some KerberosKeys (generated from password)
- * 2. A KeyTab (for a typical service)
- * 3. A TGT (for S4U2proxy extension)
- *
- * Note that some creds can coexist. For example, a user2user service
- * can use its keytab (or keys) if the client can successfully obtain a
- * normal service ticket, otherwise, it can uses the TGT (actually, the
- * session key of the TGT) if the client can only acquire a service ticket
- * of ENC-TKT-IN-SKEY style.
- */
- public static class ServiceCreds {
- private KerberosPrincipal kp;
- private List ktabs;
- private List kk;
- private Subject subj;
- private KerberosTicket tgt;
-
- private static ServiceCreds getInstance(
- Subject subj, String serverPrincipal) {
-
- ServiceCreds sc = new ServiceCreds();
- sc.subj = subj;
-
- for (KerberosPrincipal p: subj.getPrincipals(KerberosPrincipal.class)) {
- if (serverPrincipal == null ||
- p.getName().equals(serverPrincipal)) {
- sc.kp = p;
- serverPrincipal = p.getName();
- break;
- }
- }
- if (sc.kp == null) {
- // Compatibility with old behavior: even when there is no
- // KerberosPrincipal, we can find one from KerberosKeys
- List keys = SubjectComber.findMany(
- subj, serverPrincipal, null, KerberosKey.class);
- if (!keys.isEmpty()) {
- sc.kp = keys.get(0).getPrincipal();
- serverPrincipal = sc.kp.getName();
- if (DEBUG) {
- System.out.println(">>> ServiceCreds: no kp?"
- + " find one from kk: " + serverPrincipal);
- }
- } else {
- return null;
- }
- }
- sc.ktabs = SubjectComber.findMany(
- subj, null, null, KeyTab.class);
- sc.kk = SubjectComber.findMany(
- subj, serverPrincipal, null, KerberosKey.class);
- sc.tgt = SubjectComber.find(
- subj, null, serverPrincipal, KerberosTicket.class);
- if (sc.ktabs.isEmpty() && sc.kk.isEmpty() && sc.tgt == null) {
- return null;
- }
- return sc;
- }
-
- public String getName() {
- return kp.getName();
- }
-
- public KerberosKey[] getKKeys() {
- List keys = new ArrayList<>();
- for (KerberosKey k: kk) {
- keys.add(k);
- }
- for (KeyTab ktab: ktabs) {
- for (KerberosKey k: ktab.getKeys(kp)) {
- keys.add(k);
- }
- }
- return keys.toArray(new KerberosKey[keys.size()]);
- }
-
- public EncryptionKey[] getEKeys() {
- KerberosKey[] kkeys = getKKeys();
- EncryptionKey[] ekeys = new EncryptionKey[kkeys.length];
- for (int i=0; i allPrincs;
+
+ // All private credentials that can be used
+ private List ktabs;
+ private List kk;
+ private KerberosTicket tgt;
+
+ private boolean destroyed;
+
+ private ServiceCreds() {
+ // Make sure this class cannot be instantiated externally.
+ }
+
+ /**
+ * Creates a ServiceCreds object based on info in a Subject for
+ * a given principal name (if specified).
+ * @return the object, or null if there is no private creds for it
+ */
+ public static ServiceCreds getInstance(
+ Subject subj, String serverPrincipal) {
+
+ ServiceCreds sc = new ServiceCreds();
+
+ sc.allPrincs =
+ subj.getPrincipals(KerberosPrincipal.class);
+
+ // Compatibility. A key implies its own principal
+ for (KerberosKey key: SubjectComber.findMany(
+ subj, serverPrincipal, null, KerberosKey.class)) {
+ sc.allPrincs.add(key.getPrincipal());
+ }
+
+ if (serverPrincipal != null) { // A named principal
+ sc.kp = new KerberosPrincipal(serverPrincipal);
+ } else {
+ if (sc.allPrincs.size() == 1) { // choose the only one
+ sc.kp = sc.allPrincs.iterator().next();
+ serverPrincipal = sc.kp.getName();
+ }
+ }
+
+ sc.ktabs = SubjectComber.findMany(
+ subj, serverPrincipal, null, KeyTab.class);
+ sc.kk = SubjectComber.findMany(
+ subj, serverPrincipal, null, KerberosKey.class);
+ sc.tgt = SubjectComber.find(
+ subj, null, serverPrincipal, KerberosTicket.class);
+ if (sc.ktabs.isEmpty() && sc.kk.isEmpty() && sc.tgt == null) {
+ return null;
+ }
+
+ sc.destroyed = false;
+
+ return sc;
+ }
+
+ // can be null
+ public String getName() {
+ if (destroyed) {
+ throw new IllegalStateException("This object is destroyed");
+ }
+ return kp == null ? null : kp.getName();
+ }
+
+ /**
+ * Gets keys for someone unknown.
+ * Used by TLS or as a fallback in getEKeys(). Can still return an
+ * empty array.
+ */
+ public KerberosKey[] getKKeys() {
+ if (destroyed) {
+ throw new IllegalStateException("This object is destroyed");
+ }
+ if (kp != null) {
+ return getKKeys(kp);
+ } else if (!allPrincs.isEmpty()) {
+ return getKKeys(allPrincs.iterator().next());
+ }
+ return new KerberosKey[0];
+ }
+
+ /**
+ * Get kkeys for a principal,
+ * @param princ the target name initiator requests. Not null.
+ * @return keys for the princ, never null, might be empty
+ */
+ private KerberosKey[] getKKeys(KerberosPrincipal princ) {
+ ArrayList keys = new ArrayList<>();
+ if (kp != null && !princ.equals(kp)) {
+ return new KerberosKey[0]; // Not me
+ }
+ if (!allPrincs.contains(princ)) {
+ return new KerberosKey[0]; // Not someone I know, This check
+ // is necessary but a KeyTab has
+ // no principal name recorded.
+ }
+ for (KerberosKey k: kk) {
+ if (k.getPrincipal().equals(princ)) {
+ keys.add(k);
+ }
+ }
+ for (KeyTab ktab: ktabs) {
+ for (KerberosKey k: ktab.getKeys(princ)) {
+ keys.add(k);
+ }
+ }
+ return keys.toArray(new KerberosKey[keys.size()]);
+ }
+
+ /**
+ * Gets EKeys for a principal.
+ * @param princ the target name initiator requests. Not null.
+ * @return keys for the princ, never null, might be empty
+ */
+ public EncryptionKey[] getEKeys(PrincipalName princ) {
+ if (destroyed) {
+ throw new IllegalStateException("This object is destroyed");
+ }
+ KerberosKey[] kkeys = getKKeys(new KerberosPrincipal(princ.getName()));
+ if (kkeys.length == 0) {
+ // Note: old JDK does not perform real name checking. If the
+ // acceptor starts by name A but initiator requests for B,
+ // as long as their keys match (i.e. A's keys can decrypt B's
+ // service ticket), the authentication is OK. There are real
+ // customers depending on this to use different names for a
+ // single service.
+ kkeys = getKKeys();
+ }
+ EncryptionKey[] ekeys = new EncryptionKey[kkeys.length];
+ for (int i=0; i answer = (oneOnly ? null : new ArrayList());
- if (credClass == KeyTab.class) { // Principal un-related
- // We are looking for credentials unrelated to serverPrincipal
- Iterator iterator =
- subject.getPrivateCredentials(credClass).iterator();
- while (iterator.hasNext()) {
- T t = iterator.next();
- if (DEBUG) {
- System.out.println("Found " + credClass.getSimpleName());
+ if (credClass == KeyTab.class) {
+ // TODO: There is currently no good way to filter out keytabs
+ // not for serverPrincipal. We can only check the principal
+ // set. If the server is not there, we can be sure none of the
+ // keytabs should be used, otherwise, use all for safety.
+ boolean useAll = false;
+ if (serverPrincipal != null) {
+ for (KerberosPrincipal princ:
+ subject.getPrincipals(KerberosPrincipal.class)) {
+ if (princ.getName().equals(serverPrincipal)) {
+ useAll = true;
+ break;
+ }
}
- if (oneOnly) {
- return t;
- } else {
- answer.add(t);
+ } else {
+ useAll = true;
+ }
+ if (useAll) {
+ Iterator iterator =
+ subject.getPrivateCredentials(KeyTab.class).iterator();
+ while (iterator.hasNext()) {
+ KeyTab t = iterator.next();
+ if (DEBUG) {
+ System.out.println("Found " + credClass.getSimpleName()
+ + " " + t);
+ }
+ if (oneOnly) {
+ return t;
+ } else {
+ answer.add(credClass.cast(t));
+ }
}
}
} else if (credClass == KerberosKey.class) {
@@ -114,11 +133,6 @@ class SubjectComber {
if (oneOnly) {
return t;
} else {
- if (serverPrincipal == null) {
- // Record name so that keys returned will all
- // belong to the same principal
- serverPrincipal = name;
- }
answer.add(credClass.cast(t));
}
}
diff --git a/jdk/src/share/classes/sun/security/krb5/KrbApReq.java b/jdk/src/share/classes/sun/security/krb5/KrbApReq.java
index f4e52d35f7d..535bb0dc52f 100644
--- a/jdk/src/share/classes/sun/security/krb5/KrbApReq.java
+++ b/jdk/src/share/classes/sun/security/krb5/KrbApReq.java
@@ -34,6 +34,7 @@ package sun.security.krb5;
import sun.security.krb5.internal.*;
import sun.security.krb5.internal.crypto.*;
import sun.security.krb5.internal.rcache.*;
+import sun.security.jgss.krb5.Krb5AcceptCredential;
import java.net.InetAddress;
import sun.security.util.*;
import java.io.IOException;
@@ -135,13 +136,13 @@ public class KrbApReq {
*/
// Used in InitSecContextToken (for AP_REQ and not TGS REQ)
public KrbApReq(byte[] message,
- EncryptionKey[] keys,
+ Krb5AcceptCredential cred,
InetAddress initiator)
throws KrbException, IOException {
obuf = message;
if (apReqMessg == null)
decode();
- authenticate(keys, initiator);
+ authenticate(cred, initiator);
}
/**
@@ -260,10 +261,11 @@ public class KrbApReq {
}
}
- private void authenticate(EncryptionKey[] keys, InetAddress initiator)
+ private void authenticate(Krb5AcceptCredential cred, InetAddress initiator)
throws KrbException, IOException {
int encPartKeyType = apReqMessg.ticket.encPart.getEType();
Integer kvno = apReqMessg.ticket.encPart.getKeyVersionNumber();
+ EncryptionKey[] keys = cred.getKrb5EncryptionKeys(apReqMessg.ticket.sname);
EncryptionKey dkey = EncryptionKey.findKey(encPartKeyType, kvno, keys);
if (dkey == null) {
diff --git a/jdk/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java b/jdk/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java
index b2a71ce6693..d1023de9de3 100644
--- a/jdk/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java
+++ b/jdk/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java
@@ -382,9 +382,15 @@ public class KeyTab implements KeyTabConstants {
*/
public void addEntry(PrincipalName service, char[] psswd,
int kvno, boolean append) throws KrbException {
+ addEntry(service, service.getSalt(), psswd, kvno, append);
+ }
+
+ // Called by KDC test
+ public void addEntry(PrincipalName service, String salt, char[] psswd,
+ int kvno, boolean append) throws KrbException {
EncryptionKey[] encKeys = EncryptionKey.acquireSecretKeys(
- psswd, service.getSalt());
+ psswd, salt);
// There should be only one maximum KVNO value for all etypes, so that
// all added keys can have the same KVNO.
diff --git a/jdk/src/share/classes/sun/security/ssl/krb5/Krb5ProxyImpl.java b/jdk/src/share/classes/sun/security/ssl/krb5/Krb5ProxyImpl.java
index bc22a77a93b..7f9a7984b98 100644
--- a/jdk/src/share/classes/sun/security/ssl/krb5/Krb5ProxyImpl.java
+++ b/jdk/src/share/classes/sun/security/ssl/krb5/Krb5ProxyImpl.java
@@ -36,6 +36,7 @@ import javax.security.auth.login.LoginException;
import sun.security.jgss.GSSCaller;
import sun.security.jgss.krb5.Krb5Util;
+import sun.security.jgss.krb5.ServiceCreds;
import sun.security.krb5.PrincipalName;
import sun.security.ssl.Krb5Proxy;
@@ -62,7 +63,7 @@ public class Krb5ProxyImpl implements Krb5Proxy {
@Override
public SecretKey[] getServerKeys(AccessControlContext acc)
throws LoginException {
- Krb5Util.ServiceCreds serviceCreds =
+ ServiceCreds serviceCreds =
Krb5Util.getServiceCreds(GSSCaller.CALLER_SSL_SERVER, null, acc);
return serviceCreds != null ? serviceCreds.getKKeys() :
new KerberosKey[0];
diff --git a/jdk/test/sun/security/krb5/ServiceCredsCombination.java b/jdk/test/sun/security/krb5/ServiceCredsCombination.java
new file mode 100644
index 00000000000..3208560e788
--- /dev/null
+++ b/jdk/test/sun/security/krb5/ServiceCredsCombination.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2012, 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 8005447
+ * @compile -XDignore.symbol.file ServiceCredsCombination.java
+ * @run main ServiceCredsCombination
+ * @summary default principal can act as anyone
+ */
+
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.Objects;
+import javax.security.auth.Subject;
+import javax.security.auth.kerberos.KerberosKey;
+import javax.security.auth.kerberos.KerberosPrincipal;
+import javax.security.auth.kerberos.KeyTab;
+import org.ietf.jgss.GSSCredential;
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.GSSManager;
+import org.ietf.jgss.GSSName;
+import sun.security.jgss.GSSUtil;
+
+public class ServiceCredsCombination {
+
+ public static void main(String[] args) throws Exception {
+ // pass
+ check("a", "a", princ("a"), key("a"));
+ check(null, "a", princ("a"), key("a"));
+ check("x", "NOCRED", princ("a"), key("a"));
+ // two pass
+ check("a", "a", princ("a"), key("a"), princ("b"), key("b"));
+ check("b", "b", princ("a"), key("a"), princ("b"), key("b"));
+ check(null, null, princ("a"), key("a"), princ("b"), key("b"));
+ check("x", "NOCRED", princ("a"), key("a"), princ("b"), key("b"));
+ // old ktab
+ check("b", "b", princ("b"), oldktab());
+ check("x", "NOCRED", princ("b"), oldktab());
+ check(null, "b", princ("b"), oldktab());
+ // Two old ktab
+ check("a", "a", princ("a"), princ("b"), oldktab(), oldktab());
+ check("b", "b", princ("a"), princ("b"), oldktab(), oldktab());
+ check(null, null, princ("a"), princ("b"), oldktab(), oldktab());
+ check("x", "NOCRED", princ("a"), princ("b"), oldktab(), oldktab());
+ // pass + old ktab
+ check("a", "a", princ("a"), princ("b"), key("a"), oldktab());
+ check("b", "b", princ("a"), princ("b"), key("a"), oldktab());
+ check(null, null, princ("a"), princ("b"), key("a"), oldktab());
+ check("x", "NOCRED", princ("a"), princ("b"), key("a"), oldktab());
+ // Compatibility, automatically add princ for keys
+ check(null, "a", key("a"));
+ check("x", "NOCRED", key("a"));
+ check(null, "a", key("a"), oldktab());
+ check("x", "NOCRED", key("a"), oldktab());
+ // Limitation, "a" has no key, but we don't know oldktab() is for "b"
+ check("a", "a", princ("a"), princ("b"), oldktab());
+ }
+
+ /**
+ * Checks the correct bound
+ * @param a get a creds for this principal, null for default one
+ * @param b expected name, null for still unbound, "NOCRED" for no creds
+ * @param objs princs, keys and keytabs in the subject
+ */
+ private static void check(final String a, String b, Object... objs)
+ throws Exception {
+ Subject subj = new Subject();
+ for (Object obj: objs) {
+ if (obj instanceof KerberosPrincipal) {
+ subj.getPrincipals().add((KerberosPrincipal)obj);
+ } else if (obj instanceof KerberosKey || obj instanceof KeyTab) {
+ subj.getPrivateCredentials().add(obj);
+ }
+ }
+ final GSSManager man = GSSManager.getInstance();
+ try {
+ String result = Subject.doAs(
+ subj, new PrivilegedExceptionAction() {
+ @Override
+ public String run() throws GSSException {
+ GSSCredential cred = man.createCredential(
+ a == null ? null : man.createName(r(a), null),
+ GSSCredential.INDEFINITE_LIFETIME,
+ GSSUtil.GSS_KRB5_MECH_OID,
+ GSSCredential.ACCEPT_ONLY);
+ GSSName name = cred.getName();
+ return name == null ? null : name.toString();
+ }
+ });
+ if (!Objects.equals(result, r(b))) {
+ throw new Exception("Check failed: getInstance(" + a
+ + ") has name " + result + ", not " + b);
+ }
+ } catch (PrivilegedActionException e) {
+ if (!"NOCRED".equals(b)) {
+ throw new Exception("Check failed: getInstance(" + a
+ + ") is null " + ", but not one with name " + b);
+ }
+ }
+ }
+ private static String r(String s) {
+ return s == null ? null : (s+"@REALM");
+ }
+ private static KerberosPrincipal princ(String s) {
+ return new KerberosPrincipal(r(s));
+ }
+ private static KerberosKey key(String s) {
+ return new KerberosKey(princ(s), new byte[0], 0, 0);
+ }
+ private static KeyTab oldktab() {
+ return KeyTab.getInstance();
+ }
+}
diff --git a/jdk/test/sun/security/krb5/auto/AcceptPermissions.java b/jdk/test/sun/security/krb5/auto/AcceptPermissions.java
new file mode 100644
index 00000000000..3a6d422842f
--- /dev/null
+++ b/jdk/test/sun/security/krb5/auto/AcceptPermissions.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2012, 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 9999999
+ * @summary default principal can act as anyone
+ * @compile -XDignore.symbol.file AcceptPermissions.java
+ * @run main/othervm AcceptPermissions
+ */
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.security.Permission;
+import javax.security.auth.kerberos.ServicePermission;
+import sun.security.jgss.GSSUtil;
+import java.util.*;
+
+public class AcceptPermissions extends SecurityManager {
+
+ private static Map perms = new HashMap<>();
+ @Override
+ public void checkPermission(Permission perm) {
+ if (!(perm instanceof ServicePermission)) {
+ return;
+ }
+ ServicePermission sp = (ServicePermission)perm;
+ if (!sp.getActions().equals("accept")) {
+ return;
+ }
+ // We only care about accept ServicePermission in this test
+ try {
+ super.checkPermission(sp);
+ } catch (SecurityException se) {
+ if (perms.containsKey(sp)) {
+ perms.put(sp, "checked");
+ } else {
+ throw se; // We didn't expect this is needed
+ }
+ }
+ }
+
+ // Fills in permissions we are expecting
+ private static void initPerms(String... names) {
+ perms.clear();
+ for (String name: names) {
+ perms.put(new ServicePermission(
+ name + "@" + OneKDC.REALM, "accept"), "expected");
+ }
+ }
+
+ // Checks if they are all checked
+ private static void checkPerms() {
+ for (Map.Entry entry: perms.entrySet()) {
+ if (entry.getValue().equals("expected")) {
+ throw new RuntimeException(
+ "Expected but not used: " + entry.getKey());
+ }
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ System.setSecurityManager(new AcceptPermissions());
+ new OneKDC(null).writeJAASConf();
+ String two = "two {\n"
+ + " com.sun.security.auth.module.Krb5LoginModule required"
+ + " principal=\"" + OneKDC.SERVER + "\" useKeyTab=true"
+ + " isInitiator=false storeKey=true;\n"
+ + " com.sun.security.auth.module.Krb5LoginModule required"
+ + " principal=\"" + OneKDC.BACKEND + "\" useKeyTab=true"
+ + " isInitiator=false storeKey=true;\n"
+ + "};\n";
+ Files.write(Paths.get(OneKDC.JAAS_CONF), two.getBytes(),
+ StandardOpenOption.APPEND);
+
+ Context c, s;
+
+ // In all cases, a ServicePermission on the acceptor name is needed
+ // for a handshake. For default principal with no predictable name,
+ // permission not needed (yet) for credentials creation.
+
+ // Named principal
+ initPerms(OneKDC.SERVER);
+ c = Context.fromJAAS("client");
+ s = Context.fromJAAS("server");
+ c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID);
+ s.startAsServer(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID);
+ checkPerms();
+ initPerms(OneKDC.SERVER);
+ Context.handshake(c, s);
+ checkPerms();
+
+ // Named principal (even if there are 2 JAAS modules)
+ initPerms(OneKDC.SERVER);
+ c = Context.fromJAAS("client");
+ s = Context.fromJAAS("two");
+ c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID);
+ s.startAsServer(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID);
+ checkPerms();
+ initPerms(OneKDC.SERVER);
+ Context.handshake(c, s);
+ checkPerms();
+
+ // Default principal with a predictable name
+ initPerms(OneKDC.SERVER);
+ c = Context.fromJAAS("client");
+ s = Context.fromJAAS("server");
+ c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID);
+ s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID);
+ checkPerms();
+ initPerms(OneKDC.SERVER);
+ Context.handshake(c, s);
+ checkPerms();
+
+ // Default principal with no predictable name
+ initPerms(); // permission not needed for cred !!!
+ c = Context.fromJAAS("client");
+ s = Context.fromJAAS("two");
+ c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID);
+ s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID);
+ checkPerms();
+ initPerms(OneKDC.SERVER); // still needed for handshake !!!
+ Context.handshake(c, s);
+ checkPerms();
+ }
+}
diff --git a/jdk/test/sun/security/krb5/auto/CleanState.java b/jdk/test/sun/security/krb5/auto/CleanState.java
index fbd8785cbab..d87325456e6 100644
--- a/jdk/test/sun/security/krb5/auto/CleanState.java
+++ b/jdk/test/sun/security/krb5/auto/CleanState.java
@@ -24,6 +24,7 @@
/*
* @test
* @bug 6716534
+ * @compile -XDignore.symbol.file CleanState.java
* @run main/othervm CleanState
* @summary Krb5LoginModule has not cleaned temp info between authentication attempts
*/
diff --git a/jdk/test/sun/security/krb5/auto/Context.java b/jdk/test/sun/security/krb5/auto/Context.java
index 7eef77c61c8..aae14f46bd3 100644
--- a/jdk/test/sun/security/krb5/auto/Context.java
+++ b/jdk/test/sun/security/krb5/auto/Context.java
@@ -131,21 +131,24 @@ public class Context {
return out;
}
+ /**
+ * Logins with username/password as a new Subject
+ */
public static Context fromUserPass(
String user, char[] pass, boolean storeKey) throws Exception {
- return fromUserPass(null, user, pass, storeKey);
+ return fromUserPass(new Subject(), user, pass, storeKey);
}
/**
- * Logins with a username and a password, using Krb5LoginModule directly
- * @param s existing subject, test multiple princ & creds for single subj
- * @param storeKey true if key should be saved, used on acceptor side
+ * Logins with username/password as an existing Subject. The
+ * same subject can be used multiple times to simulate multiple logins.
+ * @param s existing subject
*/
public static Context fromUserPass(Subject s,
String user, char[] pass, boolean storeKey) throws Exception {
Context out = new Context();
out.name = user;
- out.s = s == null ? new Subject() : s;
+ out.s = s;
Krb5LoginModule krb5 = new Krb5LoginModule();
Map map = new HashMap<>();
Map shared = new HashMap<>();
@@ -172,14 +175,23 @@ public class Context {
}
/**
- * Logins with a username and a keytab, using Krb5LoginModule directly
- * @param storeKey true if key should be saved, used on acceptor side
+ * Logins with username/keytab as an existing Subject. The
+ * same subject can be used multiple times to simulate multiple logins.
+ * @param s existing subject
*/
- public static Context fromUserKtab(String user, String ktab, boolean storeKey)
- throws Exception {
+ public static Context fromUserKtab(
+ String user, String ktab, boolean storeKey) throws Exception {
+ return fromUserKtab(new Subject(), user, ktab, storeKey);
+ }
+
+ /**
+ * Logins with username/keytab as a new subject,
+ */
+ public static Context fromUserKtab(Subject s,
+ String user, String ktab, boolean storeKey) throws Exception {
Context out = new Context();
out.name = user;
- out.s = new Subject();
+ out.s = s;
Krb5LoginModule krb5 = new Krb5LoginModule();
Map map = new HashMap<>();
diff --git a/jdk/test/sun/security/krb5/auto/DiffNameSameKey.java b/jdk/test/sun/security/krb5/auto/DiffNameSameKey.java
new file mode 100644
index 00000000000..92c487839c0
--- /dev/null
+++ b/jdk/test/sun/security/krb5/auto/DiffNameSameKey.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2012, 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 8005447
+ * @summary default principal can act as anyone
+ * @compile -XDignore.symbol.file DiffNameSameKey.java
+ * @run main/othervm/fail DiffNameSameKey a
+ * @run main/othervm DiffNameSameKey b
+ */
+
+import sun.security.jgss.GSSUtil;
+import sun.security.krb5.PrincipalName;
+
+/**
+ * This test confirms the compatibility codes described in
+ * ServiceCreds.getEKeys(). If the acceptor starts as x.us.oracle.com
+ * but client requests for x.us, as long as the KDC supports both names
+ * and the keys are the same, the auth should succeed.
+ */
+public class DiffNameSameKey {
+
+ static final String SERVER2 = "x" + OneKDC.SERVER;
+
+ public static void main(String[] args) throws Exception {
+
+ OneKDC kdc = new KDC2();
+ kdc.addPrincipal(SERVER2, "samepass".toCharArray());
+ kdc.addPrincipal(OneKDC.SERVER, "samepass".toCharArray());
+ kdc.writeJAASConf();
+ kdc.writeKtab(OneKDC.KTAB);
+
+ Context c, s;
+ c = Context.fromJAAS("client");
+ s = Context.fromJAAS("server");
+
+ switch (args[0]) {
+ case "a": // If server starts as another service, should fail
+ c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_SPNEGO_MECH_OID);
+ s.startAsServer(SERVER2.replace('/', '@'),
+ GSSUtil.GSS_SPNEGO_MECH_OID);
+ break;
+ case "b": // If client requests another server with the same keys,
+ // succeed to be compatible
+ c.startAsClient(SERVER2, GSSUtil.GSS_SPNEGO_MECH_OID);
+ s.startAsServer(OneKDC.SERVER.replace('/', '@'),
+ GSSUtil.GSS_SPNEGO_MECH_OID);
+ break;
+ }
+
+ Context.handshake(c, s);
+
+ s.dispose();
+ c.dispose();
+ }
+
+ /**
+ * This KDC returns the same salt for all principals. This means same
+ * passwords generate same keys.
+ */
+ static class KDC2 extends OneKDC {
+ KDC2() throws Exception {
+ super(null);
+ }
+ @Override
+ public String getSalt(PrincipalName pn) {
+ return "SAME";
+ }
+ }
+}
diff --git a/jdk/test/sun/security/krb5/auto/DynamicKeytab.java b/jdk/test/sun/security/krb5/auto/DynamicKeytab.java
index 6525b8fb49f..9c48fe44332 100644
--- a/jdk/test/sun/security/krb5/auto/DynamicKeytab.java
+++ b/jdk/test/sun/security/krb5/auto/DynamicKeytab.java
@@ -24,6 +24,7 @@
/*
* @test
* @bug 6894072
+ * @compile -XDignore.symbol.file DynamicKeytab.java
* @run main/othervm DynamicKeytab
* @summary always refresh keytab
*/
diff --git a/jdk/test/sun/security/krb5/auto/KDC.java b/jdk/test/sun/security/krb5/auto/KDC.java
index 409f3131fb8..83cafe73f8f 100644
--- a/jdk/test/sun/security/krb5/auto/KDC.java
+++ b/jdk/test/sun/security/krb5/auto/KDC.java
@@ -285,10 +285,12 @@ public class KDC {
if (Character.isDigit(pass[pass.length-1])) {
kvno = pass[pass.length-1] - '0';
}
- ktab.addEntry(new PrincipalName(name,
- name.indexOf('/') < 0 ?
- PrincipalName.KRB_NT_UNKNOWN :
- PrincipalName.KRB_NT_SRV_HST),
+ PrincipalName pn = new PrincipalName(name,
+ name.indexOf('/') < 0 ?
+ PrincipalName.KRB_NT_UNKNOWN :
+ PrincipalName.KRB_NT_SRV_HST);
+ ktab.addEntry(pn,
+ getSalt(pn),
pass,
kvno,
true);
@@ -534,7 +536,7 @@ public class KDC {
if (pass == null) {
throw new KrbException(server?
Krb5.KDC_ERR_S_PRINCIPAL_UNKNOWN:
- Krb5.KDC_ERR_C_PRINCIPAL_UNKNOWN);
+ Krb5.KDC_ERR_C_PRINCIPAL_UNKNOWN, pn.toString());
}
return pass;
}
@@ -544,7 +546,7 @@ public class KDC {
* @param p principal
* @return the salt
*/
- private String getSalt(PrincipalName p) {
+ protected String getSalt(PrincipalName p) {
String pn = p.toString();
if (p.getRealmString() == null) {
pn = pn + "@" + getRealm();
diff --git a/jdk/test/sun/security/krb5/auto/KeyTabCompat.java b/jdk/test/sun/security/krb5/auto/KeyTabCompat.java
index 87a3e7e9c78..ebc1c75c7e4 100644
--- a/jdk/test/sun/security/krb5/auto/KeyTabCompat.java
+++ b/jdk/test/sun/security/krb5/auto/KeyTabCompat.java
@@ -38,7 +38,7 @@ import sun.security.jgss.GSSUtil;
*
* 1. If there is only KerberosKeys in private credential set and no
* KerberosPrincipal. JAAS login should go on.
- * 2. Even if KeyTab is used, user can still get KerberosKeys from
+ * 2. If KeyTab is used, user won't get KerberosKeys from
* private credentials set.
*/
public class KeyTabCompat {
diff --git a/jdk/test/sun/security/krb5/auto/TwoOrThree.java b/jdk/test/sun/security/krb5/auto/TwoOrThree.java
new file mode 100644
index 00000000000..77f5e21b440
--- /dev/null
+++ b/jdk/test/sun/security/krb5/auto/TwoOrThree.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2012, 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 8005447
+ * @summary default principal can act as anyone
+ * @compile -XDignore.symbol.file TwoOrThree.java
+ * @run main/othervm TwoOrThree first first
+ * @run main/othervm/fail TwoOrThree first second
+ * @run main/othervm TwoOrThree - first
+ * @run main/othervm TwoOrThree - second
+ * @run main/othervm/fail TwoOrThree - third
+ */
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import javax.security.auth.Subject;
+import sun.security.jgss.GSSUtil;
+
+/*
+ * The JAAS login has two krb5 modules
+ * 1. principal is A
+ * 2. principal is B
+ * A named principal can only accept itself. The default principal can accept
+ * either, but not any other service even if the keytab also include its keys.
+ */
+public class TwoOrThree {
+
+ public static void main(String[] args) throws Exception {
+
+ String server = args[0].equals("-") ? null : args[0];
+ String target = args[1];
+ OneKDC kdc = new OneKDC(null);
+ kdc.addPrincipal("first", "first".toCharArray());
+ kdc.addPrincipal("second", "second".toCharArray());
+ kdc.addPrincipal("third", "third".toCharArray());
+ kdc.writeKtab(OneKDC.KTAB);
+
+ Context c = Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false);
+
+ // Using keytabs
+ Subject sub4s = new Subject();
+ Context.fromUserKtab(sub4s, "first", OneKDC.KTAB, true);
+ Context s = Context.fromUserKtab(sub4s, "second", OneKDC.KTAB, true);
+ c.startAsClient(target, GSSUtil.GSS_KRB5_MECH_OID);
+ s.startAsServer(server, GSSUtil.GSS_KRB5_MECH_OID);
+ Context.handshake(c, s);
+
+ // Using keys
+ sub4s = new Subject();
+ Context.fromUserPass(sub4s, "first", "first".toCharArray(), true);
+ s = Context.fromUserPass(sub4s, "second", "second".toCharArray(), true);
+ c.startAsClient(target, GSSUtil.GSS_KRB5_MECH_OID);
+ s.startAsServer(server, GSSUtil.GSS_KRB5_MECH_OID);
+ Context.handshake(c, s);
+
+ s.dispose();
+ c.dispose();
+ }
+}
From 159b251085a0f8e5429fb5e1716b215663b65e8f Mon Sep 17 00:00:00 2001
From: Maurizio Cimadamore
Date: Tue, 8 Jan 2013 10:15:30 +0100
Subject: [PATCH 27/53] 8005243: Restructure method check code to allow
pluggable checkers
Add interface to perform a method check - to be implemented by helper classes
Reviewed-by: jjg
---
.../com/sun/tools/javac/comp/Infer.java | 38 +-
.../com/sun/tools/javac/comp/Resolve.java | 348 +++++++++---------
2 files changed, 174 insertions(+), 212 deletions(-)
diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java
index 678e6216b4d..3c26e0d480a 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java
@@ -114,7 +114,7 @@ public class Infer {
}
}
- private final InferenceException inferenceException;
+ final InferenceException inferenceException;
/***************************************************************************
* Mini/Maximization of UndetVars
@@ -271,15 +271,19 @@ public class Infer {
boolean allowBoxing,
boolean useVarargs,
Resolve.MethodResolutionContext resolveContext,
+ Resolve.MethodCheck methodCheck,
Warner warn) throws InferenceException {
//-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG
final InferenceContext inferenceContext = new InferenceContext(tvars, this, true);
inferenceException.clear();
+ DeferredAttr.DeferredAttrContext deferredAttrContext =
+ resolveContext.deferredAttrContext(msym, inferenceContext);
+
try {
- rs.checkRawArgumentsAcceptable(env, msym, resolveContext.attrMode(), inferenceContext,
- argtypes, mt.getParameterTypes(), allowBoxing, useVarargs, warn,
- new InferenceCheckHandler(inferenceContext));
+ methodCheck.argumentsAcceptable(env, deferredAttrContext, argtypes, mt.getParameterTypes(), warn);
+
+ deferredAttrContext.complete();
// minimize as yet undetermined type variables
for (Type t : inferenceContext.undetvars) {
@@ -309,32 +313,6 @@ public class Infer {
inferenceContext.notifyChange(types);
}
}
- //where
-
- /** inference check handler **/
- class InferenceCheckHandler implements Resolve.MethodCheckHandler {
-
- InferenceContext inferenceContext;
-
- public InferenceCheckHandler(InferenceContext inferenceContext) {
- this.inferenceContext = inferenceContext;
- }
-
- public InapplicableMethodException arityMismatch() {
- return inferenceException.setMessage("infer.arg.length.mismatch", inferenceContext.inferenceVars());
- }
- public InapplicableMethodException argumentMismatch(boolean varargs, JCDiagnostic details) {
- String key = varargs ?
- "infer.varargs.argument.mismatch" :
- "infer.no.conforming.assignment.exists";
- return inferenceException.setMessage(key,
- inferenceContext.inferenceVars(), details);
- }
- public InapplicableMethodException inaccessibleVarargs(Symbol location, Type expected) {
- return inferenceException.setMessage("inaccessible.varargs.type",
- expected, Kinds.kindName(location), location);
- }
- }
/** check that type parameters are within their bounds.
*/
diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java
index 423f4dc4a45..236750cfec7 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java
@@ -506,6 +506,7 @@ public class Resolve {
List typeargtypes,
boolean allowBoxing,
boolean useVarargs,
+ MethodCheck methodCheck,
Warner warn) throws Infer.InferenceException {
Type mt = types.memberType(site, m);
@@ -558,10 +559,11 @@ public class Resolve {
allowBoxing,
useVarargs,
currentResolutionContext,
+ methodCheck,
warn);
- checkRawArgumentsAcceptable(env, m, argtypes, mt.getParameterTypes(),
- allowBoxing, useVarargs, warn);
+ methodCheck.argumentsAcceptable(env, currentResolutionContext.deferredAttrContext(m, infer.emptyContext),
+ argtypes, mt.getParameterTypes(), warn);
return mt;
}
@@ -578,7 +580,7 @@ public class Resolve {
currentResolutionContext.attrMode = DeferredAttr.AttrMode.CHECK;
MethodResolutionPhase step = currentResolutionContext.step = env.info.pendingResolutionPhase;
return rawInstantiate(env, site, m, resultInfo, argtypes, typeargtypes,
- step.isBoxingRequired(), step.isVarargsRequired(), warn);
+ step.isBoxingRequired(), step.isVarargsRequired(), resolveMethodCheck, warn);
}
finally {
currentResolutionContext = prevContext;
@@ -595,81 +597,66 @@ public class Resolve {
List typeargtypes,
boolean allowBoxing,
boolean useVarargs,
+ MethodCheck methodCheck,
Warner warn) {
try {
return rawInstantiate(env, site, m, resultInfo, argtypes, typeargtypes,
- allowBoxing, useVarargs, warn);
+ allowBoxing, useVarargs, methodCheck, warn);
} catch (InapplicableMethodException ex) {
return null;
}
}
- /** Check if a parameter list accepts a list of args.
+ /**
+ * This interface defines an entry point that should be used to perform a
+ * method check. A method check usually consist in determining as to whether
+ * a set of types (actuals) is compatible with another set of types (formals).
+ * Since the notion of compatibility can vary depending on the circumstances,
+ * this interfaces allows to easily add new pluggable method check routines.
*/
- boolean argumentsAcceptable(Env env,
- Symbol msym,
+ interface MethodCheck {
+ /**
+ * Main method check routine. A method check usually consist in determining
+ * as to whether a set of types (actuals) is compatible with another set of
+ * types (formals). If an incompatibility is found, an unchecked exception
+ * is assumed to be thrown.
+ */
+ void argumentsAcceptable(Env env,
+ DeferredAttrContext deferredAttrContext,
List argtypes,
List formals,
- boolean allowBoxing,
- boolean useVarargs,
- Warner warn) {
- try {
- checkRawArgumentsAcceptable(env, msym, argtypes, formals, allowBoxing, useVarargs, warn);
- return true;
- } catch (InapplicableMethodException ex) {
- return false;
+ Warner warn);
+ }
+
+ /**
+ * Helper enum defining all method check diagnostics (used by resolveMethodCheck).
+ */
+ enum MethodCheckDiag {
+ /**
+ * Actuals and formals differs in length.
+ */
+ ARITY_MISMATCH("arg.length.mismatch", "infer.arg.length.mismatch"),
+ /**
+ * An actual is incompatible with a formal.
+ */
+ ARG_MISMATCH("no.conforming.assignment.exists", "infer.no.conforming.assignment.exists"),
+ /**
+ * An actual is incompatible with the varargs element type.
+ */
+ VARARG_MISMATCH("varargs.argument.mismatch", "infer.varargs.argument.mismatch"),
+ /**
+ * The varargs element type is inaccessible.
+ */
+ INACCESSIBLE_VARARGS("inaccessible.varargs.type", "inaccessible.varargs.type");
+
+ final String basicKey;
+ final String inferKey;
+
+ MethodCheckDiag(String basicKey, String inferKey) {
+ this.basicKey = basicKey;
+ this.inferKey = inferKey;
}
}
- /**
- * A check handler is used by the main method applicability routine in order
- * to handle specific method applicability failures. It is assumed that a class
- * implementing this interface should throw exceptions that are a subtype of
- * InapplicableMethodException (see below). Such exception will terminate the
- * method applicability check and propagate important info outwards (for the
- * purpose of generating better diagnostics).
- */
- interface MethodCheckHandler {
- /* The number of actuals and formals differ */
- InapplicableMethodException arityMismatch();
- /* An actual argument type does not conform to the corresponding formal type */
- InapplicableMethodException argumentMismatch(boolean varargs, JCDiagnostic details);
- /* The element type of a varargs is not accessible in the current context */
- InapplicableMethodException inaccessibleVarargs(Symbol location, Type expected);
- }
-
- /**
- * Basic method check handler used within Resolve - all methods end up
- * throwing InapplicableMethodException; a diagnostic fragment that describes
- * the cause as to why the method is not applicable is set on the exception
- * before it is thrown.
- */
- MethodCheckHandler resolveHandler = new MethodCheckHandler() {
- public InapplicableMethodException arityMismatch() {
- return inapplicableMethodException.setMessage("arg.length.mismatch");
- }
- public InapplicableMethodException argumentMismatch(boolean varargs, JCDiagnostic details) {
- String key = varargs ?
- "varargs.argument.mismatch" :
- "no.conforming.assignment.exists";
- return inapplicableMethodException.setMessage(key,
- details);
- }
- public InapplicableMethodException inaccessibleVarargs(Symbol location, Type expected) {
- return inapplicableMethodException.setMessage("inaccessible.varargs.type",
- expected, Kinds.kindName(location), location);
- }
- };
-
- void checkRawArgumentsAcceptable(Env env,
- Symbol msym,
- List argtypes,
- List formals,
- boolean allowBoxing,
- boolean useVarargs,
- Warner warn) {
- checkRawArgumentsAcceptable(env, msym, currentResolutionContext.attrMode(), infer.emptyContext, argtypes, formals,
- allowBoxing, useVarargs, warn, resolveHandler);
- }
/**
* Main method applicability routine. Given a list of actual types A,
@@ -689,68 +676,94 @@ public class Resolve {
*
* A method check handler (see above) is used in order to report errors.
*/
- void checkRawArgumentsAcceptable(final Env env,
- Symbol msym,
- DeferredAttr.AttrMode mode,
- final Infer.InferenceContext inferenceContext,
- List argtypes,
- List formals,
- boolean allowBoxing,
- boolean useVarargs,
- Warner warn,
- final MethodCheckHandler handler) {
- Type varargsFormal = useVarargs ? formals.last() : null;
+ MethodCheck resolveMethodCheck = new MethodCheck() {
+ @Override
+ public void argumentsAcceptable(final Env env,
+ DeferredAttrContext deferredAttrContext,
+ List argtypes,
+ List formals,
+ Warner warn) {
+ //should we expand formals?
+ boolean useVarargs = deferredAttrContext.phase.isVarargsRequired();
- if (varargsFormal == null &&
- argtypes.size() != formals.size()) {
- throw handler.arityMismatch(); // not enough args
- }
+ //inference context used during this method check
+ InferenceContext inferenceContext = deferredAttrContext.inferenceContext;
- DeferredAttr.DeferredAttrContext deferredAttrContext =
- deferredAttr.new DeferredAttrContext(mode, msym, currentResolutionContext.step, inferenceContext);
+ Type varargsFormal = useVarargs ? formals.last() : null;
- while (argtypes.nonEmpty() && formals.head != varargsFormal) {
- ResultInfo mresult = methodCheckResult(formals.head, allowBoxing, false, inferenceContext, deferredAttrContext, handler, warn);
- mresult.check(null, argtypes.head);
- argtypes = argtypes.tail;
- formals = formals.tail;
- }
+ if (varargsFormal == null &&
+ argtypes.size() != formals.size()) {
+ report(MethodCheckDiag.ARITY_MISMATCH, inferenceContext); // not enough args
+ }
- if (formals.head != varargsFormal) {
- throw handler.arityMismatch(); // not enough args
- }
-
- if (useVarargs) {
- //note: if applicability check is triggered by most specific test,
- //the last argument of a varargs is _not_ an array type (see JLS 15.12.2.5)
- final Type elt = types.elemtype(varargsFormal);
- ResultInfo mresult = methodCheckResult(elt, allowBoxing, true, inferenceContext, deferredAttrContext, handler, warn);
- while (argtypes.nonEmpty()) {
+ while (argtypes.nonEmpty() && formals.head != varargsFormal) {
+ ResultInfo mresult = methodCheckResult(false, formals.head, deferredAttrContext, warn);
mresult.check(null, argtypes.head);
argtypes = argtypes.tail;
+ formals = formals.tail;
}
- //check varargs element type accessibility
- varargsAccessible(env, elt, handler, inferenceContext);
- }
- deferredAttrContext.complete();
- }
+ if (formals.head != varargsFormal) {
+ report(MethodCheckDiag.ARITY_MISMATCH, inferenceContext); // not enough args
+ }
- void varargsAccessible(final Env env, final Type t, final Resolve.MethodCheckHandler handler, final InferenceContext inferenceContext) {
- if (inferenceContext.free(t)) {
- inferenceContext.addFreeTypeListener(List.of(t), new FreeTypeListener() {
- @Override
- public void typesInferred(InferenceContext inferenceContext) {
- varargsAccessible(env, inferenceContext.asInstType(t, types), handler, inferenceContext);
+ if (useVarargs) {
+ //note: if applicability check is triggered by most specific test,
+ //the last argument of a varargs is _not_ an array type (see JLS 15.12.2.5)
+ final Type elt = types.elemtype(varargsFormal);
+ ResultInfo mresult = methodCheckResult(true, elt, deferredAttrContext, warn);
+ while (argtypes.nonEmpty()) {
+ mresult.check(null, argtypes.head);
+ argtypes = argtypes.tail;
}
- });
- } else {
- if (!isAccessible(env, t)) {
- Symbol location = env.enclClass.sym;
- throw handler.inaccessibleVarargs(location, t);
+ //check varargs element type accessibility
+ varargsAccessible(env, elt, inferenceContext);
}
}
- }
+
+ private void report(MethodCheckDiag diag, InferenceContext inferenceContext, Object... args) {
+ boolean inferDiag = inferenceContext != infer.emptyContext;
+ InapplicableMethodException ex = inferDiag ?
+ infer.inferenceException : inapplicableMethodException;
+ if (inferDiag && (!diag.inferKey.equals(diag.basicKey))) {
+ Object[] args2 = new Object[args.length + 1];
+ System.arraycopy(args, 0, args2, 1, args.length);
+ args2[0] = inferenceContext.inferenceVars();
+ args = args2;
+ }
+ throw ex.setMessage(inferDiag ? diag.inferKey : diag.basicKey, args);
+ }
+
+ private void varargsAccessible(final Env env, final Type t, final InferenceContext inferenceContext) {
+ if (inferenceContext.free(t)) {
+ inferenceContext.addFreeTypeListener(List.of(t), new FreeTypeListener() {
+ @Override
+ public void typesInferred(InferenceContext inferenceContext) {
+ varargsAccessible(env, inferenceContext.asInstType(t, types), inferenceContext);
+ }
+ });
+ } else {
+ if (!isAccessible(env, t)) {
+ Symbol location = env.enclClass.sym;
+ report(MethodCheckDiag.INACCESSIBLE_VARARGS, inferenceContext, t, Kinds.kindName(location), location);
+ }
+ }
+ }
+
+ private ResultInfo methodCheckResult(final boolean varargsCheck, Type to,
+ final DeferredAttr.DeferredAttrContext deferredAttrContext, Warner rsWarner) {
+ CheckContext checkContext = new MethodCheckContext(!deferredAttrContext.phase.isBoxingRequired(), deferredAttrContext, rsWarner) {
+ MethodCheckDiag methodDiag = varargsCheck ?
+ MethodCheckDiag.VARARG_MISMATCH : MethodCheckDiag.ARG_MISMATCH;
+
+ @Override
+ public void report(DiagnosticPosition pos, JCDiagnostic details) {
+ report(methodDiag, deferredAttrContext.inferenceContext, details);
+ }
+ };
+ return new MethodResultInfo(to, checkContext);
+ }
+ };
/**
* Check context to be used during method applicability checks. A method check
@@ -758,23 +771,24 @@ public class Resolve {
*/
abstract class MethodCheckContext implements CheckContext {
- MethodCheckHandler handler;
- boolean useVarargs;
- Infer.InferenceContext inferenceContext;
+ boolean strict;
DeferredAttrContext deferredAttrContext;
Warner rsWarner;
- public MethodCheckContext(MethodCheckHandler handler, boolean useVarargs,
- Infer.InferenceContext inferenceContext, DeferredAttrContext deferredAttrContext, Warner rsWarner) {
- this.handler = handler;
- this.useVarargs = useVarargs;
- this.inferenceContext = inferenceContext;
- this.deferredAttrContext = deferredAttrContext;
- this.rsWarner = rsWarner;
+ public MethodCheckContext(boolean strict, DeferredAttrContext deferredAttrContext, Warner rsWarner) {
+ this.strict = strict;
+ this.deferredAttrContext = deferredAttrContext;
+ this.rsWarner = rsWarner;
+ }
+
+ public boolean compatible(Type found, Type req, Warner warn) {
+ return strict ?
+ types.isSubtypeUnchecked(found, deferredAttrContext.inferenceContext.asFree(req, types), warn) :
+ types.isConvertible(found, deferredAttrContext.inferenceContext.asFree(req, types), warn);
}
public void report(DiagnosticPosition pos, JCDiagnostic details) {
- throw handler.argumentMismatch(useVarargs, details);
+ throw inapplicableMethodException.setMessage(details);
}
public Warner checkWarner(DiagnosticPosition pos, Type found, Type req) {
@@ -782,7 +796,7 @@ public class Resolve {
}
public InferenceContext inferenceContext() {
- return inferenceContext;
+ return deferredAttrContext.inferenceContext;
}
public DeferredAttrContext deferredAttrContext() {
@@ -791,56 +805,13 @@ public class Resolve {
}
/**
- * Subclass of method check context class that implements strict method conversion.
- * Strict method conversion checks compatibility between types using subtyping tests.
+ * ResultInfo class to be used during method applicability checks. Check
+ * for deferred types goes through special path.
*/
- class StrictMethodContext extends MethodCheckContext {
-
- public StrictMethodContext(MethodCheckHandler handler, boolean useVarargs,
- Infer.InferenceContext inferenceContext, DeferredAttrContext deferredAttrContext, Warner rsWarner) {
- super(handler, useVarargs, inferenceContext, deferredAttrContext, rsWarner);
- }
-
- public boolean compatible(Type found, Type req, Warner warn) {
- return types.isSubtypeUnchecked(found, inferenceContext.asFree(req, types), warn);
- }
- }
-
- /**
- * Subclass of method check context class that implements loose method conversion.
- * Loose method conversion checks compatibility between types using method conversion tests.
- */
- class LooseMethodContext extends MethodCheckContext {
-
- public LooseMethodContext(MethodCheckHandler handler, boolean useVarargs,
- Infer.InferenceContext inferenceContext, DeferredAttrContext deferredAttrContext, Warner rsWarner) {
- super(handler, useVarargs, inferenceContext, deferredAttrContext, rsWarner);
- }
-
- public boolean compatible(Type found, Type req, Warner warn) {
- return types.isConvertible(found, inferenceContext.asFree(req, types), warn);
- }
- }
-
- /**
- * Create a method check context to be used during method applicability check
- */
- ResultInfo methodCheckResult(Type to, boolean allowBoxing, boolean useVarargs,
- Infer.InferenceContext inferenceContext, DeferredAttr.DeferredAttrContext deferredAttrContext,
- MethodCheckHandler methodHandler, Warner rsWarner) {
- MethodCheckContext checkContext = allowBoxing ?
- new LooseMethodContext(methodHandler, useVarargs, inferenceContext, deferredAttrContext, rsWarner) :
- new StrictMethodContext(methodHandler, useVarargs, inferenceContext, deferredAttrContext, rsWarner);
- return new MethodResultInfo(to, checkContext, deferredAttrContext);
- }
-
class MethodResultInfo extends ResultInfo {
- DeferredAttr.DeferredAttrContext deferredAttrContext;
-
- public MethodResultInfo(Type pt, CheckContext checkContext, DeferredAttr.DeferredAttrContext deferredAttrContext) {
+ public MethodResultInfo(Type pt, CheckContext checkContext) {
attr.super(VAL, pt, checkContext);
- this.deferredAttrContext = deferredAttrContext;
}
@Override
@@ -855,12 +826,12 @@ public class Resolve {
@Override
protected MethodResultInfo dup(Type newPt) {
- return new MethodResultInfo(newPt, checkContext, deferredAttrContext);
+ return new MethodResultInfo(newPt, checkContext);
}
@Override
protected ResultInfo dup(CheckContext newContext) {
- return new MethodResultInfo(pt, newContext, deferredAttrContext);
+ return new MethodResultInfo(pt, newContext);
}
}
@@ -1071,7 +1042,7 @@ public class Resolve {
Assert.check(sym.kind < AMBIGUOUS);
try {
Type mt = rawInstantiate(env, site, sym, null, argtypes, typeargtypes,
- allowBoxing, useVarargs, types.noWarnings);
+ allowBoxing, useVarargs, resolveMethodCheck, types.noWarnings);
if (!operator)
currentResolutionContext.addApplicableCandidate(sym, mt);
} catch (InapplicableMethodException ex) {
@@ -1274,12 +1245,19 @@ public class Resolve {
}
//where
private boolean invocationMoreSpecific(Env env, Type site, Symbol m2, List argtypes1, boolean allowBoxing, boolean useVarargs) {
- noteWarner.clear();
- Type mst = instantiate(env, site, m2, null,
- types.lowerBounds(argtypes1), null,
- allowBoxing, false, noteWarner);
- return mst != null &&
- !noteWarner.hasLint(Lint.LintCategory.UNCHECKED);
+ MethodResolutionContext prevContext = currentResolutionContext;
+ try {
+ currentResolutionContext = new MethodResolutionContext();
+ currentResolutionContext.step = allowBoxing ? BOX : BASIC;
+ noteWarner.clear();
+ Type mst = instantiate(env, site, m2, null,
+ types.lowerBounds(argtypes1), null,
+ allowBoxing, false, resolveMethodCheck, noteWarner);
+ return mst != null &&
+ !noteWarner.hasLint(Lint.LintCategory.UNCHECKED);
+ } finally {
+ currentResolutionContext = prevContext;
+ }
}
//where
private Symbol adjustVarargs(Symbol to, Symbol from, boolean useVarargs) {
@@ -2366,9 +2344,11 @@ public class Resolve {
try {
currentResolutionContext = new MethodResolutionContext();
Name name = treeinfo.operatorName(optag);
+ env.info.pendingResolutionPhase = currentResolutionContext.step = BASIC;
Symbol sym = findMethod(env, syms.predefClass.type, name, argtypes,
null, false, false, true);
if (boxingEnabled && sym.kind >= WRONG_MTHS)
+ env.info.pendingResolutionPhase = currentResolutionContext.step = BOX;
sym = findMethod(env, syms.predefClass.type, name, argtypes,
null, true, false, true);
return accessMethod(sym, pos, env.enclClass.sym.type, name,
@@ -3450,6 +3430,10 @@ public class Resolve {
candidates = candidates.append(c);
}
+ DeferredAttrContext deferredAttrContext(Symbol sym, InferenceContext inferenceContext) {
+ return deferredAttr.new DeferredAttrContext(attrMode, sym, step, inferenceContext);
+ }
+
/**
* This class represents an overload resolution candidate. There are two
* kinds of candidates: applicable methods and inapplicable methods;
From c932023b04da80aaad79c7554d4ce4c8bd93d4d6 Mon Sep 17 00:00:00 2001
From: Maurizio Cimadamore
Date: Tue, 8 Jan 2013 10:16:26 +0100
Subject: [PATCH 28/53] 8005179: Cleanup Resolve.AmbiguityError
Linearize nested ambiguity errors
Reviewed-by: jjg
---
.../com/sun/tools/javac/comp/Resolve.java | 154 +++++++++++-------
.../test/tools/javac/lambda/TargetType21.java | 2 +-
.../test/tools/javac/lambda/TargetType21.out | 2 +-
3 files changed, 93 insertions(+), 65 deletions(-)
diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java
index 236750cfec7..4b6cab1bf0e 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java
@@ -1122,52 +1122,20 @@ public class Resolve {
if (m1Abstract && !m2Abstract) return m2;
if (m2Abstract && !m1Abstract) return m1;
// both abstract or both concrete
- if (!m1Abstract && !m2Abstract)
- return ambiguityError(m1, m2);
- // check that both signatures have the same erasure
- if (!types.isSameTypes(m1.erasure(types).getParameterTypes(),
- m2.erasure(types).getParameterTypes()))
- return ambiguityError(m1, m2);
- // both abstract, neither overridden; merge throws clause and result type
- Type mst = mostSpecificReturnType(mt1, mt2);
- if (mst == null) {
- // Theoretically, this can't happen, but it is possible
- // due to error recovery or mixing incompatible class files
- return ambiguityError(m1, m2);
- }
- Symbol mostSpecific = mst == mt1 ? m1 : m2;
- List allThrown = chk.intersect(mt1.getThrownTypes(), mt2.getThrownTypes());
- Type newSig = types.createMethodTypeWithThrown(mostSpecific.type, allThrown);
- MethodSymbol result = new MethodSymbol(
- mostSpecific.flags(),
- mostSpecific.name,
- newSig,
- mostSpecific.owner) {
- @Override
- public MethodSymbol implementation(TypeSymbol origin, Types types, boolean checkResult) {
- if (origin == site.tsym)
- return this;
- else
- return super.implementation(origin, types, checkResult);
- }
- };
- return result;
+ return ambiguityError(m1, m2);
}
if (m1SignatureMoreSpecific) return m1;
if (m2SignatureMoreSpecific) return m2;
return ambiguityError(m1, m2);
case AMBIGUOUS:
+ //check if m1 is more specific than all ambiguous methods in m2
AmbiguityError e = (AmbiguityError)m2;
- Symbol err1 = mostSpecific(argtypes, m1, e.sym, env, site, allowBoxing, useVarargs);
- Symbol err2 = mostSpecific(argtypes, m1, e.sym2, env, site, allowBoxing, useVarargs);
- if (err1 == err2) return err1;
- if (err1 == e.sym && err2 == e.sym2) return m2;
- if (err1 instanceof AmbiguityError &&
- err2 instanceof AmbiguityError &&
- ((AmbiguityError)err1).sym == ((AmbiguityError)err2).sym)
- return ambiguityError(m1, m2);
- else
- return ambiguityError(err1, err2);
+ for (Symbol s : e.ambiguousSyms) {
+ if (mostSpecific(argtypes, m1, s, env, site, allowBoxing, useVarargs) != m1) {
+ return e.addAmbiguousSymbol(m1);
+ }
+ }
+ return m1;
default:
throw new AssertionError();
}
@@ -2504,6 +2472,10 @@ public class Resolve {
@Override
Symbol access(Env env, DiagnosticPosition pos, Symbol location, Symbol sym) {
+ if (sym.kind == AMBIGUOUS) {
+ AmbiguityError a_err = (AmbiguityError)sym;
+ sym = a_err.mergeAbstracts(site);
+ }
if (sym.kind >= AMBIGUOUS) {
//if nothing is found return the 'first' error
sym = accessMethod(sym, pos, location, site, name, true, argtypes, typeargtypes);
@@ -2559,6 +2531,10 @@ public class Resolve {
abstract JCMemberReference.ReferenceKind referenceKind(Symbol sym);
Symbol access(Env env, DiagnosticPosition pos, Symbol location, Symbol sym) {
+ if (sym.kind == AMBIGUOUS) {
+ AmbiguityError a_err = (AmbiguityError)sym;
+ sym = a_err.mergeAbstracts(site);
+ }
//skip error reporting
return sym;
}
@@ -2994,9 +2970,7 @@ public class Resolve {
@Override
public Symbol access(Name name, TypeSymbol location) {
- if (sym.kind >= AMBIGUOUS)
- return ((ResolveError)sym).access(name, location);
- else if ((sym.kind & ERRONEOUS) == 0 && (sym.kind & TYP) != 0)
+ if ((sym.kind & ERRONEOUS) == 0 && (sym.kind & TYP) != 0)
return types.createErrorType(name, location, sym.type).tsym;
else
return sym;
@@ -3318,14 +3292,32 @@ public class Resolve {
* (either methods, constructors or operands) are ambiguous
* given an actual arguments/type argument list.
*/
- class AmbiguityError extends InvalidSymbolError {
+ class AmbiguityError extends ResolveError {
/** The other maximally specific symbol */
- Symbol sym2;
+ List ambiguousSyms = List.nil();
+
+ @Override
+ public boolean exists() {
+ return true;
+ }
AmbiguityError(Symbol sym1, Symbol sym2) {
- super(AMBIGUOUS, sym1, "ambiguity error");
- this.sym2 = sym2;
+ super(AMBIGUOUS, "ambiguity error");
+ ambiguousSyms = flatten(sym2).appendList(flatten(sym1));
+ }
+
+ private List flatten(Symbol sym) {
+ if (sym.kind == AMBIGUOUS) {
+ return ((AmbiguityError)sym).ambiguousSyms;
+ } else {
+ return List.of(sym);
+ }
+ }
+
+ AmbiguityError addAmbiguousSymbol(Symbol s) {
+ ambiguousSyms = ambiguousSyms.prepend(s);
+ return this;
}
@Override
@@ -3336,24 +3328,60 @@ public class Resolve {
Name name,
List argtypes,
List typeargtypes) {
- AmbiguityError pair = this;
- while (true) {
- if (pair.sym.kind == AMBIGUOUS)
- pair = (AmbiguityError)pair.sym;
- else if (pair.sym2.kind == AMBIGUOUS)
- pair = (AmbiguityError)pair.sym2;
- else break;
- }
- Name sname = pair.sym.name;
- if (sname == names.init) sname = pair.sym.owner.name;
+ List diagSyms = ambiguousSyms.reverse();
+ Symbol s1 = diagSyms.head;
+ Symbol s2 = diagSyms.tail.head;
+ Name sname = s1.name;
+ if (sname == names.init) sname = s1.owner.name;
return diags.create(dkind, log.currentSource(),
pos, "ref.ambiguous", sname,
- kindName(pair.sym),
- pair.sym,
- pair.sym.location(site, types),
- kindName(pair.sym2),
- pair.sym2,
- pair.sym2.location(site, types));
+ kindName(s1),
+ s1,
+ s1.location(site, types),
+ kindName(s2),
+ s2,
+ s2.location(site, types));
+ }
+
+ /**
+ * If multiple applicable methods are found during overload and none of them
+ * is more specific than the others, attempt to merge their signatures.
+ */
+ Symbol mergeAbstracts(Type site) {
+ Symbol fst = ambiguousSyms.last();
+ Symbol res = fst;
+ for (Symbol s : ambiguousSyms.reverse()) {
+ Type mt1 = types.memberType(site, res);
+ Type mt2 = types.memberType(site, s);
+ if ((s.flags() & ABSTRACT) == 0 ||
+ !types.overrideEquivalent(mt1, mt2) ||
+ !types.isSameTypes(fst.erasure(types).getParameterTypes(),
+ s.erasure(types).getParameterTypes())) {
+ //ambiguity cannot be resolved
+ return this;
+ } else {
+ Type mst = mostSpecificReturnType(mt1, mt2);
+ if (mst == null) {
+ // Theoretically, this can't happen, but it is possible
+ // due to error recovery or mixing incompatible class files
+ return this;
+ }
+ Symbol mostSpecific = mst == mt1 ? res : s;
+ List allThrown = chk.intersect(mt1.getThrownTypes(), mt2.getThrownTypes());
+ Type newSig = types.createMethodTypeWithThrown(mostSpecific.type, allThrown);
+ res = new MethodSymbol(
+ mostSpecific.flags(),
+ mostSpecific.name,
+ newSig,
+ mostSpecific.owner);
+ }
+ }
+ return res;
+ }
+
+ @Override
+ protected Symbol access(Name name, TypeSymbol location) {
+ return ambiguousSyms.last();
}
}
diff --git a/langtools/test/tools/javac/lambda/TargetType21.java b/langtools/test/tools/javac/lambda/TargetType21.java
index 89375143a2b..d916f50d5cb 100644
--- a/langtools/test/tools/javac/lambda/TargetType21.java
+++ b/langtools/test/tools/javac/lambda/TargetType21.java
@@ -25,7 +25,7 @@ class TargetType21 {
void call(SAM3 sam) { }
void test() {
- call(x -> { throw new Exception(); }); //ok - resolves to call(SAM1)
+ call(x -> { throw new Exception(); }); //ambiguous
call(x -> { System.out.println(""); }); //ok - resolves to call(SAM2)
call(x -> { return (Object) null; }); //error - call(SAM3) is not applicable because of cyclic inference
call(x -> { return null; }); ////ok - resolves to call(SAM1)
diff --git a/langtools/test/tools/javac/lambda/TargetType21.out b/langtools/test/tools/javac/lambda/TargetType21.out
index 14895540288..638b32f680c 100644
--- a/langtools/test/tools/javac/lambda/TargetType21.out
+++ b/langtools/test/tools/javac/lambda/TargetType21.out
@@ -1,3 +1,3 @@
TargetType21.java:28:9: compiler.err.ref.ambiguous: call, kindname.method, call(TargetType21.SAM1), TargetType21, kindname.method, call(TargetType21.SAM2), TargetType21
-TargetType21.java:30:9: compiler.err.cant.apply.symbols: kindname.method, call, @755,{(compiler.misc.inapplicable.method: kindname.method, TargetType21, call(TargetType21.SAM1), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.inconvertible.types: java.lang.Object, java.lang.String)))),(compiler.misc.inapplicable.method: kindname.method, TargetType21, call(TargetType21.SAM2), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.unexpected.ret.val)))),(compiler.misc.inapplicable.method: kindname.method, TargetType21, call(TargetType21.SAM3), (compiler.misc.cyclic.inference: A))}
+TargetType21.java:30:9: compiler.err.cant.apply.symbols: kindname.method, call, @737,{(compiler.misc.inapplicable.method: kindname.method, TargetType21, call(TargetType21.SAM1), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.inconvertible.types: java.lang.Object, java.lang.String)))),(compiler.misc.inapplicable.method: kindname.method, TargetType21, call(TargetType21.SAM2), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.unexpected.ret.val)))),(compiler.misc.inapplicable.method: kindname.method, TargetType21, call(TargetType21.SAM3), (compiler.misc.cyclic.inference: A))}
2 errors
From 5ee942d5a8d3b6998925906e4b510b6b8dba0650 Mon Sep 17 00:00:00 2001
From: Maurizio Cimadamore
Date: Tue, 8 Jan 2013 10:17:29 +0100
Subject: [PATCH 29/53] 8005184: Restructure DeferredAttr to allow pluggable
deferred type completers
Add hooks to generalize deferred type completion via custom helper objects
Reviewed-by: jjg
---
.../sun/tools/javac/comp/DeferredAttr.java | 236 +++++++++++-------
1 file changed, 143 insertions(+), 93 deletions(-)
diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java b/langtools/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java
index cf81fc6f5dd..f80aad98456 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java
@@ -38,6 +38,7 @@ import com.sun.tools.javac.tree.JCTree.*;
import javax.tools.JavaFileObject;
import java.util.ArrayList;
+import java.util.EnumSet;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Queue;
@@ -177,29 +178,19 @@ public class DeferredAttr extends JCTree.Visitor {
* attribution round must follow one or more speculative rounds.
*/
Type check(ResultInfo resultInfo) {
+ return check(resultInfo, stuckVars(tree, env, resultInfo), basicCompleter);
+ }
+
+ Type check(ResultInfo resultInfo, List stuckVars, DeferredTypeCompleter deferredTypeCompleter) {
DeferredAttrContext deferredAttrContext =
resultInfo.checkContext.deferredAttrContext();
Assert.check(deferredAttrContext != emptyDeferredAttrContext);
- List stuckVars = stuckVars(tree, env, resultInfo);
if (stuckVars.nonEmpty()) {
deferredAttrContext.addDeferredAttrNode(this, resultInfo, stuckVars);
return Type.noType;
} else {
try {
- switch (deferredAttrContext.mode) {
- case SPECULATIVE:
- Assert.check(mode == null ||
- (mode == AttrMode.SPECULATIVE &&
- speculativeType(deferredAttrContext.msym, deferredAttrContext.phase).hasTag(NONE)));
- JCTree speculativeTree = attribSpeculative(tree, env, resultInfo);
- speculativeCache.put(deferredAttrContext.msym, speculativeTree, deferredAttrContext.phase);
- return speculativeTree.type;
- case CHECK:
- Assert.check(mode == AttrMode.SPECULATIVE);
- return attr.attribTree(tree, env, resultInfo);
- }
- Assert.error();
- return null;
+ return deferredTypeCompleter.complete(this, resultInfo, deferredAttrContext);
} finally {
mode = deferredAttrContext.mode;
}
@@ -207,6 +198,43 @@ public class DeferredAttr extends JCTree.Visitor {
}
}
+ /**
+ * A completer for deferred types. Defines an entry point for type-checking
+ * a deferred type.
+ */
+ interface DeferredTypeCompleter {
+ /**
+ * Entry point for type-checking a deferred type. Depending on the
+ * circumstances, type-checking could amount to full attribution
+ * or partial structural check (aka potential applicability).
+ */
+ Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext);
+ }
+
+ /**
+ * A basic completer for deferred types. This completer type-checks a deferred type
+ * using attribution; depending on the attribution mode, this could be either standard
+ * or speculative attribution.
+ */
+ DeferredTypeCompleter basicCompleter = new DeferredTypeCompleter() {
+ public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
+ switch (deferredAttrContext.mode) {
+ case SPECULATIVE:
+ Assert.check(dt.mode == null ||
+ (dt.mode == AttrMode.SPECULATIVE &&
+ dt.speculativeType(deferredAttrContext.msym, deferredAttrContext.phase).hasTag(NONE)));
+ JCTree speculativeTree = attribSpeculative(dt.tree, dt.env, resultInfo);
+ dt.speculativeCache.put(deferredAttrContext.msym, speculativeTree, deferredAttrContext.phase);
+ return speculativeTree.type;
+ case CHECK:
+ Assert.check(dt.mode == AttrMode.SPECULATIVE);
+ return attr.attribTree(dt.tree, dt.env, resultInfo);
+ }
+ Assert.error();
+ return null;
+ }
+ };
+
/**
* The 'mode' in which the deferred type is to be type-checked
*/
@@ -498,10 +526,80 @@ public class DeferredAttr extends JCTree.Visitor {
if (resultInfo.pt.hasTag(NONE) || resultInfo.pt.isErroneous()) {
return List.nil();
} else {
- StuckChecker sc = new StuckChecker(resultInfo, env);
+ return stuckVarsInternal(tree, resultInfo.pt, resultInfo.checkContext.inferenceContext());
+ }
+ }
+ //where
+ private List stuckVarsInternal(JCTree tree, Type pt, Infer.InferenceContext inferenceContext) {
+ StuckChecker sc = new StuckChecker(pt, inferenceContext);
sc.scan(tree);
return List.from(sc.stuckVars);
}
+
+ /**
+ * A special tree scanner that would only visit portions of a given tree.
+ * The set of nodes visited by the scanner can be customized at construction-time.
+ */
+ abstract static class FilterScanner extends TreeScanner {
+
+ final Filter treeFilter;
+
+ FilterScanner(final Set validTags) {
+ this.treeFilter = new Filter() {
+ public boolean accepts(JCTree t) {
+ return validTags.contains(t.getTag());
+ }
+ };
+ }
+
+ @Override
+ public void scan(JCTree tree) {
+ if (tree != null) {
+ if (treeFilter.accepts(tree)) {
+ super.scan(tree);
+ } else {
+ skip(tree);
+ }
+ }
+ }
+
+ /**
+ * handler that is executed when a node has been discarded
+ */
+ abstract void skip(JCTree tree);
+ }
+
+ /**
+ * A tree scanner suitable for visiting the target-type dependent nodes of
+ * a given argument expression.
+ */
+ static class PolyScanner extends FilterScanner {
+
+ PolyScanner() {
+ super(EnumSet.of(CONDEXPR, PARENS, LAMBDA, REFERENCE));
+ }
+
+ @Override
+ void skip(JCTree tree) {
+ //do nothing
+ }
+ }
+
+ /**
+ * A tree scanner suitable for visiting the target-type dependent nodes nested
+ * within a lambda expression body.
+ */
+ static class LambdaReturnScanner extends FilterScanner {
+
+ LambdaReturnScanner() {
+ super(EnumSet.of(BLOCK, CASE, CATCH, DOLOOP, FOREACHLOOP,
+ FORLOOP, RETURN, SYNCHRONIZED, SWITCH, TRY, WHILELOOP));
+ }
+
+ @Override
+ void skip(JCTree tree) {
+ //do nothing
+ }
}
/**
@@ -510,83 +608,32 @@ public class DeferredAttr extends JCTree.Visitor {
* inferring types that make some of the nested expressions incompatible
* with their corresponding instantiated target
*/
- class StuckChecker extends TreeScanner {
+ class StuckChecker extends PolyScanner {
Type pt;
- Filter treeFilter;
Infer.InferenceContext inferenceContext;
Set stuckVars = new LinkedHashSet();
- Env env;
- final Filter argsFilter = new Filter() {
- public boolean accepts(JCTree t) {
- switch (t.getTag()) {
- case CONDEXPR:
- case LAMBDA:
- case PARENS:
- case REFERENCE:
- return true;
- default:
- return false;
- }
- }
- };
-
- final Filter lambdaBodyFilter = new Filter() {
- public boolean accepts(JCTree t) {
- switch (t.getTag()) {
- case BLOCK: case CASE: case CATCH: case DOLOOP:
- case FOREACHLOOP: case FORLOOP: case RETURN:
- case SYNCHRONIZED: case SWITCH: case TRY: case WHILELOOP:
- return true;
- default:
- return false;
- }
- }
- };
-
- StuckChecker(ResultInfo resultInfo, Env env) {
- this.pt = resultInfo.pt;
- this.inferenceContext = resultInfo.checkContext.inferenceContext();
- this.treeFilter = argsFilter;
- this.env = env;
- }
-
- @Override
- public void scan(JCTree tree) {
- if (tree != null && treeFilter.accepts(tree)) {
- super.scan(tree);
- }
+ StuckChecker(Type pt, Infer.InferenceContext inferenceContext) {
+ this.pt = pt;
+ this.inferenceContext = inferenceContext;
}
@Override
public void visitLambda(JCLambda tree) {
- Type prevPt = pt;
- Filter prevFilter = treeFilter;
- try {
- if (inferenceContext.inferenceVars().contains(pt)) {
- stuckVars.add(pt);
- }
- if (!types.isFunctionalInterface(pt.tsym)) {
- return;
- }
- Type descType = types.findDescriptorType(pt);
- List freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
- if (!TreeInfo.isExplicitLambda(tree) &&
- freeArgVars.nonEmpty()) {
- stuckVars.addAll(freeArgVars);
- }
- pt = descType.getReturnType();
- if (tree.getBodyKind() == JCTree.JCLambda.BodyKind.EXPRESSION) {
- scan(tree.getBody());
- } else {
- treeFilter = lambdaBodyFilter;
- super.visitLambda(tree);
- }
- } finally {
- pt = prevPt;
- treeFilter = prevFilter;
+ if (inferenceContext.inferenceVars().contains(pt)) {
+ stuckVars.add(pt);
}
+ if (!types.isFunctionalInterface(pt.tsym)) {
+ return;
+ }
+ Type descType = types.findDescriptorType(pt);
+ List freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
+ if (!TreeInfo.isExplicitLambda(tree) &&
+ freeArgVars.nonEmpty()) {
+ stuckVars.addAll(freeArgVars);
+ }
+ scanLambdaBody(tree, descType.getReturnType());
}
@Override
@@ -605,16 +652,19 @@ public class DeferredAttr extends JCTree.Visitor {
stuckVars.addAll(freeArgVars);
}
- @Override
- public void visitReturn(JCReturn tree) {
- Filter prevFilter = treeFilter;
- try {
- treeFilter = argsFilter;
- if (tree.expr != null) {
- scan(tree.expr);
- }
- } finally {
- treeFilter = prevFilter;
+ void scanLambdaBody(JCLambda lambda, final Type pt) {
+ if (lambda.getBodyKind() == JCTree.JCLambda.BodyKind.EXPRESSION) {
+ stuckVars.addAll(stuckVarsInternal(lambda.body, pt, inferenceContext));
+ } else {
+ LambdaReturnScanner lambdaScanner = new LambdaReturnScanner() {
+ @Override
+ public void visitReturn(JCReturn tree) {
+ if (tree.expr != null) {
+ stuckVars.addAll(stuckVarsInternal(tree.expr, pt, inferenceContext));
+ }
+ }
+ };
+ lambdaScanner.scan(lambda.body);
}
}
}
From 9d4f6a0ebeac0b2a6bc8cd91f2588fe777f774b5 Mon Sep 17 00:00:00 2001
From: Vicente Romero
Date: Tue, 8 Jan 2013 13:47:57 +0000
Subject: [PATCH 30/53] 8005167: execution time of combo tests in javac should
be improved
Reviewed-by: jjg, jjh
---
.../javac/Diagnostics/6769027/T6769027.java | 115 ++++++-----
langtools/test/tools/javac/T7093325.java | 81 ++++----
.../IntersectionTypeCastTest.java | 114 ++++++-----
.../super/TestDefaultSuperCall.java | 67 ++++---
.../javac/failover/CheckAttributedTree.java | 120 ++++++------
.../7046778/DiamondAndInnerClassTest.java | 121 +++++++-----
.../7062745/GenericOverrideTest.java | 59 +++---
.../FunctionalInterfaceConversionTest.java | 73 ++++---
.../tools/javac/lambda/LambdaParserTest.java | 65 ++++---
.../lambda/MethodReferenceParserTest.java | 40 ++--
.../tools/javac/lambda/TestInvokeDynamic.java | 140 ++++++++------
.../StructuralMostSpecificTest.java | 65 ++++---
.../combo/TypeInferenceComboTest.java | 179 ++++++++++++------
.../lib/JavacTestingAbstractThreadedTest.java | 142 ++++++++++++++
.../DisjunctiveTypeWellFormednessTest.java | 44 +++--
.../tools/javac/varargs/7042566/T7042566.java | 103 +++++-----
.../tools/javac/varargs/warning/Warn4.java | 100 ++++++----
.../tools/javac/varargs/warning/Warn5.java | 80 +++++---
18 files changed, 1062 insertions(+), 646 deletions(-)
create mode 100644 langtools/test/tools/javac/lib/JavacTestingAbstractThreadedTest.java
diff --git a/langtools/test/tools/javac/Diagnostics/6769027/T6769027.java b/langtools/test/tools/javac/Diagnostics/6769027/T6769027.java
index 922b00fcebd..8339124619e 100644
--- a/langtools/test/tools/javac/Diagnostics/6769027/T6769027.java
+++ b/langtools/test/tools/javac/Diagnostics/6769027/T6769027.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2013, 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
@@ -26,14 +26,19 @@
* @bug 6769027
* @summary Source line should be displayed immediately after the first diagnostic line
* @author Maurizio Cimadamore
+ * @library ../../lib
+ * @build JavacTestingAbstractThreadedTest
* @run main/othervm T6769027
*/
+
import java.net.URI;
import java.util.regex.Matcher;
import javax.tools.*;
import com.sun.tools.javac.util.*;
-public class T6769027 {
+public class T6769027
+ extends JavacTestingAbstractThreadedTest
+ implements Runnable {
enum OutputKind {
RAW("rawDiagnostics","rawDiagnostics"),
@@ -314,7 +319,7 @@ public class T6769027 {
@Override
protected java.io.PrintWriter getWriterForDiagnosticType(JCDiagnostic.DiagnosticType dt) {
- return new java.io.PrintWriter(System.out);
+ return outWriter;
}
@Override
@@ -323,13 +328,42 @@ public class T6769027 {
}
}
- int nerrors = 0;
+ OutputKind outputKind;
+ ErrorKind errorKind;
+ MultilineKind multiKind;
+ MultilinePolicy multiPolicy;
+ PositionKind posKind;
+ XDiagsSource xdiagsSource;
+ XDiagsCompact xdiagsCompact;
+ CaretKind caretKind;
+ SourceLineKind sourceLineKind;
+ IndentKind summaryIndent;
+ IndentKind detailsIndent;
+ IndentKind sourceIndent;
+ IndentKind subdiagsIndent;
- void exec(OutputKind outputKind, ErrorKind errorKind, MultilineKind multiKind,
+ T6769027(OutputKind outputKind, ErrorKind errorKind, MultilineKind multiKind,
MultilinePolicy multiPolicy, PositionKind posKind, XDiagsSource xdiagsSource,
XDiagsCompact xdiagsCompact, CaretKind caretKind, SourceLineKind sourceLineKind,
IndentKind summaryIndent, IndentKind detailsIndent, IndentKind sourceIndent,
IndentKind subdiagsIndent) {
+ this.outputKind = outputKind;
+ this.errorKind = errorKind;
+ this.multiKind = multiKind;
+ this.multiPolicy = multiPolicy;
+ this.posKind = posKind;
+ this.xdiagsSource = xdiagsSource;
+ this.xdiagsCompact = xdiagsCompact;
+ this.caretKind = caretKind;
+ this.sourceLineKind = sourceLineKind;
+ this.summaryIndent = summaryIndent;
+ this.detailsIndent = detailsIndent;
+ this.sourceIndent = sourceIndent;
+ this.subdiagsIndent = subdiagsIndent;
+ }
+
+ @Override
+ public void run() {
Context ctx = new Context();
Options options = Options.instance(ctx);
outputKind.init(options);
@@ -362,23 +396,10 @@ public class T6769027 {
d = new JCDiagnostic.MultilineDiagnostic(d, subdiags);
}
String diag = log.getDiagnosticFormatter().format(d, messages.getCurrentLocale());
- checkOutput(diag,
- outputKind,
- errorKind,
- multiKind,
- multiPolicy,
- posKind,
- xdiagsSource,
- xdiagsCompact,
- caretKind,
- sourceLineKind,
- summaryIndent,
- detailsIndent,
- sourceIndent,
- subdiagsIndent);
+ checkOutput(diag);
}
- void test() {
+ public static void main(String[] args) throws Exception {
for (OutputKind outputKind : OutputKind.values()) {
for (ErrorKind errKind : ErrorKind.values()) {
for (MultilineKind multiKind : MultilineKind.values()) {
@@ -392,7 +413,7 @@ public class T6769027 {
for (IndentKind detailsIndent : IndentKind.values()) {
for (IndentKind sourceIndent : IndentKind.values()) {
for (IndentKind subdiagsIndent : IndentKind.values()) {
- exec(outputKind,
+ pool.execute(new T6769027(outputKind,
errKind,
multiKind,
multiPolicy,
@@ -404,7 +425,7 @@ public class T6769027 {
summaryIndent,
detailsIndent,
sourceIndent,
- subdiagsIndent);
+ subdiagsIndent));
}
}
}
@@ -418,15 +439,11 @@ public class T6769027 {
}
}
}
- if (nerrors != 0)
- throw new AssertionError(nerrors + " errors found");
+
+ checkAfterExec(false);
}
- void printInfo(String msg, OutputKind outputKind, ErrorKind errorKind, MultilineKind multiKind,
- MultilinePolicy multiPolicy, PositionKind posKind, XDiagsSource xdiagsSource,
- XDiagsCompact xdiagsCompact, CaretKind caretKind, SourceLineKind sourceLineKind,
- IndentKind summaryIndent, IndentKind detailsIndent, IndentKind sourceIndent,
- IndentKind subdiagsIndent, String errorLine) {
+ void printInfo(String msg, String errorLine) {
String sep = "*********************************************************";
String desc = "raw=" + outputKind + " pos=" + posKind + " key=" + errorKind.key() +
" multiline=" + multiKind +" multiPolicy=" + multiPolicy.value +
@@ -434,18 +451,14 @@ public class T6769027 {
" caret=" + caretKind + " sourcePosition=" + sourceLineKind +
" summaryIndent=" + summaryIndent + " detailsIndent=" + detailsIndent +
" sourceIndent=" + sourceIndent + " subdiagsIndent=" + subdiagsIndent;
- System.out.println(sep);
- System.out.println(desc);
- System.out.println(sep);
- System.out.println(msg);
- System.out.println("Diagnostic formatting problem - expected diagnostic...\n" + errorLine);
+ errWriter.println(sep);
+ errWriter.println(desc);
+ errWriter.println(sep);
+ errWriter.println(msg);
+ errWriter.println("Diagnostic formatting problem - expected diagnostic...\n" + errorLine);
}
- void checkOutput(String msg, OutputKind outputKind, ErrorKind errorKind, MultilineKind multiKind,
- MultilinePolicy multiPolicy, PositionKind posKind, XDiagsSource xdiagsSource,
- XDiagsCompact xdiagsCompact, CaretKind caretKind, SourceLineKind sourceLineKind,
- IndentKind summaryIndent, IndentKind detailsIndent, IndentKind sourceIndent,
- IndentKind subdiagsIndent) {
+ void checkOutput(String msg) {
boolean shouldPrintSource = posKind == PositionKind.POS &&
xdiagsSource != XDiagsSource.NO_SOURCE &&
(xdiagsSource == XDiagsSource.SOURCE ||
@@ -453,7 +466,8 @@ public class T6769027 {
String errorLine = posKind.getOutput(outputKind) +
errorKind.getOutput(outputKind, summaryIndent, detailsIndent);
if (xdiagsCompact != XDiagsCompact.COMPACT)
- errorLine += multiKind.getOutput(outputKind, errorKind, multiPolicy, summaryIndent, detailsIndent, subdiagsIndent);
+ errorLine += multiKind.getOutput(outputKind, errorKind, multiPolicy,
+ summaryIndent, detailsIndent, subdiagsIndent);
String[] lines = errorLine.split("\n");
if (xdiagsCompact == XDiagsCompact.COMPACT) {
errorLine = lines[0];
@@ -474,26 +488,9 @@ public class T6769027 {
}
if (!msg.equals(errorLine)) {
- printInfo(msg,
- outputKind,
- errorKind,
- multiKind,
- multiPolicy,
- posKind,
- xdiagsSource,
- xdiagsCompact,
- caretKind,
- sourceLineKind,
- summaryIndent,
- detailsIndent,
- sourceIndent,
- subdiagsIndent,
- errorLine);
- nerrors++;
+ printInfo(msg, errorLine);
+ errCount.incrementAndGet();
}
}
- public static void main(String... args) throws Exception {
- new T6769027().test();
- }
}
diff --git a/langtools/test/tools/javac/T7093325.java b/langtools/test/tools/javac/T7093325.java
index 42ea3bc0705..8330ede8624 100644
--- a/langtools/test/tools/javac/T7093325.java
+++ b/langtools/test/tools/javac/T7093325.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2013, 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
@@ -25,35 +25,29 @@
* @test
* @bug 7093325
* @summary Redundant entry in bytecode exception table
+ * @library lib
+ * @build JavacTestingAbstractThreadedTest
+ * @run main T7093325
*/
-import com.sun.source.util.JavacTask;
-import com.sun.tools.classfile.Attribute;
-import com.sun.tools.classfile.ClassFile;
-import com.sun.tools.classfile.Code_attribute;
-import com.sun.tools.classfile.ConstantPool.*;
-import com.sun.tools.classfile.Method;
-import com.sun.tools.javac.api.JavacTool;
-
import java.io.File;
import java.net.URI;
import java.util.Arrays;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
-import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
+import com.sun.source.util.JavacTask;
+import com.sun.tools.classfile.Attribute;
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.Code_attribute;
+import com.sun.tools.classfile.ConstantPool.*;
+import com.sun.tools.classfile.Method;
-public class T7093325 {
-
- /** global decls ***/
-
- // Create a single file manager and reuse it for each compile to save time.
- static StandardJavaFileManager fm = JavacTool.create().getStandardFileManager(null, null, null);
-
- //statistics
- static int checkCount = 0;
+public class T7093325
+ extends JavacTestingAbstractThreadedTest
+ implements Runnable {
enum StatementKind {
THROW("throw new RuntimeException();", false, false),
@@ -89,7 +83,8 @@ public class T7093325 {
if (this.ordinal() == 0) {
return catchStr;
} else {
- return CatchArity.values()[this.ordinal() - 1].catchers() + catchStr;
+ return CatchArity.values()[this.ordinal() - 1].catchers() +
+ catchStr;
}
}
}
@@ -98,31 +93,36 @@ public class T7093325 {
for (CatchArity ca : CatchArity.values()) {
for (StatementKind stmt0 : StatementKind.values()) {
if (ca.ordinal() == 0) {
- new T7093325(ca, stmt0).compileAndCheck();
+ pool.execute(new T7093325(ca, stmt0));
continue;
}
for (StatementKind stmt1 : StatementKind.values()) {
if (ca.ordinal() == 1) {
- new T7093325(ca, stmt0, stmt1).compileAndCheck();
+ pool.execute(new T7093325(ca, stmt0, stmt1));
continue;
}
for (StatementKind stmt2 : StatementKind.values()) {
if (ca.ordinal() == 2) {
- new T7093325(ca, stmt0, stmt1, stmt2).compileAndCheck();
+ pool.execute(new T7093325(ca, stmt0, stmt1, stmt2));
continue;
}
for (StatementKind stmt3 : StatementKind.values()) {
if (ca.ordinal() == 3) {
- new T7093325(ca, stmt0, stmt1, stmt2, stmt3).compileAndCheck();
+ pool.execute(
+ new T7093325(ca, stmt0, stmt1, stmt2, stmt3));
continue;
}
for (StatementKind stmt4 : StatementKind.values()) {
if (ca.ordinal() == 4) {
- new T7093325(ca, stmt0, stmt1, stmt2, stmt3, stmt4).compileAndCheck();
+ pool.execute(
+ new T7093325(ca, stmt0, stmt1,
+ stmt2, stmt3, stmt4));
continue;
}
for (StatementKind stmt5 : StatementKind.values()) {
- new T7093325(ca, stmt0, stmt1, stmt2, stmt3, stmt4, stmt5).compileAndCheck();
+ pool.execute(
+ new T7093325(ca, stmt0, stmt1, stmt2,
+ stmt3, stmt4, stmt5));
}
}
}
@@ -131,7 +131,7 @@ public class T7093325 {
}
}
- System.out.println("Total checks made: " + checkCount);
+ checkAfterExec();
}
/** instance decls **/
@@ -144,17 +144,18 @@ public class T7093325 {
this.stmts = stmts;
}
- void compileAndCheck() throws Exception {
+ @Override
+ public void run() {
+ int id = checkCount.incrementAndGet();
final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
- JavaSource source = new JavaSource();
- JavacTask ct = (JavacTask)tool.getTask(null, fm, null,
+ JavaSource source = new JavaSource(id);
+ JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), null,
null, null, Arrays.asList(source));
ct.call();
- verifyBytecode(source);
+ verifyBytecode(source, id);
}
- void verifyBytecode(JavaSource source) {
- checkCount++;
+ void verifyBytecode(JavaSource source, int id) {
boolean lastInlined = false;
boolean hasCode = false;
int gapsCount = 0;
@@ -172,11 +173,12 @@ public class T7093325 {
//System.out.printf("gaps %d \n %s \n", gapsCount, source.toString());
- File compiledTest = new File("Test.class");
+ File compiledTest = new File(String.format("Test%s.class", id));
try {
ClassFile cf = ClassFile.read(compiledTest);
if (cf == null) {
- throw new Error("Classfile not found: " + compiledTest.getName());
+ throw new Error("Classfile not found: " +
+ compiledTest.getName());
}
Method test_method = null;
@@ -232,7 +234,7 @@ public class T7093325 {
"class C extends RuntimeException {} \n" +
"class D extends RuntimeException {} \n" +
"class E extends RuntimeException {} \n" +
- "class Test {\n" +
+ "class Test#ID {\n" +
" void test() {\n" +
" try { #S0 } #C finally { System.out.println(); }\n" +
" }\n" +
@@ -240,10 +242,12 @@ public class T7093325 {
String source;
- public JavaSource() {
- super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
+ public JavaSource(int id) {
+ super(URI.create(String.format("myfo:/Test%s.java", id)),
+ JavaFileObject.Kind.SOURCE);
source = source_template.replace("#C", ca.catchers());
source = source.replace("#S0", stmts[0].stmt);
+ source = source.replace("#ID", String.valueOf(id));
for (int i = 1; i < ca.ordinal() + 1; i++) {
source = source.replace("#S" + i, stmts[i].stmt);
}
@@ -259,4 +263,5 @@ public class T7093325 {
return source;
}
}
+
}
diff --git a/langtools/test/tools/javac/cast/intersection/IntersectionTypeCastTest.java b/langtools/test/tools/javac/cast/intersection/IntersectionTypeCastTest.java
index b82e1babf34..262ef48e03f 100644
--- a/langtools/test/tools/javac/cast/intersection/IntersectionTypeCastTest.java
+++ b/langtools/test/tools/javac/cast/intersection/IntersectionTypeCastTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, 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
@@ -25,23 +25,26 @@
* @test
* @bug 8002099
* @summary Add support for intersection types in cast expression
+ * @library ../../lib
+ * @build JavacTestingAbstractThreadedTest
+ * @run main/timeout=360 IntersectionTypeCastTest
*/
-import com.sun.source.util.JavacTask;
-import com.sun.tools.javac.util.List;
-import com.sun.tools.javac.util.ListBuffer;
import java.net.URI;
import java.util.Arrays;
import javax.tools.Diagnostic;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
-import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
-public class IntersectionTypeCastTest {
+import com.sun.source.util.JavacTask;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.ListBuffer;
- static int checkCount = 0;
+public class IntersectionTypeCastTest
+ extends JavacTestingAbstractThreadedTest
+ implements Runnable {
interface Type {
boolean subtypeOf(Type that);
@@ -59,7 +62,8 @@ public class IntersectionTypeCastTest {
String typeStr;
InterfaceKind superInterface;
- InterfaceKind(String declStr, String typeStr, InterfaceKind superInterface) {
+ InterfaceKind(String declStr, String typeStr,
+ InterfaceKind superInterface) {
this.declStr = declStr;
this.typeStr = typeStr;
this.superInterface = superInterface;
@@ -67,7 +71,8 @@ public class IntersectionTypeCastTest {
@Override
public boolean subtypeOf(Type that) {
- return this == that || superInterface == that || that == ClassKind.OBJECT;
+ return this == that || superInterface == that ||
+ that == ClassKind.OBJECT;
}
@Override
@@ -88,19 +93,27 @@ public class IntersectionTypeCastTest {
enum ClassKind implements Type {
OBJECT(null, "Object"),
- CA("#M class CA implements A { }\n", "CA", InterfaceKind.A),
- CB("#M class CB implements B { }\n", "CB", InterfaceKind.B),
- CAB("#M class CAB implements A, B { }\n", "CAB", InterfaceKind.A, InterfaceKind.B),
- CC("#M class CC implements C { }\n", "CC", InterfaceKind.C, InterfaceKind.A),
- CCA("#M class CCA implements C, A { }\n", "CCA", InterfaceKind.C, InterfaceKind.A),
- CCB("#M class CCB implements C, B { }\n", "CCB", InterfaceKind.C, InterfaceKind.A, InterfaceKind.B),
- CCAB("#M class CCAB implements C, A, B { }\n", "CCAB", InterfaceKind.C, InterfaceKind.A, InterfaceKind.B);
+ CA("#M class CA implements A { }\n", "CA",
+ InterfaceKind.A),
+ CB("#M class CB implements B { }\n", "CB",
+ InterfaceKind.B),
+ CAB("#M class CAB implements A, B { }\n", "CAB",
+ InterfaceKind.A, InterfaceKind.B),
+ CC("#M class CC implements C { }\n", "CC",
+ InterfaceKind.C, InterfaceKind.A),
+ CCA("#M class CCA implements C, A { }\n", "CCA",
+ InterfaceKind.C, InterfaceKind.A),
+ CCB("#M class CCB implements C, B { }\n", "CCB",
+ InterfaceKind.C, InterfaceKind.A, InterfaceKind.B),
+ CCAB("#M class CCAB implements C, A, B { }\n", "CCAB",
+ InterfaceKind.C, InterfaceKind.A, InterfaceKind.B);
String declTemplate;
String typeStr;
List superInterfaces;
- ClassKind(String declTemplate, String typeStr, InterfaceKind... superInterfaces) {
+ ClassKind(String declTemplate, String typeStr,
+ InterfaceKind... superInterfaces) {
this.declTemplate = declTemplate;
this.typeStr = typeStr;
this.superInterfaces = List.from(superInterfaces);
@@ -114,7 +127,8 @@ public class IntersectionTypeCastTest {
@Override
public boolean subtypeOf(Type that) {
- return this == that || superInterfaces.contains(that) || that == OBJECT;
+ return this == that || superInterfaces.contains(that) ||
+ that == OBJECT;
}
@Override
@@ -170,9 +184,11 @@ public class IntersectionTypeCastTest {
}
String getCast() {
- String temp = kind.castTemplate.replaceAll("#C", types[0].asString());
+ String temp = kind.castTemplate.replaceAll("#C",
+ types[0].asString());
for (int i = 0; i < kind.interfaceBounds ; i++) {
- temp = temp.replace(String.format("#I%d", i), types[i + 1].asString());
+ temp = temp.replace(String.format("#I%d", i),
+ types[i + 1].asString());
}
return temp;
}
@@ -195,7 +211,8 @@ public class IntersectionTypeCastTest {
t1.subtypeOf(t2) ||
t2.subtypeOf(t1) ||
(t1.isInterface() && t2.isInterface()) || //side-cast (1)
- (mod == ModifierKind.NONE && (t1.isInterface() != t2.isInterface())); //side-cast (2)
+ (mod == ModifierKind.NONE &&
+ (t1.isInterface() != t2.isInterface())); //side-cast (2)
if (!compat) return false;
}
}
@@ -204,18 +221,15 @@ public class IntersectionTypeCastTest {
}
public static void main(String... args) throws Exception {
- //create default shared JavaCompiler - reused across multiple compilations
- JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
- StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
-
for (ModifierKind mod : ModifierKind.values()) {
for (CastInfo cast1 : allCastInfo()) {
for (CastInfo cast2 : allCastInfo()) {
- new IntersectionTypeCastTest(mod, cast1, cast2).run(comp, fm);
+ pool.execute(
+ new IntersectionTypeCastTest(mod, cast1, cast2));
}
}
}
- System.out.println("Total check executed: " + checkCount);
+ checkAfterExec();
}
static List allCastInfo() {
@@ -235,11 +249,14 @@ public class IntersectionTypeCastTest {
} else {
for (InterfaceKind intf2 : InterfaceKind.values()) {
if (kind.interfaceBounds == 2) {
- buf.append(new CastInfo(kind, clazz, intf1, intf2));
+ buf.append(
+ new CastInfo(kind, clazz, intf1, intf2));
continue;
} else {
for (InterfaceKind intf3 : InterfaceKind.values()) {
- buf.append(new CastInfo(kind, clazz, intf1, intf2, intf3));
+ buf.append(
+ new CastInfo(kind, clazz, intf1,
+ intf2, intf3));
continue;
}
}
@@ -265,6 +282,22 @@ public class IntersectionTypeCastTest {
this.diagChecker = new DiagnosticChecker();
}
+ @Override
+ public void run() {
+ final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
+
+ JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), diagChecker,
+ Arrays.asList("-XDallowIntersectionTypes"),
+ null, Arrays.asList(source));
+ try {
+ ct.analyze();
+ } catch (Throwable ex) {
+ throw new AssertionError("Error thrown when compiling the following code:\n" +
+ source.getCharContent(true));
+ }
+ check();
+ }
+
class JavaSource extends SimpleJavaFileObject {
String bodyTemplate = "class Test {\n" +
@@ -282,7 +315,8 @@ public class IntersectionTypeCastTest {
for (InterfaceKind ik : InterfaceKind.values()) {
source += ik.declStr;
}
- source += bodyTemplate.replaceAll("#C1", cast1.getCast()).replaceAll("#C2", cast2.getCast());
+ source += bodyTemplate.replaceAll("#C1", cast1.getCast()).
+ replaceAll("#C2", cast2.getCast());
}
@Override
@@ -291,21 +325,11 @@ public class IntersectionTypeCastTest {
}
}
- void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception {
- JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker,
- Arrays.asList("-XDallowIntersectionTypes"), null, Arrays.asList(source));
- try {
- ct.analyze();
- } catch (Throwable ex) {
- throw new AssertionError("Error thrown when compiling the following code:\n" + source.getCharContent(true));
- }
- check();
- }
-
void check() {
- checkCount++;
+ checkCount.incrementAndGet();
- boolean errorExpected = cast1.hasDuplicateTypes() || cast2.hasDuplicateTypes();
+ boolean errorExpected = cast1.hasDuplicateTypes() ||
+ cast2.hasDuplicateTypes();
errorExpected |= !cast2.compatibleWith(mod, cast1);
@@ -317,7 +341,8 @@ public class IntersectionTypeCastTest {
}
}
- static class DiagnosticChecker implements javax.tools.DiagnosticListener {
+ static class DiagnosticChecker
+ implements javax.tools.DiagnosticListener {
boolean errorFound;
@@ -327,4 +352,5 @@ public class IntersectionTypeCastTest {
}
}
}
+
}
diff --git a/langtools/test/tools/javac/defaultMethods/super/TestDefaultSuperCall.java b/langtools/test/tools/javac/defaultMethods/super/TestDefaultSuperCall.java
index 7c4ced6d293..f081e2c9290 100644
--- a/langtools/test/tools/javac/defaultMethods/super/TestDefaultSuperCall.java
+++ b/langtools/test/tools/javac/defaultMethods/super/TestDefaultSuperCall.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, 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
@@ -24,25 +24,25 @@
/*
* @test
* @summary Automatic test for checking correctness of default super/this resolution
+ * @library ../../lib
+ * @build JavacTestingAbstractThreadedTest
+ * @run main TestDefaultSuperCall
*/
-import com.sun.source.util.JavacTask;
import java.net.URI;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
-import java.util.Map;
import javax.tools.Diagnostic;
-import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
-import javax.tools.StandardJavaFileManager;
-import javax.tools.ToolProvider;
-public class TestDefaultSuperCall {
+import com.sun.source.util.JavacTask;
- static int checkCount = 0;
+public class TestDefaultSuperCall
+ extends JavacTestingAbstractThreadedTest
+ implements Runnable {
enum InterfaceKind {
DEFAULT("interface A extends B { default void m() { } }"),
@@ -212,7 +212,7 @@ public class TestDefaultSuperCall {
List elementsWithMethod;
Shape(ElementKind... elements) {
- System.err.println("elements = " + Arrays.toString(elements));
+ errWriter.println("elements = " + Arrays.toString(elements));
enclosingElements = new ArrayList<>();
enclosingNames = new ArrayList<>();
elementsWithMethod = new ArrayList<>();
@@ -231,28 +231,26 @@ public class TestDefaultSuperCall {
elementsWithMethod.add(prevName);
}
String element = ek.templateDecl.replaceAll("#N", name);
- shapeStr = shapeStr == null ? element : shapeStr.replaceAll("#B", element);
+ shapeStr = shapeStr ==
+ null ? element : shapeStr.replaceAll("#B", element);
prevName = name;
}
}
String getShape(QualifierKind qk, ExprKind ek) {
String methName = ek == ExprKind.THIS ? "test" : "m";
- String call = qk.getQualifier(this) + "." + ek.exprStr + "." + methName + "();";
+ String call = qk.getQualifier(this) + "." +
+ ek.exprStr + "." + methName + "();";
return shapeStr.replaceAll("#B", call);
}
String enclosingAt(int index) {
- return index < enclosingNames.size() ? enclosingNames.get(index) : "BAD";
+ return index < enclosingNames.size() ?
+ enclosingNames.get(index) : "BAD";
}
}
public static void main(String... args) throws Exception {
-
- //create default shared JavaCompiler - reused across multiple compilations
- JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
- StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
-
for (InterfaceKind ik : InterfaceKind.values()) {
for (PruneKind pk : PruneKind.values()) {
for (ElementKind ek1 : ElementKind.values()) {
@@ -264,10 +262,14 @@ public class TestDefaultSuperCall {
for (ElementKind ek4 : ElementKind.values()) {
if (!ek4.isAllowedEnclosing(ek3, false)) continue;
for (ElementKind ek5 : ElementKind.values()) {
- if (!ek5.isAllowedEnclosing(ek4, false) || ek5.isClassDecl()) continue;
+ if (!ek5.isAllowedEnclosing(ek4, false) ||
+ ek5.isClassDecl()) continue;
for (QualifierKind qk : QualifierKind.values()) {
for (ExprKind ek : ExprKind.values()) {
- new TestDefaultSuperCall(ik, pk, new Shape(ek1, ek2, ek3, ek4, ek5), qk, ek).run(comp, fm);
+ pool.execute(
+ new TestDefaultSuperCall(ik, pk,
+ new Shape(ek1, ek2, ek3,
+ ek4, ek5), qk, ek));
}
}
}
@@ -277,7 +279,8 @@ public class TestDefaultSuperCall {
}
}
}
- System.out.println("Total check executed: " + checkCount);
+
+ checkAfterExec();
}
InterfaceKind ik;
@@ -288,7 +291,8 @@ public class TestDefaultSuperCall {
JavaSource source;
DiagnosticChecker diagChecker;
- TestDefaultSuperCall(InterfaceKind ik, PruneKind pk, Shape sh, QualifierKind qk, ExprKind ek) {
+ TestDefaultSuperCall(InterfaceKind ik, PruneKind pk, Shape sh,
+ QualifierKind qk, ExprKind ek) {
this.ik = ik;
this.pk = pk;
this.sh = sh;
@@ -321,13 +325,14 @@ public class TestDefaultSuperCall {
}
}
- void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception {
- JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker,
+ public void run() {
+ JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker,
null, null, Arrays.asList(source));
try {
ct.analyze();
} catch (Throwable ex) {
- throw new AssertionError("Error thrown when analyzing the following source:\n" + source.getCharContent(true));
+ processException(ex);
+ return;
}
check();
}
@@ -370,7 +375,8 @@ public class TestDefaultSuperCall {
int lastIdx = sh.enclosingElements.size() - 1;
boolean found = lastIdx == -1 ? false :
- sh.enclosingElements.get(lastIdx).hasSuper() && qk.allowSuperCall(ik, pk);
+ sh.enclosingElements.get(lastIdx).hasSuper() &&
+ qk.allowSuperCall(ik, pk);
errorExpected |= !found;
if (!found) {
@@ -378,9 +384,10 @@ public class TestDefaultSuperCall {
}
}
- checkCount++;
+ checkCount.incrementAndGet();
if (diagChecker.errorFound != errorExpected) {
- throw new AssertionError("Problem when compiling source:\n" + source.getCharContent(true) +
+ throw new AssertionError("Problem when compiling source:\n" +
+ source.getCharContent(true) +
"\nenclosingElems: " + sh.enclosingElements +
"\nenclosingNames: " + sh.enclosingNames +
"\nelementsWithMethod: " + sh.elementsWithMethod +
@@ -392,15 +399,17 @@ public class TestDefaultSuperCall {
}
}
- static class DiagnosticChecker implements javax.tools.DiagnosticListener {
+ static class DiagnosticChecker
+ implements javax.tools.DiagnosticListener {
boolean errorFound;
public void report(Diagnostic extends JavaFileObject> diagnostic) {
if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
- System.err.println(diagnostic.getMessage(Locale.getDefault()));
+ errWriter.println(diagnostic.getMessage(Locale.getDefault()));
errorFound = true;
}
}
}
+
}
diff --git a/langtools/test/tools/javac/failover/CheckAttributedTree.java b/langtools/test/tools/javac/failover/CheckAttributedTree.java
index 5dbc86d003a..f664995d107 100644
--- a/langtools/test/tools/javac/failover/CheckAttributedTree.java
+++ b/langtools/test/tools/javac/failover/CheckAttributedTree.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2013, 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
@@ -21,7 +21,15 @@
* questions.
*/
-import com.sun.source.util.TaskEvent;
+/*
+ * @test
+ * @bug 6970584
+ * @summary assorted position errors in compiler syntax trees
+ * @library ../lib
+ * @build JavacTestingAbstractThreadedTest
+ * @run main CheckAttributedTree -q -r -et ERRONEOUS .
+ */
+
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
@@ -34,6 +42,20 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.lang.model.element.Element;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JComponent;
@@ -49,23 +71,14 @@ import javax.swing.event.CaretListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultHighlighter;
import javax.swing.text.Highlighter;
-import java.io.File;
-import java.io.IOException;
-import java.io.PrintStream;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.List;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticListener;
import javax.tools.JavaFileObject;
-import javax.tools.StandardJavaFileManager;
import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.util.TaskEvent;
import com.sun.source.util.JavacTask;
import com.sun.source.util.TaskListener;
-import com.sun.tools.javac.api.JavacTool;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.tree.EndPosTable;
@@ -76,11 +89,6 @@ import com.sun.tools.javac.tree.TreeInfo;
import com.sun.tools.javac.tree.TreeScanner;
import com.sun.tools.javac.util.Pair;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-import javax.lang.model.element.Element;
-
import static com.sun.tools.javac.tree.JCTree.Tag.*;
/**
@@ -95,13 +103,7 @@ import static com.sun.tools.javac.tree.JCTree.Tag.*;
* covering any new language features that may be tested in this test suite.
*/
-/*
- * @test
- * @bug 6970584
- * @summary assorted position errors in compiler syntax trees
- * @run main CheckAttributedTree -q -r -et ERRONEOUS .
- */
-public class CheckAttributedTree {
+public class CheckAttributedTree extends JavacTestingAbstractThreadedTest {
/**
* Main entry point.
* If test.src is set, program runs in jtreg mode, and will throw an Error
@@ -110,9 +112,10 @@ public class CheckAttributedTree {
* args is the value of ${test.src}. In jtreg mode, the -r option can be
* given to change the default base directory to the root test directory.
*/
- public static void main(String... args) {
+ public static void main(String... args) throws Exception {
String testSrc = System.getProperty("test.src");
File baseDir = (testSrc == null) ? null : new File(testSrc);
+ throwAssertionOnError = false;
boolean ok = new CheckAttributedTree().run(baseDir, args);
if (!ok) {
if (testSrc != null) // jtreg mode
@@ -130,7 +133,7 @@ public class CheckAttributedTree {
* @param args command line args
* @return true if successful or in gui mode
*/
- boolean run(File baseDir, String... args) {
+ boolean run(File baseDir, String... args) throws Exception {
if (args.length == 0) {
usage(System.out);
return true;
@@ -145,8 +148,10 @@ public class CheckAttributedTree {
gui = true;
else if (arg.equals("-q"))
quiet = true;
- else if (arg.equals("-v"))
+ else if (arg.equals("-v")) {
verbose = true;
+ printAll = true;
+ }
else if (arg.equals("-t") && i + 1 < args.length)
tags.add(args[++i]);
else if (arg.equals("-ef") && i + 1 < args.length)
@@ -179,12 +184,11 @@ public class CheckAttributedTree {
error("File not found: " + file);
}
- if (fileCount != 1)
- System.err.println(fileCount + " files read");
- if (errors > 0)
- System.err.println(errors + " errors");
+ if (fileCount.get() != 1)
+ errWriter.println(fileCount + " files read");
+ checkAfterExec(false);
- return (gui || errors == 0);
+ return (gui || errCount.get() == 0);
}
/**
@@ -215,7 +219,7 @@ public class CheckAttributedTree {
* for java files.
* @param file the file or directory to test
*/
- void test(File file) {
+ void test(final File file) {
if (excludeFiles.contains(file)) {
if (!quiet)
error("File " + file + " excluded");
@@ -230,20 +234,24 @@ public class CheckAttributedTree {
}
if (file.isFile() && file.getName().endsWith(".java")) {
- try {
- if (verbose)
- System.err.println(file);
- fileCount++;
- NPETester p = new NPETester();
- p.test(read(file));
- } catch (AttributionException e) {
- if (!quiet) {
- error("Error attributing " + file + "\n" + e.getMessage());
+ pool.execute(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ if (verbose)
+ errWriter.println(file);
+ fileCount.incrementAndGet();
+ NPETester p = new NPETester();
+ p.test(read(file));
+ } catch (AttributionException e) {
+ if (!quiet) {
+ error("Error attributing " + file + "\n" + e.getMessage());
+ }
+ } catch (IOException e) {
+ error("Error reading " + file + ": " + e);
+ }
}
- } catch (IOException e) {
- error("Error reading " + file + ": " + e);
- }
- return;
+ });
}
if (!quiet)
@@ -254,8 +262,6 @@ public class CheckAttributedTree {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
Reporter r = new Reporter(pw);
- JavacTool tool = JavacTool.create();
- StandardJavaFileManager fm = tool.getStandardFileManager(r, null, null);
/**
* Read a file.
@@ -265,11 +271,10 @@ public class CheckAttributedTree {
* @throws TreePosTest.ParseException if any errors occur while parsing the file
*/
List> read(File file) throws IOException, AttributionException {
- JavacTool tool = JavacTool.create();
r.errors = 0;
- Iterable extends JavaFileObject> files = fm.getJavaFileObjects(file);
+ Iterable extends JavaFileObject> files = fm.get().getJavaFileObjects(file);
String[] opts = { "-XDshouldStopPolicy=ATTR", "-XDverboseCompilePolicy" };
- JavacTask task = tool.getTask(pw, fm, r, Arrays.asList(opts), null, files);
+ JavacTask task = (JavacTask)comp.getTask(pw, fm.get(), r, Arrays.asList(opts), null, files);
final List analyzedElems = new ArrayList<>();
task.setTaskListener(new TaskListener() {
public void started(TaskEvent e) {
@@ -308,13 +313,9 @@ public class CheckAttributedTree {
*/
void error(String msg) {
System.err.println(msg);
- errors++;
+ errCount.incrementAndGet();
}
- /** Number of files that have been analyzed. */
- int fileCount;
- /** Number of errors reported. */
- int errors;
/** Flag: don't report irrelevant files. */
boolean quiet;
/** Flag: show errors in GUI viewer. */
@@ -385,7 +386,8 @@ public class CheckAttributedTree {
viewer = new Viewer();
viewer.addEntry(sourcefile, label, encl, self);
}
- error(label + self.toString() + " encl: " + encl.toString() + " in file: " + sourcefile + " " + self.tree);
+ error(label + self.toString() + " encl: " + encl.toString() +
+ " in file: " + sourcefile + " " + self.tree);
}
}
@@ -754,4 +756,8 @@ public class CheckAttributedTree {
final Info self;
}
}
+
+ /** Number of files that have been analyzed. */
+ static AtomicInteger fileCount = new AtomicInteger();
+
}
diff --git a/langtools/test/tools/javac/generics/diamond/7046778/DiamondAndInnerClassTest.java b/langtools/test/tools/javac/generics/diamond/7046778/DiamondAndInnerClassTest.java
index 290d083aad7..2d8fea2c13d 100644
--- a/langtools/test/tools/javac/generics/diamond/7046778/DiamondAndInnerClassTest.java
+++ b/langtools/test/tools/javac/generics/diamond/7046778/DiamondAndInnerClassTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2013, 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
@@ -25,21 +25,21 @@
* @test
* @bug 7046778
* @summary Project Coin: problem with diamond and member inner classes
+ * @library ../../../lib
+ * @build JavacTestingAbstractThreadedTest
+ * @run main DiamondAndInnerClassTest
*/
import com.sun.source.util.JavacTask;
import java.net.URI;
import java.util.Arrays;
import javax.tools.Diagnostic;
-import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
-import javax.tools.StandardJavaFileManager;
-import javax.tools.ToolProvider;
-public class DiamondAndInnerClassTest {
-
- static int checkCount = 0;
+public class DiamondAndInnerClassTest
+ extends JavacTestingAbstractThreadedTest
+ implements Runnable {
enum TypeArgumentKind {
NONE(""),
@@ -151,11 +151,6 @@ public class DiamondAndInnerClassTest {
}
public static void main(String... args) throws Exception {
-
- //create default shared JavaCompiler - reused across multiple compilations
- JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
- StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
-
for (InnerClassDeclArity innerClassDeclArity : InnerClassDeclArity.values()) {
for (TypeQualifierArity declType : TypeQualifierArity.values()) {
if (!declType.matches(innerClassDeclArity)) continue;
@@ -168,53 +163,79 @@ public class DiamondAndInnerClassTest {
//no diamond on decl site
if (taDecl1 == TypeArgumentKind.DIAMOND) continue;
for (TypeArgumentKind taSite1 : TypeArgumentKind.values()) {
- boolean isSiteRaw = taSite1 == TypeArgumentKind.NONE;
+ boolean isSiteRaw =
+ taSite1 == TypeArgumentKind.NONE;
//diamond only allowed on the last type qualifier
if (taSite1 == TypeArgumentKind.DIAMOND &&
- innerClassDeclArity != InnerClassDeclArity.ONE) continue;
+ innerClassDeclArity !=
+ InnerClassDeclArity.ONE)
+ continue;
for (ArgumentKind arg1 : ArgumentKind.values()) {
if (innerClassDeclArity == innerClassDeclArity.ONE) {
- new DiamondAndInnerClassTest(innerClassDeclArity, declType, newClassType,
- argList, new TypeArgumentKind[] {taDecl1},
- new TypeArgumentKind[] {taSite1}, new ArgumentKind[] {arg1}).run(comp, fm);
+ pool.execute(
+ new DiamondAndInnerClassTest(
+ innerClassDeclArity, declType,
+ newClassType, argList,
+ new TypeArgumentKind[] {taDecl1},
+ new TypeArgumentKind[] {taSite1},
+ new ArgumentKind[] {arg1}));
continue;
}
for (TypeArgumentKind taDecl2 : TypeArgumentKind.values()) {
//no rare types
- if (isDeclRaw != (taDecl2 == TypeArgumentKind.NONE)) continue;
+ if (isDeclRaw != (taDecl2 == TypeArgumentKind.NONE))
+ continue;
//no diamond on decl site
- if (taDecl2 == TypeArgumentKind.DIAMOND) continue;
+ if (taDecl2 == TypeArgumentKind.DIAMOND)
+ continue;
for (TypeArgumentKind taSite2 : TypeArgumentKind.values()) {
//no rare types
- if (isSiteRaw != (taSite2 == TypeArgumentKind.NONE)) continue;
+ if (isSiteRaw != (taSite2 == TypeArgumentKind.NONE))
+ continue;
//diamond only allowed on the last type qualifier
if (taSite2 == TypeArgumentKind.DIAMOND &&
- innerClassDeclArity != InnerClassDeclArity.TWO) continue;
+ innerClassDeclArity != InnerClassDeclArity.TWO)
+ continue;
for (ArgumentKind arg2 : ArgumentKind.values()) {
if (innerClassDeclArity == innerClassDeclArity.TWO) {
- new DiamondAndInnerClassTest(innerClassDeclArity, declType, newClassType,
- argList, new TypeArgumentKind[] {taDecl1, taDecl2},
+ pool.execute(
+ new DiamondAndInnerClassTest(
+ innerClassDeclArity,
+ declType,
+ newClassType,
+ argList,
+ new TypeArgumentKind[] {taDecl1, taDecl2},
new TypeArgumentKind[] {taSite1, taSite2},
- new ArgumentKind[] {arg1, arg2}).run(comp, fm);
+ new ArgumentKind[] {arg1, arg2}));
continue;
}
for (TypeArgumentKind taDecl3 : TypeArgumentKind.values()) {
//no rare types
- if (isDeclRaw != (taDecl3 == TypeArgumentKind.NONE)) continue;
+ if (isDeclRaw != (taDecl3 == TypeArgumentKind.NONE))
+ continue;
//no diamond on decl site
- if (taDecl3 == TypeArgumentKind.DIAMOND) continue;
+ if (taDecl3 == TypeArgumentKind.DIAMOND)
+ continue;
for (TypeArgumentKind taSite3 : TypeArgumentKind.values()) {
//no rare types
- if (isSiteRaw != (taSite3 == TypeArgumentKind.NONE)) continue;
+ if (isSiteRaw != (taSite3 == TypeArgumentKind.NONE))
+ continue;
//diamond only allowed on the last type qualifier
if (taSite3 == TypeArgumentKind.DIAMOND &&
- innerClassDeclArity != InnerClassDeclArity.THREE) continue;
+ innerClassDeclArity != InnerClassDeclArity.THREE)
+ continue;
for (ArgumentKind arg3 : ArgumentKind.values()) {
- if (innerClassDeclArity == innerClassDeclArity.THREE) {
- new DiamondAndInnerClassTest(innerClassDeclArity, declType, newClassType,
- argList, new TypeArgumentKind[] {taDecl1, taDecl2, taDecl3},
+ if (innerClassDeclArity ==
+ innerClassDeclArity.THREE) {
+ pool.execute(
+ new DiamondAndInnerClassTest(
+ innerClassDeclArity,
+ declType,
+ newClassType,
+ argList,
+ new TypeArgumentKind[] {taDecl1, taDecl2, taDecl3},
new TypeArgumentKind[] {taSite1, taSite2, taSite3},
- new ArgumentKind[] {arg1, arg2, arg3}).run(comp, fm);
+ new ArgumentKind[] {arg1, arg2, arg3}));
continue;
}
}
@@ -230,7 +251,8 @@ public class DiamondAndInnerClassTest {
}
}
}
- System.out.println("Total check executed: " + checkCount);
+
+ checkAfterExec();
}
InnerClassDeclArity innerClassDeclArity;
@@ -244,9 +266,9 @@ public class DiamondAndInnerClassTest {
DiagnosticChecker diagChecker;
DiamondAndInnerClassTest(InnerClassDeclArity innerClassDeclArity,
- TypeQualifierArity declType, TypeQualifierArity siteType, ArgumentListArity argList,
- TypeArgumentKind[] declTypeArgumentKinds, TypeArgumentKind[] siteTypeArgumentKinds,
- ArgumentKind[] argumentKinds) {
+ TypeQualifierArity declType, TypeQualifierArity siteType,
+ ArgumentListArity argList, TypeArgumentKind[] declTypeArgumentKinds,
+ TypeArgumentKind[] siteTypeArgumentKinds, ArgumentKind[] argumentKinds) {
this.innerClassDeclArity = innerClassDeclArity;
this.declType = declType;
this.siteType = siteType;
@@ -267,9 +289,9 @@ public class DiamondAndInnerClassTest {
public JavaSource() {
super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
source = innerClassDeclArity.classDeclStr.replace("#B", bodyTemplate)
- .replace("#D", declType.getType(declTypeArgumentKinds))
- .replace("#S", siteType.getType(siteTypeArgumentKinds))
- .replace("#AL", argList.getArgs(argumentKinds));
+ .replace("#D", declType.getType(declTypeArgumentKinds))
+ .replace("#S", siteType.getType(siteTypeArgumentKinds))
+ .replace("#AL", argList.getArgs(argumentKinds));
}
@Override
@@ -278,36 +300,39 @@ public class DiamondAndInnerClassTest {
}
}
- void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception {
- JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker,
+ @Override
+ public void run() {
+ JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker,
null, null, Arrays.asList(source));
try {
ct.analyze();
} catch (Throwable ex) {
- throw new AssertionError("Error thrown when compiling the following code:\n" + source.getCharContent(true));
+ throw new AssertionError("Error thrown when compiling the following code:\n" +
+ source.getCharContent(true));
}
check();
}
void check() {
- checkCount++;
+ checkCount.incrementAndGet();
boolean errorExpected = false;
- TypeArgumentKind[] expectedArgKinds = new TypeArgumentKind[innerClassDeclArity.n];
+ TypeArgumentKind[] expectedArgKinds =
+ new TypeArgumentKind[innerClassDeclArity.n];
for (int i = 0 ; i < innerClassDeclArity.n ; i++) {
if (!declTypeArgumentKinds[i].compatible(siteTypeArgumentKinds[i])) {
errorExpected = true;
break;
}
- expectedArgKinds[i] = siteTypeArgumentKinds[i] == TypeArgumentKind.DIAMOND ?
+ expectedArgKinds[i] = siteTypeArgumentKinds[i] ==
+ TypeArgumentKind.DIAMOND ?
declTypeArgumentKinds[i] : siteTypeArgumentKinds[i];
}
if (!errorExpected) {
for (int i = 0 ; i < innerClassDeclArity.n ; i++) {
- //System.out.println("check " + expectedArgKinds[i] + " against " + argumentKinds[i]);
if (!expectedArgKinds[i].compatible(argumentKinds[i])) {
errorExpected = true;
break;
@@ -323,7 +348,8 @@ public class DiamondAndInnerClassTest {
}
}
- static class DiagnosticChecker implements javax.tools.DiagnosticListener {
+ static class DiagnosticChecker
+ implements javax.tools.DiagnosticListener