8145862: Improve lazy initialization of fields in java.net.URI

Reviewed-by: shade, chegar
This commit is contained in:
Claes Redestad 2015-12-22 19:14:47 +01:00
parent 22df7c453f
commit c6afc47fc1

View File

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