--- a/jdk/src/java.base/share/classes/java/net/URI.java Tue Dec 22 16:42:16 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/net/URI.java Tue Dec 22 19:14:47 2015 +0100
@@ -489,17 +489,17 @@
private transient String path; // null ==> opaque
private transient String query;
- // The remaining fields may be computed on demand
-
- private transient volatile String schemeSpecificPart;
- private transient volatile int hash; // Zero ==> undefined
-
- private transient volatile String decodedUserInfo;
- private transient volatile String decodedAuthority;
- private transient volatile String decodedPath;
- private transient volatile String decodedQuery;
- private transient volatile String decodedFragment;
- private transient volatile String decodedSchemeSpecificPart;
+ // The remaining fields may be computed on demand, which is safe even in
+ // the face of multiple threads racing to initialize them
+ private transient String schemeSpecificPart;
+ private transient int hash; // Zero ==> undefined
+
+ private transient String decodedUserInfo;
+ private transient String decodedAuthority;
+ private transient String decodedPath;
+ private transient String decodedQuery;
+ private transient String decodedFragment;
+ private transient String decodedSchemeSpecificPart;
/**
* The string form of this URI.
@@ -910,8 +910,7 @@
// either more fields or a more-obscure representation.
if ((host != null) || (authority == null))
return this;
- defineString();
- new Parser(string).parse(true);
+ new Parser(toString()).parse(true);
return this;
}
@@ -1143,8 +1142,17 @@
* (never {@code null})
*/
public String getRawSchemeSpecificPart() {
- defineSchemeSpecificPart();
- return schemeSpecificPart;
+ String part = schemeSpecificPart;
+ if (part != null) {
+ return part;
+ }
+ StringBuilder sb = new StringBuilder();
+ appendSchemeSpecificPart(sb, null, getAuthority(), getUserInfo(),
+ host, port, getPath(), getQuery());
+ if (sb.length() == 0) {
+ return null;
+ }
+ return schemeSpecificPart = sb.toString();
}
/**
@@ -1159,9 +1167,11 @@
* (never {@code null})
*/
public String getSchemeSpecificPart() {
- if (decodedSchemeSpecificPart == null)
- decodedSchemeSpecificPart = decode(getRawSchemeSpecificPart());
- return decodedSchemeSpecificPart;
+ String part = decodedSchemeSpecificPart;
+ if (part == null) {
+ decodedSchemeSpecificPart = part = decode(getRawSchemeSpecificPart());
+ }
+ return part;
}
/**
@@ -1192,9 +1202,11 @@
* or {@code null} if the authority is undefined
*/
public String getAuthority() {
- if (decodedAuthority == null)
- decodedAuthority = decode(authority);
- return decodedAuthority;
+ String auth = decodedAuthority;
+ if ((auth == null) && (authority != null)) {
+ decodedAuthority = auth = decode(authority);
+ }
+ return auth;
}
/**
@@ -1222,9 +1234,11 @@
* or {@code null} if the user information is undefined
*/
public String getUserInfo() {
- if ((decodedUserInfo == null) && (userInfo != null))
- decodedUserInfo = decode(userInfo);
- return decodedUserInfo;
+ String user = decodedUserInfo;
+ if ((user == null) && (userInfo != null)) {
+ decodedUserInfo = user = decode(userInfo);
+ }
+ return user;
}
/**
@@ -1306,9 +1320,11 @@
* or {@code null} if the path is undefined
*/
public String getPath() {
- if ((decodedPath == null) && (path != null))
- decodedPath = decode(path);
- return decodedPath;
+ String decoded = decodedPath;
+ if ((decoded == null) && (path != null)) {
+ decodedPath = decoded = decode(path);
+ }
+ return decoded;
}
/**
@@ -1335,9 +1351,11 @@
* or {@code null} if the query is undefined
*/
public String getQuery() {
- if ((decodedQuery == null) && (query != null))
- decodedQuery = decode(query, false);
- return decodedQuery;
+ String decoded = decodedQuery;
+ if ((decoded == null) && (query != null)) {
+ decodedQuery = decoded = decode(query, false);
+ }
+ return decoded;
}
/**
@@ -1364,9 +1382,11 @@
* or {@code null} if the fragment is undefined
*/
public String getFragment() {
- if ((decodedFragment == null) && (fragment != null))
- decodedFragment = decode(fragment, false);
- return decodedFragment;
+ String decoded = decodedFragment;
+ if ((decoded == null) && (fragment != null)) {
+ decodedFragment = decoded = decode(fragment, false);
+ }
+ return decoded;
}
@@ -1452,24 +1472,27 @@
* @return A hash-code value for this URI
*/
public int hashCode() {
- if (hash != 0)
- return hash;
- int h = hashIgnoringCase(0, scheme);
- h = hash(h, fragment);
- if (isOpaque()) {
- h = hash(h, schemeSpecificPart);
- } else {
- h = hash(h, path);
- h = hash(h, query);
- if (host != null) {
- h = hash(h, userInfo);
- h = hashIgnoringCase(h, host);
- h += 1949 * port;
+ int h = hash;
+ if (h == 0) {
+ h = hashIgnoringCase(0, scheme);
+ h = hash(h, fragment);
+ if (isOpaque()) {
+ h = hash(h, schemeSpecificPart);
} else {
- h = hash(h, authority);
+ h = hash(h, path);
+ h = hash(h, query);
+ if (host != null) {
+ h = hash(h, userInfo);
+ h = hashIgnoringCase(h, host);
+ h += 1949 * port;
+ } else {
+ h = hash(h, authority);
+ }
+ }
+ if (h != 0) {
+ hash = h;
}
}
- hash = h;
return h;
}
@@ -1599,8 +1622,59 @@
* @return The string form of this URI
*/
public String toString() {
- defineString();
- return string;
+ String s = string;
+ if (s == null) {
+ s = defineString();
+ }
+ return s;
+ }
+
+ private String defineString() {
+ String s = string;
+ if (s != null) {
+ return s;
+ }
+
+ StringBuilder sb = new StringBuilder();
+ if (scheme != null) {
+ sb.append(scheme);
+ sb.append(':');
+ }
+ if (isOpaque()) {
+ sb.append(schemeSpecificPart);
+ } else {
+ if (host != null) {
+ sb.append("//");
+ if (userInfo != null) {
+ sb.append(userInfo);
+ sb.append('@');
+ }
+ boolean needBrackets = ((host.indexOf(':') >= 0)
+ && !host.startsWith("[")
+ && !host.endsWith("]"));
+ if (needBrackets) sb.append('[');
+ sb.append(host);
+ if (needBrackets) sb.append(']');
+ if (port != -1) {
+ sb.append(':');
+ sb.append(port);
+ }
+ } else if (authority != null) {
+ sb.append("//");
+ sb.append(authority);
+ }
+ if (path != null)
+ sb.append(path);
+ if (query != null) {
+ sb.append('?');
+ sb.append(query);
+ }
+ }
+ if (fragment != null) {
+ sb.append('#');
+ sb.append(fragment);
+ }
+ return string = sb.toString();
}
/**
@@ -1617,8 +1691,7 @@
* charset
*/
public String toASCIIString() {
- defineString();
- return encode(string);
+ return encode(toString());
}
@@ -1824,7 +1897,7 @@
}
}
- private void appendAuthority(StringBuffer sb,
+ private void appendAuthority(StringBuilder sb,
String authority,
String userInfo,
String host,
@@ -1874,7 +1947,7 @@
}
}
- private void appendSchemeSpecificPart(StringBuffer sb,
+ private void appendSchemeSpecificPart(StringBuilder sb,
String opaquePart,
String authority,
String userInfo,
@@ -1915,7 +1988,7 @@
}
}
- private void appendFragment(StringBuffer sb, String fragment) {
+ private void appendFragment(StringBuilder sb, String fragment) {
if (fragment != null) {
sb.append('#');
sb.append(quote(fragment, L_URIC, H_URIC));
@@ -1932,7 +2005,7 @@
String query,
String fragment)
{
- StringBuffer sb = new StringBuffer();
+ StringBuilder sb = new StringBuilder();
if (scheme != null) {
sb.append(scheme);
sb.append(':');
@@ -1944,61 +2017,6 @@
return sb.toString();
}
- private void defineSchemeSpecificPart() {
- if (schemeSpecificPart != null) return;
- StringBuffer sb = new StringBuffer();
- appendSchemeSpecificPart(sb, null, getAuthority(), getUserInfo(),
- host, port, getPath(), getQuery());
- if (sb.length() == 0) return;
- schemeSpecificPart = sb.toString();
- }
-
- private void defineString() {
- if (string != null) return;
-
- StringBuilder sb = new StringBuilder();
- if (scheme != null) {
- sb.append(scheme);
- sb.append(':');
- }
- if (isOpaque()) {
- sb.append(schemeSpecificPart);
- } else {
- if (host != null) {
- sb.append("//");
- if (userInfo != null) {
- sb.append(userInfo);
- sb.append('@');
- }
- boolean needBrackets = ((host.indexOf(':') >= 0)
- && !host.startsWith("[")
- && !host.endsWith("]"));
- if (needBrackets) sb.append('[');
- sb.append(host);
- if (needBrackets) sb.append(']');
- if (port != -1) {
- sb.append(':');
- sb.append(port);
- }
- } else if (authority != null) {
- sb.append("//");
- sb.append(authority);
- }
- if (path != null)
- sb.append(path);
- if (query != null) {
- sb.append('?');
- sb.append(query);
- }
- }
- if (fragment != null) {
- sb.append('#');
- sb.append(fragment);
- }
- string = sb.toString();
- }
-
-
// -- Normalization, resolution, and relativization --
// RFC2396 5.2 (6)
@@ -2649,13 +2667,13 @@
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
- private static void appendEscape(StringBuffer sb, byte b) {
+ private static void appendEscape(StringBuilder sb, byte b) {
sb.append('%');
sb.append(hexDigits[(b >> 4) & 0x0f]);
sb.append(hexDigits[(b >> 0) & 0x0f]);
}
- private static void appendEncoded(StringBuffer sb, char c) {
+ private static void appendEncoded(StringBuilder sb, char c) {
ByteBuffer bb = null;
try {
bb = ThreadLocalCoders.encoderFor("UTF-8")
@@ -2676,15 +2694,14 @@
// by the given mask pair
//
private static String quote(String s, long lowMask, long highMask) {
- int n = s.length();
- StringBuffer sb = null;
+ StringBuilder sb = null;
boolean allowNonASCII = ((lowMask & L_ESCAPED) != 0);
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c < '\u0080') {
if (!match(c, lowMask, highMask)) {
if (sb == null) {
- sb = new StringBuffer();
+ sb = new StringBuilder();
sb.append(s, 0, i);
}
appendEscape(sb, (byte)c);
@@ -2696,7 +2713,7 @@
&& (Character.isSpaceChar(c)
|| Character.isISOControl(c))) {
if (sb == null) {
- sb = new StringBuffer();
+ sb = new StringBuilder();
sb.append(s, 0, i);
}
appendEncoded(sb, c);
@@ -2733,7 +2750,7 @@
assert false;
}
- StringBuffer sb = new StringBuffer();
+ StringBuilder sb = new StringBuilder();
while (bb.hasRemaining()) {
int b = bb.get() & 0xff;
if (b >= 0x80)
@@ -2864,12 +2881,6 @@
fail("Expected " + expected, p);
}
- private void failExpecting(String expected, String prior, int p)
- throws URISyntaxException
- {
- fail("Expected " + expected + " following " + prior, p);
- }
-
// -- Simple access to the input string --