8145862: Improve lazy initialization of fields in java.net.URI
Reviewed-by: shade, chegar
This commit is contained in:
parent
22df7c453f
commit
c6afc47fc1
@ -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 --
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user