Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in / Register
Toggle navigation
S
spring-boot
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
DEMO
spring-boot
Commits
e3bfd797
Commit
e3bfd797
authored
Jan 04, 2018
by
Stephane Nicoll
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch '1.5.x'
parents
bee5fa7f
d49b022c
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
2612 additions
and
20 deletions
+2612
-20
checkstyle-suppressions.xml
...ng-boot-parent/src/checkstyle/checkstyle-suppressions.xml
+1
-0
pom.xml
...ng-boot-tools/spring-boot-configuration-processor/pom.xml
+1
-6
JSONOrderedObject.java
...ot/configurationprocessor/metadata/JSONOrderedObject.java
+3
-3
JsonConverter.java
...k/boot/configurationprocessor/metadata/JsonConverter.java
+3
-4
JsonMarshaller.java
.../boot/configurationprocessor/metadata/JsonMarshaller.java
+3
-4
ConfigurationMetadataAnnotationProcessorTests.java
...cessor/ConfigurationMetadataAnnotationProcessorTests.java
+3
-3
JSON.java
...pringframework/boot/configurationprocessor/json/JSON.java
+116
-0
JSONArray.java
...framework/boot/configurationprocessor/json/JSONArray.java
+615
-0
JSONException.java
...ework/boot/configurationprocessor/json/JSONException.java
+49
-0
JSONObject.java
...ramework/boot/configurationprocessor/json/JSONObject.java
+775
-0
JSONStringer.java
...mework/boot/configurationprocessor/json/JSONStringer.java
+432
-0
JSONTokener.java
...amework/boot/configurationprocessor/json/JSONTokener.java
+611
-0
No files found.
spring-boot-project/spring-boot-parent/src/checkstyle/checkstyle-suppressions.xml
View file @
e3bfd797
...
@@ -22,4 +22,5 @@
...
@@ -22,4 +22,5 @@
<suppress
files=
"Ansi.*\.java"
checks=
"JavadocStyle"
/>
<suppress
files=
"Ansi.*\.java"
checks=
"JavadocStyle"
/>
<suppress
files=
"LogLevel\.java"
checks=
"JavadocVariable"
/>
<suppress
files=
"LogLevel\.java"
checks=
"JavadocVariable"
/>
<suppress
files=
"HelpMojo\.java"
checks=
".*"
/>
<suppress
files=
"HelpMojo\.java"
checks=
".*"
/>
<suppress
files=
"[\\/]org.springframework.boot.configurationprocessor.json[\\/].*\.java$"
checks=
".*"
/>
</suppressions>
</suppressions>
spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/pom.xml
View file @
e3bfd797
...
@@ -14,12 +14,7 @@
...
@@ -14,12 +14,7 @@
<main.basedir>
${basedir}/../../..
</main.basedir>
<main.basedir>
${basedir}/../../..
</main.basedir>
</properties>
</properties>
<dependencies>
<dependencies>
<!-- Compile (should stick to the bare minimum) -->
<!-- Test -->
<dependency>
<groupId>
com.vaadin.external.google
</groupId>
<artifactId>
android-json
</artifactId>
</dependency>
<!-- Test -->
<dependency>
<dependency>
<groupId>
org.projectlombok
</groupId>
<groupId>
org.projectlombok
</groupId>
<artifactId>
lombok
</artifactId>
<artifactId>
lombok
</artifactId>
...
...
spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/JSONOrderedObject.java
View file @
e3bfd797
/*
/*
* Copyright 2012-201
7
the original author or authors.
* Copyright 2012-201
8
the original author or authors.
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* you may not use this file except in compliance with the License.
...
@@ -20,8 +20,8 @@ import java.util.Iterator;
...
@@ -20,8 +20,8 @@ import java.util.Iterator;
import
java.util.LinkedHashSet
;
import
java.util.LinkedHashSet
;
import
java.util.Set
;
import
java.util.Set
;
import
org.json.JSONException
;
import
org.
springframework.boot.configurationprocessor.
json.JSONException
;
import
org.json.JSONObject
;
import
org.
springframework.boot.configurationprocessor.
json.JSONObject
;
/**
/**
* Extension to {@link JSONObject} that remembers the order of inserts.
* Extension to {@link JSONObject} that remembers the order of inserts.
...
...
spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/JsonConverter.java
View file @
e3bfd797
/*
/*
* Copyright 2012-201
7
the original author or authors.
* Copyright 2012-201
8
the original author or authors.
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* you may not use this file except in compliance with the License.
...
@@ -20,9 +20,8 @@ import java.lang.reflect.Array;
...
@@ -20,9 +20,8 @@ import java.lang.reflect.Array;
import
java.util.Collection
;
import
java.util.Collection
;
import
java.util.Map
;
import
java.util.Map
;
import
org.json.JSONArray
;
import
org.springframework.boot.configurationprocessor.json.JSONArray
;
import
org.json.JSONObject
;
import
org.springframework.boot.configurationprocessor.json.JSONObject
;
import
org.springframework.boot.configurationprocessor.metadata.ItemMetadata.ItemType
;
import
org.springframework.boot.configurationprocessor.metadata.ItemMetadata.ItemType
;
/**
/**
...
...
spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/JsonMarshaller.java
View file @
e3bfd797
/*
/*
* Copyright 2012-201
7
the original author or authors.
* Copyright 2012-201
8
the original author or authors.
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* you may not use this file except in compliance with the License.
...
@@ -27,9 +27,8 @@ import java.util.Iterator;
...
@@ -27,9 +27,8 @@ import java.util.Iterator;
import
java.util.List
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Map
;
import
org.json.JSONArray
;
import
org.springframework.boot.configurationprocessor.json.JSONArray
;
import
org.json.JSONObject
;
import
org.springframework.boot.configurationprocessor.json.JSONObject
;
import
org.springframework.boot.configurationprocessor.metadata.ItemMetadata.ItemType
;
import
org.springframework.boot.configurationprocessor.metadata.ItemMetadata.ItemType
;
/**
/**
...
...
spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessorTests.java
View file @
e3bfd797
/*
/*
* Copyright 2012-201
7
the original author or authors.
* Copyright 2012-201
8
the original author or authors.
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* you may not use this file except in compliance with the License.
...
@@ -23,14 +23,14 @@ import java.time.Duration;
...
@@ -23,14 +23,14 @@ import java.time.Duration;
import
java.util.Arrays
;
import
java.util.Arrays
;
import
java.util.Collections
;
import
java.util.Collections
;
import
org.json.JSONArray
;
import
org.json.JSONObject
;
import
org.junit.Before
;
import
org.junit.Before
;
import
org.junit.Rule
;
import
org.junit.Rule
;
import
org.junit.Test
;
import
org.junit.Test
;
import
org.junit.rules.ExpectedException
;
import
org.junit.rules.ExpectedException
;
import
org.junit.rules.TemporaryFolder
;
import
org.junit.rules.TemporaryFolder
;
import
org.springframework.boot.configurationprocessor.json.JSONArray
;
import
org.springframework.boot.configurationprocessor.json.JSONObject
;
import
org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata
;
import
org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata
;
import
org.springframework.boot.configurationprocessor.metadata.ItemDeprecation
;
import
org.springframework.boot.configurationprocessor.metadata.ItemDeprecation
;
import
org.springframework.boot.configurationprocessor.metadata.ItemHint
;
import
org.springframework.boot.configurationprocessor.metadata.ItemHint
;
...
...
spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/json/JSON.java
0 → 100644
View file @
e3bfd797
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
springframework
.
boot
.
configurationprocessor
.
json
;
class
JSON
{
/**
* Returns the input if it is a JSON-permissible value; throws otherwise.
*/
static
double
checkDouble
(
double
d
)
throws
JSONException
{
if
(
Double
.
isInfinite
(
d
)
||
Double
.
isNaN
(
d
))
{
throw
new
JSONException
(
"Forbidden numeric value: "
+
d
);
}
return
d
;
}
static
Boolean
toBoolean
(
Object
value
)
{
if
(
value
instanceof
Boolean
)
{
return
(
Boolean
)
value
;
}
else
if
(
value
instanceof
String
)
{
String
stringValue
=
(
String
)
value
;
if
(
"true"
.
equalsIgnoreCase
(
stringValue
))
{
return
true
;
}
else
if
(
"false"
.
equalsIgnoreCase
(
stringValue
))
{
return
false
;
}
}
return
null
;
}
static
Double
toDouble
(
Object
value
)
{
if
(
value
instanceof
Double
)
{
return
(
Double
)
value
;
}
else
if
(
value
instanceof
Number
)
{
return
((
Number
)
value
).
doubleValue
();
}
else
if
(
value
instanceof
String
)
{
try
{
return
Double
.
valueOf
((
String
)
value
);
}
catch
(
NumberFormatException
ignored
)
{
}
}
return
null
;
}
static
Integer
toInteger
(
Object
value
)
{
if
(
value
instanceof
Integer
)
{
return
(
Integer
)
value
;
}
else
if
(
value
instanceof
Number
)
{
return
((
Number
)
value
).
intValue
();
}
else
if
(
value
instanceof
String
)
{
try
{
return
(
int
)
Double
.
parseDouble
((
String
)
value
);
}
catch
(
NumberFormatException
ignored
)
{
}
}
return
null
;
}
static
Long
toLong
(
Object
value
)
{
if
(
value
instanceof
Long
)
{
return
(
Long
)
value
;
}
else
if
(
value
instanceof
Number
)
{
return
((
Number
)
value
).
longValue
();
}
else
if
(
value
instanceof
String
)
{
try
{
return
(
long
)
Double
.
parseDouble
((
String
)
value
);
}
catch
(
NumberFormatException
ignored
)
{
}
}
return
null
;
}
static
String
toString
(
Object
value
)
{
if
(
value
instanceof
String
)
{
return
(
String
)
value
;
}
else
if
(
value
!=
null
)
{
return
String
.
valueOf
(
value
);
}
return
null
;
}
public
static
JSONException
typeMismatch
(
Object
indexOrName
,
Object
actual
,
String
requiredType
)
throws
JSONException
{
if
(
actual
==
null
)
{
throw
new
JSONException
(
"Value at "
+
indexOrName
+
" is null."
);
}
else
{
throw
new
JSONException
(
"Value "
+
actual
+
" at "
+
indexOrName
+
" of type "
+
actual
.
getClass
().
getName
()
+
" cannot be converted to "
+
requiredType
);
}
}
public
static
JSONException
typeMismatch
(
Object
actual
,
String
requiredType
)
throws
JSONException
{
if
(
actual
==
null
)
{
throw
new
JSONException
(
"Value is null."
);
}
else
{
throw
new
JSONException
(
"Value "
+
actual
+
" of type "
+
actual
.
getClass
().
getName
()
+
" cannot be converted to "
+
requiredType
);
}
}
}
spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/json/JSONArray.java
0 → 100644
View file @
e3bfd797
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
springframework
.
boot
.
configurationprocessor
.
json
;
import
java.lang.reflect.Array
;
import
java.util.ArrayList
;
import
java.util.Collection
;
import
java.util.Iterator
;
import
java.util.List
;
// Note: this class was written without inspecting the non-free org.json sourcecode.
/**
* A dense indexed sequence of values. Values may be any mix of
* {@link JSONObject JSONObjects}, other {@link JSONArray JSONArrays}, Strings,
* Booleans, Integers, Longs, Doubles, {@code null} or {@link JSONObject#NULL}.
* Values may not be {@link Double#isNaN() NaNs}, {@link Double#isInfinite()
* infinities}, or of any type not listed here.
*
* <p>{@code JSONArray} has the same type coercion behavior and
* optional/mandatory accessors as {@link JSONObject}. See that class'
* documentation for details.
*
* <p><strong>Warning:</strong> this class represents null in two incompatible
* ways: the standard Java {@code null} reference, and the sentinel value {@link
* JSONObject#NULL}. In particular, {@code get} fails if the requested index
* holds the null reference, but succeeds if it holds {@code JSONObject.NULL}.
*
* <p>Instances of this class are not thread safe. Although this class is
* nonfinal, it was not designed for inheritance and should not be subclassed.
* In particular, self-use by overridable methods is not specified. See
* <i>Effective Java</i> Item 17, "Design and Document or inheritance or else
* prohibit it" for further information.
*/
public
class
JSONArray
{
private
final
List
<
Object
>
values
;
/**
* Creates a {@code JSONArray} with no values.
*/
public
JSONArray
()
{
values
=
new
ArrayList
<
Object
>();
}
/**
* Creates a new {@code JSONArray} by copying all values from the given
* collection.
*
* @param copyFrom a collection whose values are of supported types.
* Unsupported values are not permitted and will yield an array in an
* inconsistent state.
*/
/* Accept a raw type for API compatibility */
public
JSONArray
(
Collection
copyFrom
)
{
this
();
if
(
copyFrom
!=
null
)
{
for
(
Iterator
it
=
copyFrom
.
iterator
();
it
.
hasNext
();)
{
put
(
JSONObject
.
wrap
(
it
.
next
()));
}
}
}
/**
* Creates a new {@code JSONArray} with values from the next array in the
* tokener.
*
* @param readFrom a tokener whose nextValue() method will yield a
* {@code JSONArray}.
* @throws JSONException if the parse fails or doesn't yield a
* {@code JSONArray}.
*/
public
JSONArray
(
JSONTokener
readFrom
)
throws
JSONException
{
/*
* Getting the parser to populate this could get tricky. Instead, just
* parse to temporary JSONArray and then steal the data from that.
*/
Object
object
=
readFrom
.
nextValue
();
if
(
object
instanceof
JSONArray
)
{
values
=
((
JSONArray
)
object
).
values
;
}
else
{
throw
JSON
.
typeMismatch
(
object
,
"JSONArray"
);
}
}
/**
* Creates a new {@code JSONArray} with values from the JSON string.
*
* @param json a JSON-encoded string containing an array.
* @throws JSONException if the parse fails or doesn't yield a {@code
* JSONArray}.
*/
public
JSONArray
(
String
json
)
throws
JSONException
{
this
(
new
JSONTokener
(
json
));
}
/**
* Creates a new {@code JSONArray} with values from the given primitive array.
*/
public
JSONArray
(
Object
array
)
throws
JSONException
{
if
(!
array
.
getClass
().
isArray
())
{
throw
new
JSONException
(
"Not a primitive array: "
+
array
.
getClass
());
}
final
int
length
=
Array
.
getLength
(
array
);
values
=
new
ArrayList
<
Object
>(
length
);
for
(
int
i
=
0
;
i
<
length
;
++
i
)
{
put
(
JSONObject
.
wrap
(
Array
.
get
(
array
,
i
)));
}
}
/**
* Returns the number of values in this array.
*/
public
int
length
()
{
return
values
.
size
();
}
/**
* Appends {@code value} to the end of this array.
*
* @return this array.
*/
public
JSONArray
put
(
boolean
value
)
{
values
.
add
(
value
);
return
this
;
}
/**
* Appends {@code value} to the end of this array.
*
* @param value a finite value. May not be {@link Double#isNaN() NaNs} or
* {@link Double#isInfinite() infinities}.
* @return this array.
*/
public
JSONArray
put
(
double
value
)
throws
JSONException
{
values
.
add
(
JSON
.
checkDouble
(
value
));
return
this
;
}
/**
* Appends {@code value} to the end of this array.
*
* @return this array.
*/
public
JSONArray
put
(
int
value
)
{
values
.
add
(
value
);
return
this
;
}
/**
* Appends {@code value} to the end of this array.
*
* @return this array.
*/
public
JSONArray
put
(
long
value
)
{
values
.
add
(
value
);
return
this
;
}
/**
* Appends {@code value} to the end of this array.
*
* @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean,
* Integer, Long, Double, {@link JSONObject#NULL}, or {@code null}. May
* not be {@link Double#isNaN() NaNs} or {@link Double#isInfinite()
* infinities}. Unsupported values are not permitted and will cause the
* array to be in an inconsistent state.
* @return this array.
*/
public
JSONArray
put
(
Object
value
)
{
values
.
add
(
value
);
return
this
;
}
/**
* Sets the value at {@code index} to {@code value}, null padding this array
* to the required length if necessary. If a value already exists at {@code
* index}, it will be replaced.
*
* @return this array.
*/
public
JSONArray
put
(
int
index
,
boolean
value
)
throws
JSONException
{
return
put
(
index
,
(
Boolean
)
value
);
}
/**
* Sets the value at {@code index} to {@code value}, null padding this array
* to the required length if necessary. If a value already exists at {@code
* index}, it will be replaced.
*
* @param value a finite value. May not be {@link Double#isNaN() NaNs} or
* {@link Double#isInfinite() infinities}.
* @return this array.
*/
public
JSONArray
put
(
int
index
,
double
value
)
throws
JSONException
{
return
put
(
index
,
(
Double
)
value
);
}
/**
* Sets the value at {@code index} to {@code value}, null padding this array
* to the required length if necessary. If a value already exists at {@code
* index}, it will be replaced.
*
* @return this array.
*/
public
JSONArray
put
(
int
index
,
int
value
)
throws
JSONException
{
return
put
(
index
,
(
Integer
)
value
);
}
/**
* Sets the value at {@code index} to {@code value}, null padding this array
* to the required length if necessary. If a value already exists at {@code
* index}, it will be replaced.
*
* @return this array.
*/
public
JSONArray
put
(
int
index
,
long
value
)
throws
JSONException
{
return
put
(
index
,
(
Long
)
value
);
}
/**
* Sets the value at {@code index} to {@code value}, null padding this array
* to the required length if necessary. If a value already exists at {@code
* index}, it will be replaced.
*
* @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean,
* Integer, Long, Double, {@link JSONObject#NULL}, or {@code null}. May
* not be {@link Double#isNaN() NaNs} or {@link Double#isInfinite()
* infinities}.
* @return this array.
*/
public
JSONArray
put
(
int
index
,
Object
value
)
throws
JSONException
{
if
(
value
instanceof
Number
)
{
// deviate from the original by checking all Numbers, not just floats & doubles
JSON
.
checkDouble
(((
Number
)
value
).
doubleValue
());
}
while
(
values
.
size
()
<=
index
)
{
values
.
add
(
null
);
}
values
.
set
(
index
,
value
);
return
this
;
}
/**
* Returns true if this array has no value at {@code index}, or if its value
* is the {@code null} reference or {@link JSONObject#NULL}.
*/
public
boolean
isNull
(
int
index
)
{
Object
value
=
opt
(
index
);
return
value
==
null
||
value
==
JSONObject
.
NULL
;
}
/**
* Returns the value at {@code index}.
*
* @throws JSONException if this array has no value at {@code index}, or if
* that value is the {@code null} reference. This method returns
* normally if the value is {@code JSONObject#NULL}.
*/
public
Object
get
(
int
index
)
throws
JSONException
{
try
{
Object
value
=
values
.
get
(
index
);
if
(
value
==
null
)
{
throw
new
JSONException
(
"Value at "
+
index
+
" is null."
);
}
return
value
;
}
catch
(
IndexOutOfBoundsException
e
)
{
throw
new
JSONException
(
"Index "
+
index
+
" out of range [0.."
+
values
.
size
()
+
")"
);
}
}
/**
* Returns the value at {@code index}, or null if the array has no value
* at {@code index}.
*/
public
Object
opt
(
int
index
)
{
if
(
index
<
0
||
index
>=
values
.
size
())
{
return
null
;
}
return
values
.
get
(
index
);
}
/**
* Removes and returns the value at {@code index}, or null if the array has no value
* at {@code index}.
*/
public
Object
remove
(
int
index
)
{
if
(
index
<
0
||
index
>=
values
.
size
())
{
return
null
;
}
return
values
.
remove
(
index
);
}
/**
* Returns the value at {@code index} if it exists and is a boolean or can
* be coerced to a boolean.
*
* @throws JSONException if the value at {@code index} doesn't exist or
* cannot be coerced to a boolean.
*/
public
boolean
getBoolean
(
int
index
)
throws
JSONException
{
Object
object
=
get
(
index
);
Boolean
result
=
JSON
.
toBoolean
(
object
);
if
(
result
==
null
)
{
throw
JSON
.
typeMismatch
(
index
,
object
,
"boolean"
);
}
return
result
;
}
/**
* Returns the value at {@code index} if it exists and is a boolean or can
* be coerced to a boolean. Returns false otherwise.
*/
public
boolean
optBoolean
(
int
index
)
{
return
optBoolean
(
index
,
false
);
}
/**
* Returns the value at {@code index} if it exists and is a boolean or can
* be coerced to a boolean. Returns {@code fallback} otherwise.
*/
public
boolean
optBoolean
(
int
index
,
boolean
fallback
)
{
Object
object
=
opt
(
index
);
Boolean
result
=
JSON
.
toBoolean
(
object
);
return
result
!=
null
?
result
:
fallback
;
}
/**
* Returns the value at {@code index} if it exists and is a double or can
* be coerced to a double.
*
* @throws JSONException if the value at {@code index} doesn't exist or
* cannot be coerced to a double.
*/
public
double
getDouble
(
int
index
)
throws
JSONException
{
Object
object
=
get
(
index
);
Double
result
=
JSON
.
toDouble
(
object
);
if
(
result
==
null
)
{
throw
JSON
.
typeMismatch
(
index
,
object
,
"double"
);
}
return
result
;
}
/**
* Returns the value at {@code index} if it exists and is a double or can
* be coerced to a double. Returns {@code NaN} otherwise.
*/
public
double
optDouble
(
int
index
)
{
return
optDouble
(
index
,
Double
.
NaN
);
}
/**
* Returns the value at {@code index} if it exists and is a double or can
* be coerced to a double. Returns {@code fallback} otherwise.
*/
public
double
optDouble
(
int
index
,
double
fallback
)
{
Object
object
=
opt
(
index
);
Double
result
=
JSON
.
toDouble
(
object
);
return
result
!=
null
?
result
:
fallback
;
}
/**
* Returns the value at {@code index} if it exists and is an int or
* can be coerced to an int.
*
* @throws JSONException if the value at {@code index} doesn't exist or
* cannot be coerced to a int.
*/
public
int
getInt
(
int
index
)
throws
JSONException
{
Object
object
=
get
(
index
);
Integer
result
=
JSON
.
toInteger
(
object
);
if
(
result
==
null
)
{
throw
JSON
.
typeMismatch
(
index
,
object
,
"int"
);
}
return
result
;
}
/**
* Returns the value at {@code index} if it exists and is an int or
* can be coerced to an int. Returns 0 otherwise.
*/
public
int
optInt
(
int
index
)
{
return
optInt
(
index
,
0
);
}
/**
* Returns the value at {@code index} if it exists and is an int or
* can be coerced to an int. Returns {@code fallback} otherwise.
*/
public
int
optInt
(
int
index
,
int
fallback
)
{
Object
object
=
opt
(
index
);
Integer
result
=
JSON
.
toInteger
(
object
);
return
result
!=
null
?
result
:
fallback
;
}
/**
* Returns the value at {@code index} if it exists and is a long or
* can be coerced to a long.
*
* @throws JSONException if the value at {@code index} doesn't exist or
* cannot be coerced to a long.
*/
public
long
getLong
(
int
index
)
throws
JSONException
{
Object
object
=
get
(
index
);
Long
result
=
JSON
.
toLong
(
object
);
if
(
result
==
null
)
{
throw
JSON
.
typeMismatch
(
index
,
object
,
"long"
);
}
return
result
;
}
/**
* Returns the value at {@code index} if it exists and is a long or
* can be coerced to a long. Returns 0 otherwise.
*/
public
long
optLong
(
int
index
)
{
return
optLong
(
index
,
0L
);
}
/**
* Returns the value at {@code index} if it exists and is a long or
* can be coerced to a long. Returns {@code fallback} otherwise.
*/
public
long
optLong
(
int
index
,
long
fallback
)
{
Object
object
=
opt
(
index
);
Long
result
=
JSON
.
toLong
(
object
);
return
result
!=
null
?
result
:
fallback
;
}
/**
* Returns the value at {@code index} if it exists, coercing it if
* necessary.
*
* @throws JSONException if no such value exists.
*/
public
String
getString
(
int
index
)
throws
JSONException
{
Object
object
=
get
(
index
);
String
result
=
JSON
.
toString
(
object
);
if
(
result
==
null
)
{
throw
JSON
.
typeMismatch
(
index
,
object
,
"String"
);
}
return
result
;
}
/**
* Returns the value at {@code index} if it exists, coercing it if
* necessary. Returns the empty string if no such value exists.
*/
public
String
optString
(
int
index
)
{
return
optString
(
index
,
""
);
}
/**
* Returns the value at {@code index} if it exists, coercing it if
* necessary. Returns {@code fallback} if no such value exists.
*/
public
String
optString
(
int
index
,
String
fallback
)
{
Object
object
=
opt
(
index
);
String
result
=
JSON
.
toString
(
object
);
return
result
!=
null
?
result
:
fallback
;
}
/**
* Returns the value at {@code index} if it exists and is a {@code
* JSONArray}.
*
* @throws JSONException if the value doesn't exist or is not a {@code
* JSONArray}.
*/
public
JSONArray
getJSONArray
(
int
index
)
throws
JSONException
{
Object
object
=
get
(
index
);
if
(
object
instanceof
JSONArray
)
{
return
(
JSONArray
)
object
;
}
else
{
throw
JSON
.
typeMismatch
(
index
,
object
,
"JSONArray"
);
}
}
/**
* Returns the value at {@code index} if it exists and is a {@code
* JSONArray}. Returns null otherwise.
*/
public
JSONArray
optJSONArray
(
int
index
)
{
Object
object
=
opt
(
index
);
return
object
instanceof
JSONArray
?
(
JSONArray
)
object
:
null
;
}
/**
* Returns the value at {@code index} if it exists and is a {@code
* JSONObject}.
*
* @throws JSONException if the value doesn't exist or is not a {@code
* JSONObject}.
*/
public
JSONObject
getJSONObject
(
int
index
)
throws
JSONException
{
Object
object
=
get
(
index
);
if
(
object
instanceof
JSONObject
)
{
return
(
JSONObject
)
object
;
}
else
{
throw
JSON
.
typeMismatch
(
index
,
object
,
"JSONObject"
);
}
}
/**
* Returns the value at {@code index} if it exists and is a {@code
* JSONObject}. Returns null otherwise.
*/
public
JSONObject
optJSONObject
(
int
index
)
{
Object
object
=
opt
(
index
);
return
object
instanceof
JSONObject
?
(
JSONObject
)
object
:
null
;
}
/**
* Returns a new object whose values are the values in this array, and whose
* names are the values in {@code names}. Names and values are paired up by
* index from 0 through to the shorter array's length. Names that are not
* strings will be coerced to strings. This method returns null if either
* array is empty.
*/
public
JSONObject
toJSONObject
(
JSONArray
names
)
throws
JSONException
{
JSONObject
result
=
new
JSONObject
();
int
length
=
Math
.
min
(
names
.
length
(),
values
.
size
());
if
(
length
==
0
)
{
return
null
;
}
for
(
int
i
=
0
;
i
<
length
;
i
++)
{
String
name
=
JSON
.
toString
(
names
.
opt
(
i
));
result
.
put
(
name
,
opt
(
i
));
}
return
result
;
}
/**
* Returns a new string by alternating this array's values with {@code
* separator}. This array's string values are quoted and have their special
* characters escaped. For example, the array containing the strings '12"
* pizza', 'taco' and 'soda' joined on '+' returns this:
* <pre>"12\" pizza"+"taco"+"soda"</pre>
*/
public
String
join
(
String
separator
)
throws
JSONException
{
JSONStringer
stringer
=
new
JSONStringer
();
stringer
.
open
(
JSONStringer
.
Scope
.
NULL
,
""
);
for
(
int
i
=
0
,
size
=
values
.
size
();
i
<
size
;
i
++)
{
if
(
i
>
0
)
{
stringer
.
out
.
append
(
separator
);
}
stringer
.
value
(
values
.
get
(
i
));
}
stringer
.
close
(
JSONStringer
.
Scope
.
NULL
,
JSONStringer
.
Scope
.
NULL
,
""
);
return
stringer
.
out
.
toString
();
}
/**
* Encodes this array as a compact JSON string, such as:
* <pre>[94043,90210]</pre>
*/
@Override
public
String
toString
()
{
try
{
JSONStringer
stringer
=
new
JSONStringer
();
writeTo
(
stringer
);
return
stringer
.
toString
();
}
catch
(
JSONException
e
)
{
return
null
;
}
}
/**
* Encodes this array as a human readable JSON string for debugging, such
* as:
* <pre>
* [
* 94043,
* 90210
* ]</pre>
*
* @param indentSpaces the number of spaces to indent for each level of
* nesting.
*/
public
String
toString
(
int
indentSpaces
)
throws
JSONException
{
JSONStringer
stringer
=
new
JSONStringer
(
indentSpaces
);
writeTo
(
stringer
);
return
stringer
.
toString
();
}
void
writeTo
(
JSONStringer
stringer
)
throws
JSONException
{
stringer
.
array
();
for
(
Object
value
:
values
)
{
stringer
.
value
(
value
);
}
stringer
.
endArray
();
}
@Override
public
boolean
equals
(
Object
o
)
{
return
o
instanceof
JSONArray
&&
((
JSONArray
)
o
).
values
.
equals
(
values
);
}
@Override
public
int
hashCode
()
{
// diverge from the original, which doesn't implement hashCode
return
values
.
hashCode
();
}
}
spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/json/JSONException.java
0 → 100644
View file @
e3bfd797
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
springframework
.
boot
.
configurationprocessor
.
json
;
// Note: this class was written without inspecting the non-free org.json sourcecode.
/**
* Thrown to indicate a problem with the JSON API. Such problems include:
* <ul>
* <li>Attempts to parse or construct malformed documents
* <li>Use of null as a name
* <li>Use of numeric types not available to JSON, such as {@link
* Double#isNaN() NaNs} or {@link Double#isInfinite() infinities}.
* <li>Lookups using an out of range index or nonexistent name
* <li>Type mismatches on lookups
* </ul>
*
* <p>Although this is a checked exception, it is rarely recoverable. Most
* callers should simply wrap this exception in an unchecked exception and
* rethrow:
* <pre> public JSONArray toJSONObject() {
* try {
* JSONObject result = new JSONObject();
* ...
* } catch (JSONException e) {
* throw new RuntimeException(e);
* }
* }</pre>
*/
public
class
JSONException
extends
Exception
{
public
JSONException
(
String
s
)
{
super
(
s
);
}
}
spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/json/JSONObject.java
0 → 100644
View file @
e3bfd797
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
springframework
.
boot
.
configurationprocessor
.
json
;
import
java.util.ArrayList
;
import
java.util.Collection
;
import
java.util.HashMap
;
import
java.util.Iterator
;
import
java.util.Map
;
// Note: this class was written without inspecting the non-free org.json sourcecode.
/**
* A modifiable set of name/value mappings. Names are unique, non-null strings.
* Values may be any mix of {@link JSONObject JSONObjects}, {@link JSONArray
* JSONArrays}, Strings, Booleans, Integers, Longs, Doubles or {@link #NULL}.
* Values may not be {@code null}, {@link Double#isNaN() NaNs}, {@link
* Double#isInfinite() infinities}, or of any type not listed here.
*
* <p>This class can coerce values to another type when requested.
* <ul>
* <li>When the requested type is a boolean, strings will be coerced using a
* case-insensitive comparison to "true" and "false".
* <li>When the requested type is a double, other {@link Number} types will
* be coerced using {@link Number#doubleValue() doubleValue}. Strings
* that can be coerced using {@link Double#valueOf(String)} will be.
* <li>When the requested type is an int, other {@link Number} types will
* be coerced using {@link Number#intValue() intValue}. Strings
* that can be coerced using {@link Double#valueOf(String)} will be,
* and then cast to int.
* <li><a name="lossy">When the requested type is a long, other {@link Number} types will
* be coerced using {@link Number#longValue() longValue}. Strings
* that can be coerced using {@link Double#valueOf(String)} will be,
* and then cast to long. This two-step conversion is lossy for very
* large values. For example, the string "9223372036854775806" yields the
* long 9223372036854775807.</a>
* <li>When the requested type is a String, other non-null values will be
* coerced using {@link String#valueOf(Object)}. Although null cannot be
* coerced, the sentinel value {@link JSONObject#NULL} is coerced to the
* string "null".
* </ul>
*
* <p>This class can look up both mandatory and optional values:
* <ul>
* <li>Use <code>get<i>Type</i>()</code> to retrieve a mandatory value. This
* fails with a {@code JSONException} if the requested name has no value
* or if the value cannot be coerced to the requested type.
* <li>Use <code>opt<i>Type</i>()</code> to retrieve an optional value. This
* returns a system- or user-supplied default if the requested name has no
* value or if the value cannot be coerced to the requested type.
* </ul>
*
* <p><strong>Warning:</strong> this class represents null in two incompatible
* ways: the standard Java {@code null} reference, and the sentinel value {@link
* JSONObject#NULL}. In particular, calling {@code put(name, null)} removes the
* named entry from the object but {@code put(name, JSONObject.NULL)} stores an
* entry whose value is {@code JSONObject.NULL}.
*
* <p>Instances of this class are not thread safe. Although this class is
* nonfinal, it was not designed for inheritance and should not be subclassed.
* In particular, self-use by overrideable methods is not specified. See
* <i>Effective Java</i> Item 17, "Design and Document or inheritance or else
* prohibit it" for further information.
*/
public
class
JSONObject
{
private
static
final
Double
NEGATIVE_ZERO
=
-
0
d
;
/**
* A sentinel value used to explicitly define a name with no value. Unlike
* {@code null}, names with this value:
* <ul>
* <li>show up in the {@link #names} array
* <li>show up in the {@link #keys} iterator
* <li>return {@code true} for {@link #has(String)}
* <li>do not throw on {@link #get(String)}
* <li>are included in the encoded JSON string.
* </ul>
*
* <p>This value violates the general contract of {@link Object#equals} by
* returning true when compared to {@code null}. Its {@link #toString}
* method returns "null".
*/
public
static
final
Object
NULL
=
new
Object
()
{
@Override
public
boolean
equals
(
Object
o
)
{
return
o
==
this
||
o
==
null
;
// API specifies this broken equals implementation
}
@Override
public
String
toString
()
{
return
"null"
;
}
};
private
final
Map
<
String
,
Object
>
nameValuePairs
;
/**
* Creates a {@code JSONObject} with no name/value mappings.
*/
public
JSONObject
()
{
nameValuePairs
=
new
HashMap
<
String
,
Object
>();
}
/**
* Creates a new {@code JSONObject} by copying all name/value mappings from
* the given map.
*
* @param copyFrom a map whose keys are of type {@link String} and whose
* values are of supported types.
* @throws NullPointerException if any of the map's keys are null.
*/
/* (accept a raw type for API compatibility) */
public
JSONObject
(
Map
copyFrom
)
{
this
();
Map
<?,
?>
contentsTyped
=
(
Map
<?,
?>)
copyFrom
;
for
(
Map
.
Entry
<?,
?>
entry
:
contentsTyped
.
entrySet
())
{
/*
* Deviate from the original by checking that keys are non-null and
* of the proper type. (We still defer validating the values).
*/
String
key
=
(
String
)
entry
.
getKey
();
if
(
key
==
null
)
{
throw
new
NullPointerException
(
"key == null"
);
}
nameValuePairs
.
put
(
key
,
wrap
(
entry
.
getValue
()));
}
}
/**
* Creates a new {@code JSONObject} with name/value mappings from the next
* object in the tokener.
*
* @param readFrom a tokener whose nextValue() method will yield a
* {@code JSONObject}.
* @throws JSONException if the parse fails or doesn't yield a
* {@code JSONObject}.
*/
public
JSONObject
(
JSONTokener
readFrom
)
throws
JSONException
{
/*
* Getting the parser to populate this could get tricky. Instead, just
* parse to temporary JSONObject and then steal the data from that.
*/
Object
object
=
readFrom
.
nextValue
();
if
(
object
instanceof
JSONObject
)
{
this
.
nameValuePairs
=
((
JSONObject
)
object
).
nameValuePairs
;
}
else
{
throw
JSON
.
typeMismatch
(
object
,
"JSONObject"
);
}
}
/**
* Creates a new {@code JSONObject} with name/value mappings from the JSON
* string.
*
* @param json a JSON-encoded string containing an object.
* @throws JSONException if the parse fails or doesn't yield a {@code
* JSONObject}.
*/
public
JSONObject
(
String
json
)
throws
JSONException
{
this
(
new
JSONTokener
(
json
));
}
/**
* Creates a new {@code JSONObject} by copying mappings for the listed names
* from the given object. Names that aren't present in {@code copyFrom} will
* be skipped.
*/
public
JSONObject
(
JSONObject
copyFrom
,
String
[]
names
)
throws
JSONException
{
this
();
for
(
String
name
:
names
)
{
Object
value
=
copyFrom
.
opt
(
name
);
if
(
value
!=
null
)
{
nameValuePairs
.
put
(
name
,
value
);
}
}
}
/**
* Returns the number of name/value mappings in this object.
*/
public
int
length
()
{
return
nameValuePairs
.
size
();
}
/**
* Maps {@code name} to {@code value}, clobbering any existing name/value
* mapping with the same name.
*
* @return this object.
*/
public
JSONObject
put
(
String
name
,
boolean
value
)
throws
JSONException
{
nameValuePairs
.
put
(
checkName
(
name
),
value
);
return
this
;
}
/**
* Maps {@code name} to {@code value}, clobbering any existing name/value
* mapping with the same name.
*
* @param value a finite value. May not be {@link Double#isNaN() NaNs} or
* {@link Double#isInfinite() infinities}.
* @return this object.
*/
public
JSONObject
put
(
String
name
,
double
value
)
throws
JSONException
{
nameValuePairs
.
put
(
checkName
(
name
),
JSON
.
checkDouble
(
value
));
return
this
;
}
/**
* Maps {@code name} to {@code value}, clobbering any existing name/value
* mapping with the same name.
*
* @return this object.
*/
public
JSONObject
put
(
String
name
,
int
value
)
throws
JSONException
{
nameValuePairs
.
put
(
checkName
(
name
),
value
);
return
this
;
}
/**
* Maps {@code name} to {@code value}, clobbering any existing name/value
* mapping with the same name.
*
* @return this object.
*/
public
JSONObject
put
(
String
name
,
long
value
)
throws
JSONException
{
nameValuePairs
.
put
(
checkName
(
name
),
value
);
return
this
;
}
/**
* Maps {@code name} to {@code value}, clobbering any existing name/value
* mapping with the same name. If the value is {@code null}, any existing
* mapping for {@code name} is removed.
*
* @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean,
* Integer, Long, Double, {@link #NULL}, or {@code null}. May not be
* {@link Double#isNaN() NaNs} or {@link Double#isInfinite()
* infinities}.
* @return this object.
*/
public
JSONObject
put
(
String
name
,
Object
value
)
throws
JSONException
{
if
(
value
==
null
)
{
nameValuePairs
.
remove
(
name
);
return
this
;
}
if
(
value
instanceof
Number
)
{
// deviate from the original by checking all Numbers, not just floats & doubles
JSON
.
checkDouble
(((
Number
)
value
).
doubleValue
());
}
nameValuePairs
.
put
(
checkName
(
name
),
value
);
return
this
;
}
/**
* Equivalent to {@code put(name, value)} when both parameters are non-null;
* does nothing otherwise.
*/
public
JSONObject
putOpt
(
String
name
,
Object
value
)
throws
JSONException
{
if
(
name
==
null
||
value
==
null
)
{
return
this
;
}
return
put
(
name
,
value
);
}
/**
* Appends {@code value} to the array already mapped to {@code name}. If
* this object has no mapping for {@code name}, this inserts a new mapping.
* If the mapping exists but its value is not an array, the existing
* and new values are inserted in order into a new array which is itself
* mapped to {@code name}. In aggregate, this allows values to be added to a
* mapping one at a time.
*
* @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean,
* Integer, Long, Double, {@link #NULL} or null. May not be {@link
* Double#isNaN() NaNs} or {@link Double#isInfinite() infinities}.
*/
public
JSONObject
accumulate
(
String
name
,
Object
value
)
throws
JSONException
{
Object
current
=
nameValuePairs
.
get
(
checkName
(
name
));
if
(
current
==
null
)
{
return
put
(
name
,
value
);
}
// check in accumulate, since array.put(Object) doesn't do any checking
if
(
value
instanceof
Number
)
{
JSON
.
checkDouble
(((
Number
)
value
).
doubleValue
());
}
if
(
current
instanceof
JSONArray
)
{
JSONArray
array
=
(
JSONArray
)
current
;
array
.
put
(
value
);
}
else
{
JSONArray
array
=
new
JSONArray
();
array
.
put
(
current
);
array
.
put
(
value
);
nameValuePairs
.
put
(
name
,
array
);
}
return
this
;
}
String
checkName
(
String
name
)
throws
JSONException
{
if
(
name
==
null
)
{
throw
new
JSONException
(
"Names must be non-null"
);
}
return
name
;
}
/**
* Removes the named mapping if it exists; does nothing otherwise.
*
* @return the value previously mapped by {@code name}, or null if there was
* no such mapping.
*/
public
Object
remove
(
String
name
)
{
return
nameValuePairs
.
remove
(
name
);
}
/**
* Returns true if this object has no mapping for {@code name} or if it has
* a mapping whose value is {@link #NULL}.
*/
public
boolean
isNull
(
String
name
)
{
Object
value
=
nameValuePairs
.
get
(
name
);
return
value
==
null
||
value
==
NULL
;
}
/**
* Returns true if this object has a mapping for {@code name}. The mapping
* may be {@link #NULL}.
*/
public
boolean
has
(
String
name
)
{
return
nameValuePairs
.
containsKey
(
name
);
}
/**
* Returns the value mapped by {@code name}.
*
* @throws JSONException if no such mapping exists.
*/
public
Object
get
(
String
name
)
throws
JSONException
{
Object
result
=
nameValuePairs
.
get
(
name
);
if
(
result
==
null
)
{
throw
new
JSONException
(
"No value for "
+
name
);
}
return
result
;
}
/**
* Returns the value mapped by {@code name}, or null if no such mapping
* exists.
*/
public
Object
opt
(
String
name
)
{
return
nameValuePairs
.
get
(
name
);
}
/**
* Returns the value mapped by {@code name} if it exists and is a boolean or
* can be coerced to a boolean.
*
* @throws JSONException if the mapping doesn't exist or cannot be coerced
* to a boolean.
*/
public
boolean
getBoolean
(
String
name
)
throws
JSONException
{
Object
object
=
get
(
name
);
Boolean
result
=
JSON
.
toBoolean
(
object
);
if
(
result
==
null
)
{
throw
JSON
.
typeMismatch
(
name
,
object
,
"boolean"
);
}
return
result
;
}
/**
* Returns the value mapped by {@code name} if it exists and is a boolean or
* can be coerced to a boolean. Returns false otherwise.
*/
public
boolean
optBoolean
(
String
name
)
{
return
optBoolean
(
name
,
false
);
}
/**
* Returns the value mapped by {@code name} if it exists and is a boolean or
* can be coerced to a boolean. Returns {@code fallback} otherwise.
*/
public
boolean
optBoolean
(
String
name
,
boolean
fallback
)
{
Object
object
=
opt
(
name
);
Boolean
result
=
JSON
.
toBoolean
(
object
);
return
result
!=
null
?
result
:
fallback
;
}
/**
* Returns the value mapped by {@code name} if it exists and is a double or
* can be coerced to a double.
*
* @throws JSONException if the mapping doesn't exist or cannot be coerced
* to a double.
*/
public
double
getDouble
(
String
name
)
throws
JSONException
{
Object
object
=
get
(
name
);
Double
result
=
JSON
.
toDouble
(
object
);
if
(
result
==
null
)
{
throw
JSON
.
typeMismatch
(
name
,
object
,
"double"
);
}
return
result
;
}
/**
* Returns the value mapped by {@code name} if it exists and is a double or
* can be coerced to a double. Returns {@code NaN} otherwise.
*/
public
double
optDouble
(
String
name
)
{
return
optDouble
(
name
,
Double
.
NaN
);
}
/**
* Returns the value mapped by {@code name} if it exists and is a double or
* can be coerced to a double. Returns {@code fallback} otherwise.
*/
public
double
optDouble
(
String
name
,
double
fallback
)
{
Object
object
=
opt
(
name
);
Double
result
=
JSON
.
toDouble
(
object
);
return
result
!=
null
?
result
:
fallback
;
}
/**
* Returns the value mapped by {@code name} if it exists and is an int or
* can be coerced to an int.
*
* @throws JSONException if the mapping doesn't exist or cannot be coerced
* to an int.
*/
public
int
getInt
(
String
name
)
throws
JSONException
{
Object
object
=
get
(
name
);
Integer
result
=
JSON
.
toInteger
(
object
);
if
(
result
==
null
)
{
throw
JSON
.
typeMismatch
(
name
,
object
,
"int"
);
}
return
result
;
}
/**
* Returns the value mapped by {@code name} if it exists and is an int or
* can be coerced to an int. Returns 0 otherwise.
*/
public
int
optInt
(
String
name
)
{
return
optInt
(
name
,
0
);
}
/**
* Returns the value mapped by {@code name} if it exists and is an int or
* can be coerced to an int. Returns {@code fallback} otherwise.
*/
public
int
optInt
(
String
name
,
int
fallback
)
{
Object
object
=
opt
(
name
);
Integer
result
=
JSON
.
toInteger
(
object
);
return
result
!=
null
?
result
:
fallback
;
}
/**
* Returns the value mapped by {@code name} if it exists and is a long or
* can be coerced to a long. Note that JSON represents numbers as doubles,
* so this is <a href="#lossy">lossy</a>; use strings to transfer numbers via JSON.
*
* @throws JSONException if the mapping doesn't exist or cannot be coerced
* to a long.
*/
public
long
getLong
(
String
name
)
throws
JSONException
{
Object
object
=
get
(
name
);
Long
result
=
JSON
.
toLong
(
object
);
if
(
result
==
null
)
{
throw
JSON
.
typeMismatch
(
name
,
object
,
"long"
);
}
return
result
;
}
/**
* Returns the value mapped by {@code name} if it exists and is a long or
* can be coerced to a long. Returns 0 otherwise. Note that JSON represents numbers as doubles,
* so this is <a href="#lossy">lossy</a>; use strings to transfer numbers via JSON.
*/
public
long
optLong
(
String
name
)
{
return
optLong
(
name
,
0L
);
}
/**
* Returns the value mapped by {@code name} if it exists and is a long or
* can be coerced to a long. Returns {@code fallback} otherwise. Note that JSON represents
* numbers as doubles, so this is <a href="#lossy">lossy</a>; use strings to transfer
* numbers via JSON.
*/
public
long
optLong
(
String
name
,
long
fallback
)
{
Object
object
=
opt
(
name
);
Long
result
=
JSON
.
toLong
(
object
);
return
result
!=
null
?
result
:
fallback
;
}
/**
* Returns the value mapped by {@code name} if it exists, coercing it if
* necessary.
*
* @throws JSONException if no such mapping exists.
*/
public
String
getString
(
String
name
)
throws
JSONException
{
Object
object
=
get
(
name
);
String
result
=
JSON
.
toString
(
object
);
if
(
result
==
null
)
{
throw
JSON
.
typeMismatch
(
name
,
object
,
"String"
);
}
return
result
;
}
/**
* Returns the value mapped by {@code name} if it exists, coercing it if
* necessary. Returns the empty string if no such mapping exists.
*/
public
String
optString
(
String
name
)
{
return
optString
(
name
,
""
);
}
/**
* Returns the value mapped by {@code name} if it exists, coercing it if
* necessary. Returns {@code fallback} if no such mapping exists.
*/
public
String
optString
(
String
name
,
String
fallback
)
{
Object
object
=
opt
(
name
);
String
result
=
JSON
.
toString
(
object
);
return
result
!=
null
?
result
:
fallback
;
}
/**
* Returns the value mapped by {@code name} if it exists and is a {@code
* JSONArray}.
*
* @throws JSONException if the mapping doesn't exist or is not a {@code
* JSONArray}.
*/
public
JSONArray
getJSONArray
(
String
name
)
throws
JSONException
{
Object
object
=
get
(
name
);
if
(
object
instanceof
JSONArray
)
{
return
(
JSONArray
)
object
;
}
else
{
throw
JSON
.
typeMismatch
(
name
,
object
,
"JSONArray"
);
}
}
/**
* Returns the value mapped by {@code name} if it exists and is a {@code
* JSONArray}. Returns null otherwise.
*/
public
JSONArray
optJSONArray
(
String
name
)
{
Object
object
=
opt
(
name
);
return
object
instanceof
JSONArray
?
(
JSONArray
)
object
:
null
;
}
/**
* Returns the value mapped by {@code name} if it exists and is a {@code
* JSONObject}.
*
* @throws JSONException if the mapping doesn't exist or is not a {@code
* JSONObject}.
*/
public
JSONObject
getJSONObject
(
String
name
)
throws
JSONException
{
Object
object
=
get
(
name
);
if
(
object
instanceof
JSONObject
)
{
return
(
JSONObject
)
object
;
}
else
{
throw
JSON
.
typeMismatch
(
name
,
object
,
"JSONObject"
);
}
}
/**
* Returns the value mapped by {@code name} if it exists and is a {@code
* JSONObject}. Returns null otherwise.
*/
public
JSONObject
optJSONObject
(
String
name
)
{
Object
object
=
opt
(
name
);
return
object
instanceof
JSONObject
?
(
JSONObject
)
object
:
null
;
}
/**
* Returns an array with the values corresponding to {@code names}. The
* array contains null for names that aren't mapped. This method returns
* null if {@code names} is either null or empty.
*/
public
JSONArray
toJSONArray
(
JSONArray
names
)
throws
JSONException
{
JSONArray
result
=
new
JSONArray
();
if
(
names
==
null
)
{
return
null
;
}
int
length
=
names
.
length
();
if
(
length
==
0
)
{
return
null
;
}
for
(
int
i
=
0
;
i
<
length
;
i
++)
{
String
name
=
JSON
.
toString
(
names
.
opt
(
i
));
result
.
put
(
opt
(
name
));
}
return
result
;
}
/**
* Returns an iterator of the {@code String} names in this object. The
* returned iterator supports {@link Iterator#remove() remove}, which will
* remove the corresponding mapping from this object. If this object is
* modified after the iterator is returned, the iterator's behavior is
* undefined. The order of the keys is undefined.
*/
/* Return a raw type for API compatibility */
public
Iterator
keys
()
{
return
nameValuePairs
.
keySet
().
iterator
();
}
/**
* Returns an array containing the string names in this object. This method
* returns null if this object contains no mappings.
*/
public
JSONArray
names
()
{
return
nameValuePairs
.
isEmpty
()
?
null
:
new
JSONArray
(
new
ArrayList
<
String
>(
nameValuePairs
.
keySet
()));
}
/**
* Encodes this object as a compact JSON string, such as:
* <pre>{"query":"Pizza","locations":[94043,90210]}</pre>
*/
@Override
public
String
toString
()
{
try
{
JSONStringer
stringer
=
new
JSONStringer
();
writeTo
(
stringer
);
return
stringer
.
toString
();
}
catch
(
JSONException
e
)
{
return
null
;
}
}
/**
* Encodes this object as a human readable JSON string for debugging, such
* as:
* <pre>
* {
* "query": "Pizza",
* "locations": [
* 94043,
* 90210
* ]
* }</pre>
*
* @param indentSpaces the number of spaces to indent for each level of
* nesting.
*/
public
String
toString
(
int
indentSpaces
)
throws
JSONException
{
JSONStringer
stringer
=
new
JSONStringer
(
indentSpaces
);
writeTo
(
stringer
);
return
stringer
.
toString
();
}
void
writeTo
(
JSONStringer
stringer
)
throws
JSONException
{
stringer
.
object
();
for
(
Map
.
Entry
<
String
,
Object
>
entry
:
nameValuePairs
.
entrySet
())
{
stringer
.
key
(
entry
.
getKey
()).
value
(
entry
.
getValue
());
}
stringer
.
endObject
();
}
/**
* Encodes the number as a JSON string.
*
* @param number a finite value. May not be {@link Double#isNaN() NaNs} or
* {@link Double#isInfinite() infinities}.
*/
public
static
String
numberToString
(
Number
number
)
throws
JSONException
{
if
(
number
==
null
)
{
throw
new
JSONException
(
"Number must be non-null"
);
}
double
doubleValue
=
number
.
doubleValue
();
JSON
.
checkDouble
(
doubleValue
);
// the original returns "-0" instead of "-0.0" for negative zero
if
(
number
.
equals
(
NEGATIVE_ZERO
))
{
return
"-0"
;
}
long
longValue
=
number
.
longValue
();
if
(
doubleValue
==
(
double
)
longValue
)
{
return
Long
.
toString
(
longValue
);
}
return
number
.
toString
();
}
/**
* Encodes {@code data} as a JSON string. This applies quotes and any
* necessary character escaping.
*
* @param data the string to encode. Null will be interpreted as an empty
* string.
*/
public
static
String
quote
(
String
data
)
{
if
(
data
==
null
)
{
return
"\"\""
;
}
try
{
JSONStringer
stringer
=
new
JSONStringer
();
stringer
.
open
(
JSONStringer
.
Scope
.
NULL
,
""
);
stringer
.
value
(
data
);
stringer
.
close
(
JSONStringer
.
Scope
.
NULL
,
JSONStringer
.
Scope
.
NULL
,
""
);
return
stringer
.
toString
();
}
catch
(
JSONException
e
)
{
throw
new
AssertionError
();
}
}
/**
* Wraps the given object if necessary.
*
* <p>If the object is null or , returns {@link #NULL}.
* If the object is a {@code JSONArray} or {@code JSONObject}, no wrapping is necessary.
* If the object is {@code NULL}, no wrapping is necessary.
* If the object is an array or {@code Collection}, returns an equivalent {@code JSONArray}.
* If the object is a {@code Map}, returns an equivalent {@code JSONObject}.
* If the object is a primitive wrapper type or {@code String}, returns the object.
* Otherwise if the object is from a {@code java} package, returns the result of {@code toString}.
* If wrapping fails, returns null.
*/
public
static
Object
wrap
(
Object
o
)
{
if
(
o
==
null
)
{
return
NULL
;
}
if
(
o
instanceof
JSONArray
||
o
instanceof
JSONObject
)
{
return
o
;
}
if
(
o
.
equals
(
NULL
))
{
return
o
;
}
try
{
if
(
o
instanceof
Collection
)
{
return
new
JSONArray
((
Collection
)
o
);
}
else
if
(
o
.
getClass
().
isArray
())
{
return
new
JSONArray
(
o
);
}
if
(
o
instanceof
Map
)
{
return
new
JSONObject
((
Map
)
o
);
}
if
(
o
instanceof
Boolean
||
o
instanceof
Byte
||
o
instanceof
Character
||
o
instanceof
Double
||
o
instanceof
Float
||
o
instanceof
Integer
||
o
instanceof
Long
||
o
instanceof
Short
||
o
instanceof
String
)
{
return
o
;
}
if
(
o
.
getClass
().
getPackage
().
getName
().
startsWith
(
"java."
))
{
return
o
.
toString
();
}
}
catch
(
Exception
ignored
)
{
}
return
null
;
}
}
spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/json/JSONStringer.java
0 → 100644
View file @
e3bfd797
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
springframework
.
boot
.
configurationprocessor
.
json
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.List
;
// Note: this class was written without inspecting the non-free org.json sourcecode.
/**
* Implements {@link JSONObject#toString} and {@link JSONArray#toString}. Most
* application developers should use those methods directly and disregard this
* API. For example:<pre>
* JSONObject object = ...
* String json = object.toString();</pre>
*
* <p>Stringers only encode well-formed JSON strings. In particular:
* <ul>
* <li>The stringer must have exactly one top-level array or object.
* <li>Lexical scopes must be balanced: every call to {@link #array} must
* have a matching call to {@link #endArray} and every call to {@link
* #object} must have a matching call to {@link #endObject}.
* <li>Arrays may not contain keys (property names).
* <li>Objects must alternate keys (property names) and values.
* <li>Values are inserted with either literal {@link #value(Object) value}
* calls, or by nesting arrays or objects.
* </ul>
* Calls that would result in a malformed JSON string will fail with a
* {@link JSONException}.
*
* <p>This class provides no facility for pretty-printing (ie. indenting)
* output. To encode indented output, use {@link JSONObject#toString(int)} or
* {@link JSONArray#toString(int)}.
*
* <p>Some implementations of the API support at most 20 levels of nesting.
* Attempts to create more than 20 levels of nesting may fail with a {@link
* JSONException}.
*
* <p>Each stringer may be used to encode a single top level value. Instances of
* this class are not thread safe. Although this class is nonfinal, it was not
* designed for inheritance and should not be subclassed. In particular,
* self-use by overrideable methods is not specified. See <i>Effective Java</i>
* Item 17, "Design and Document or inheritance or else prohibit it" for further
* information.
*/
public
class
JSONStringer
{
/** The output data, containing at most one top-level array or object. */
final
StringBuilder
out
=
new
StringBuilder
();
/**
* Lexical scoping elements within this stringer, necessary to insert the
* appropriate separator characters (ie. commas and colons) and to detect
* nesting errors.
*/
enum
Scope
{
/**
* An array with no elements requires no separators or newlines before
* it is closed.
*/
EMPTY_ARRAY
,
/**
* A array with at least one value requires a comma and newline before
* the next element.
*/
NONEMPTY_ARRAY
,
/**
* An object with no keys or values requires no separators or newlines
* before it is closed.
*/
EMPTY_OBJECT
,
/**
* An object whose most recent element is a key. The next element must
* be a value.
*/
DANGLING_KEY
,
/**
* An object with at least one name/value pair requires a comma and
* newline before the next element.
*/
NONEMPTY_OBJECT
,
/**
* A special bracketless array needed by JSONStringer.join() and
* JSONObject.quote() only. Not used for JSON encoding.
*/
NULL
,
}
/**
* Unlike the original implementation, this stack isn't limited to 20
* levels of nesting.
*/
private
final
List
<
Scope
>
stack
=
new
ArrayList
<
Scope
>();
/**
* A string containing a full set of spaces for a single level of
* indentation, or null for no pretty printing.
*/
private
final
String
indent
;
public
JSONStringer
()
{
indent
=
null
;
}
JSONStringer
(
int
indentSpaces
)
{
char
[]
indentChars
=
new
char
[
indentSpaces
];
Arrays
.
fill
(
indentChars
,
' '
);
indent
=
new
String
(
indentChars
);
}
/**
* Begins encoding a new array. Each call to this method must be paired with
* a call to {@link #endArray}.
*
* @return this stringer.
*/
public
JSONStringer
array
()
throws
JSONException
{
return
open
(
Scope
.
EMPTY_ARRAY
,
"["
);
}
/**
* Ends encoding the current array.
*
* @return this stringer.
*/
public
JSONStringer
endArray
()
throws
JSONException
{
return
close
(
Scope
.
EMPTY_ARRAY
,
Scope
.
NONEMPTY_ARRAY
,
"]"
);
}
/**
* Begins encoding a new object. Each call to this method must be paired
* with a call to {@link #endObject}.
*
* @return this stringer.
*/
public
JSONStringer
object
()
throws
JSONException
{
return
open
(
Scope
.
EMPTY_OBJECT
,
"{"
);
}
/**
* Ends encoding the current object.
*
* @return this stringer.
*/
public
JSONStringer
endObject
()
throws
JSONException
{
return
close
(
Scope
.
EMPTY_OBJECT
,
Scope
.
NONEMPTY_OBJECT
,
"}"
);
}
/**
* Enters a new scope by appending any necessary whitespace and the given
* bracket.
*/
JSONStringer
open
(
Scope
empty
,
String
openBracket
)
throws
JSONException
{
if
(
stack
.
isEmpty
()
&&
out
.
length
()
>
0
)
{
throw
new
JSONException
(
"Nesting problem: multiple top-level roots"
);
}
beforeValue
();
stack
.
add
(
empty
);
out
.
append
(
openBracket
);
return
this
;
}
/**
* Closes the current scope by appending any necessary whitespace and the
* given bracket.
*/
JSONStringer
close
(
Scope
empty
,
Scope
nonempty
,
String
closeBracket
)
throws
JSONException
{
Scope
context
=
peek
();
if
(
context
!=
nonempty
&&
context
!=
empty
)
{
throw
new
JSONException
(
"Nesting problem"
);
}
stack
.
remove
(
stack
.
size
()
-
1
);
if
(
context
==
nonempty
)
{
newline
();
}
out
.
append
(
closeBracket
);
return
this
;
}
/**
* Returns the value on the top of the stack.
*/
private
Scope
peek
()
throws
JSONException
{
if
(
stack
.
isEmpty
())
{
throw
new
JSONException
(
"Nesting problem"
);
}
return
stack
.
get
(
stack
.
size
()
-
1
);
}
/**
* Replace the value on the top of the stack with the given value.
*/
private
void
replaceTop
(
Scope
topOfStack
)
{
stack
.
set
(
stack
.
size
()
-
1
,
topOfStack
);
}
/**
* Encodes {@code value}.
*
* @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean,
* Integer, Long, Double or null. May not be {@link Double#isNaN() NaNs}
* or {@link Double#isInfinite() infinities}.
* @return this stringer.
*/
public
JSONStringer
value
(
Object
value
)
throws
JSONException
{
if
(
stack
.
isEmpty
())
{
throw
new
JSONException
(
"Nesting problem"
);
}
if
(
value
instanceof
JSONArray
)
{
((
JSONArray
)
value
).
writeTo
(
this
);
return
this
;
}
else
if
(
value
instanceof
JSONObject
)
{
((
JSONObject
)
value
).
writeTo
(
this
);
return
this
;
}
beforeValue
();
if
(
value
==
null
||
value
instanceof
Boolean
||
value
==
JSONObject
.
NULL
)
{
out
.
append
(
value
);
}
else
if
(
value
instanceof
Number
)
{
out
.
append
(
JSONObject
.
numberToString
((
Number
)
value
));
}
else
{
string
(
value
.
toString
());
}
return
this
;
}
/**
* Encodes {@code value} to this stringer.
*
* @return this stringer.
*/
public
JSONStringer
value
(
boolean
value
)
throws
JSONException
{
if
(
stack
.
isEmpty
())
{
throw
new
JSONException
(
"Nesting problem"
);
}
beforeValue
();
out
.
append
(
value
);
return
this
;
}
/**
* Encodes {@code value} to this stringer.
*
* @param value a finite value. May not be {@link Double#isNaN() NaNs} or
* {@link Double#isInfinite() infinities}.
* @return this stringer.
*/
public
JSONStringer
value
(
double
value
)
throws
JSONException
{
if
(
stack
.
isEmpty
())
{
throw
new
JSONException
(
"Nesting problem"
);
}
beforeValue
();
out
.
append
(
JSONObject
.
numberToString
(
value
));
return
this
;
}
/**
* Encodes {@code value} to this stringer.
*
* @return this stringer.
*/
public
JSONStringer
value
(
long
value
)
throws
JSONException
{
if
(
stack
.
isEmpty
())
{
throw
new
JSONException
(
"Nesting problem"
);
}
beforeValue
();
out
.
append
(
value
);
return
this
;
}
private
void
string
(
String
value
)
{
out
.
append
(
"\""
);
for
(
int
i
=
0
,
length
=
value
.
length
();
i
<
length
;
i
++)
{
char
c
=
value
.
charAt
(
i
);
/*
* From RFC 4627, "All Unicode characters may be placed within the
* quotation marks except for the characters that must be escaped:
* quotation mark, reverse solidus, and the control characters
* (U+0000 through U+001F)."
*/
switch
(
c
)
{
case
'"'
:
case
'\\'
:
case
'/'
:
out
.
append
(
'\\'
).
append
(
c
);
break
;
case
'\t'
:
out
.
append
(
"\\t"
);
break
;
case
'\b'
:
out
.
append
(
"\\b"
);
break
;
case
'\n'
:
out
.
append
(
"\\n"
);
break
;
case
'\r'
:
out
.
append
(
"\\r"
);
break
;
case
'\f'
:
out
.
append
(
"\\f"
);
break
;
default
:
if
(
c
<=
0x1F
)
{
out
.
append
(
String
.
format
(
"\\u%04x"
,
(
int
)
c
));
}
else
{
out
.
append
(
c
);
}
break
;
}
}
out
.
append
(
"\""
);
}
private
void
newline
()
{
if
(
indent
==
null
)
{
return
;
}
out
.
append
(
"\n"
);
for
(
int
i
=
0
;
i
<
stack
.
size
();
i
++)
{
out
.
append
(
indent
);
}
}
/**
* Encodes the key (property name) to this stringer.
*
* @param name the name of the forthcoming value. May not be null.
* @return this stringer.
*/
public
JSONStringer
key
(
String
name
)
throws
JSONException
{
if
(
name
==
null
)
{
throw
new
JSONException
(
"Names must be non-null"
);
}
beforeKey
();
string
(
name
);
return
this
;
}
/**
* Inserts any necessary separators and whitespace before a name. Also
* adjusts the stack to expect the key's value.
*/
private
void
beforeKey
()
throws
JSONException
{
Scope
context
=
peek
();
if
(
context
==
Scope
.
NONEMPTY_OBJECT
)
{
// first in object
out
.
append
(
','
);
}
else
if
(
context
!=
Scope
.
EMPTY_OBJECT
)
{
// not in an object!
throw
new
JSONException
(
"Nesting problem"
);
}
newline
();
replaceTop
(
Scope
.
DANGLING_KEY
);
}
/**
* Inserts any necessary separators and whitespace before a literal value,
* inline array, or inline object. Also adjusts the stack to expect either a
* closing bracket or another element.
*/
private
void
beforeValue
()
throws
JSONException
{
if
(
stack
.
isEmpty
())
{
return
;
}
Scope
context
=
peek
();
if
(
context
==
Scope
.
EMPTY_ARRAY
)
{
// first in array
replaceTop
(
Scope
.
NONEMPTY_ARRAY
);
newline
();
}
else
if
(
context
==
Scope
.
NONEMPTY_ARRAY
)
{
// another in array
out
.
append
(
','
);
newline
();
}
else
if
(
context
==
Scope
.
DANGLING_KEY
)
{
// value for key
out
.
append
(
indent
==
null
?
":"
:
": "
);
replaceTop
(
Scope
.
NONEMPTY_OBJECT
);
}
else
if
(
context
!=
Scope
.
NULL
)
{
throw
new
JSONException
(
"Nesting problem"
);
}
}
/**
* Returns the encoded JSON string.
*
* <p>If invoked with unterminated arrays or unclosed objects, this method's
* return value is undefined.
*
* <p><strong>Warning:</strong> although it contradicts the general contract
* of {@link Object#toString}, this method returns null if the stringer
* contains no data.
*/
@Override
public
String
toString
()
{
return
out
.
length
()
==
0
?
null
:
out
.
toString
();
}
}
spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/json/JSONTokener.java
0 → 100644
View file @
e3bfd797
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
springframework
.
boot
.
configurationprocessor
.
json
;
// Note: this class was written without inspecting the non-free org.json sourcecode.
/**
* Parses a JSON (<a href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>)
* encoded string into the corresponding object. Most clients of
* this class will use only need the {@link #JSONTokener(String) constructor}
* and {@link #nextValue} method. Example usage: <pre>
* String json = "{"
* + " \"query\": \"Pizza\", "
* + " \"locations\": [ 94043, 90210 ] "
* + "}";
*
* JSONObject object = (JSONObject) new JSONTokener(json).nextValue();
* String query = object.getString("query");
* JSONArray locations = object.getJSONArray("locations");</pre>
*
* <p>For best interoperability and performance use JSON that complies with
* RFC 4627, such as that generated by {@link JSONStringer}. For legacy reasons
* this parser is lenient, so a successful parse does not indicate that the
* input string was valid JSON. All of the following syntax errors will be
* ignored:
* <ul>
* <li>End of line comments starting with {@code //} or {@code #} and ending
* with a newline character.
* <li>C-style comments starting with {@code /*} and ending with
* {@code *}{@code /}. Such comments may not be nested.
* <li>Strings that are unquoted or {@code 'single quoted'}.
* <li>Hexadecimal integers prefixed with {@code 0x} or {@code 0X}.
* <li>Octal integers prefixed with {@code 0}.
* <li>Array elements separated by {@code ;}.
* <li>Unnecessary array separators. These are interpreted as if null was the
* omitted value.
* <li>Key-value pairs separated by {@code =} or {@code =>}.
* <li>Key-value pairs separated by {@code ;}.
* </ul>
*
* <p>Each tokener may be used to parse a single JSON string. Instances of this
* class are not thread safe. Although this class is nonfinal, it was not
* designed for inheritance and should not be subclassed. In particular,
* self-use by overrideable methods is not specified. See <i>Effective Java</i>
* Item 17, "Design and Document or inheritance or else prohibit it" for further
* information.
*/
public
class
JSONTokener
{
/** The input JSON. */
private
final
String
in
;
/**
* The index of the next character to be returned by {@link #next}. When
* the input is exhausted, this equals the input's length.
*/
private
int
pos
;
/**
* @param in JSON encoded string. Null is not permitted and will yield a
* tokener that throws {@code NullPointerExceptions} when methods are
* called.
*/
public
JSONTokener
(
String
in
)
{
// consume an optional byte order mark (BOM) if it exists
if
(
in
!=
null
&&
in
.
startsWith
(
"\ufeff"
))
{
in
=
in
.
substring
(
1
);
}
this
.
in
=
in
;
}
/**
* Returns the next value from the input.
*
* @return a {@link JSONObject}, {@link JSONArray}, String, Boolean,
* Integer, Long, Double or {@link JSONObject#NULL}.
* @throws JSONException if the input is malformed.
*/
public
Object
nextValue
()
throws
JSONException
{
int
c
=
nextCleanInternal
();
switch
(
c
)
{
case
-
1
:
throw
syntaxError
(
"End of input"
);
case
'{'
:
return
readObject
();
case
'['
:
return
readArray
();
case
'\''
:
case
'"'
:
return
nextString
((
char
)
c
);
default
:
pos
--;
return
readLiteral
();
}
}
private
int
nextCleanInternal
()
throws
JSONException
{
while
(
pos
<
in
.
length
())
{
int
c
=
in
.
charAt
(
pos
++);
switch
(
c
)
{
case
'\t'
:
case
' '
:
case
'\n'
:
case
'\r'
:
continue
;
case
'/'
:
if
(
pos
==
in
.
length
())
{
return
c
;
}
char
peek
=
in
.
charAt
(
pos
);
switch
(
peek
)
{
case
'*'
:
// skip a /* c-style comment */
pos
++;
int
commentEnd
=
in
.
indexOf
(
"*/"
,
pos
);
if
(
commentEnd
==
-
1
)
{
throw
syntaxError
(
"Unterminated comment"
);
}
pos
=
commentEnd
+
2
;
continue
;
case
'/'
:
// skip a // end-of-line comment
pos
++;
skipToEndOfLine
();
continue
;
default
:
return
c
;
}
case
'#'
:
/*
* Skip a # hash end-of-line comment. The JSON RFC doesn't
* specify this behavior, but it's required to parse
* existing documents. See http://b/2571423.
*/
skipToEndOfLine
();
continue
;
default
:
return
c
;
}
}
return
-
1
;
}
/**
* Advances the position until after the next newline character. If the line
* is terminated by "\r\n", the '\n' must be consumed as whitespace by the
* caller.
*/
private
void
skipToEndOfLine
()
{
for
(;
pos
<
in
.
length
();
pos
++)
{
char
c
=
in
.
charAt
(
pos
);
if
(
c
==
'\r'
||
c
==
'\n'
)
{
pos
++;
break
;
}
}
}
/**
* Returns the string up to but not including {@code quote}, unescaping any
* character escape sequences encountered along the way. The opening quote
* should have already been read. This consumes the closing quote, but does
* not include it in the returned string.
*
* @param quote either ' or ".
* @throws NumberFormatException if any unicode escape sequences are
* malformed.
*/
public
String
nextString
(
char
quote
)
throws
JSONException
{
/*
* For strings that are free of escape sequences, we can just extract
* the result as a substring of the input. But if we encounter an escape
* sequence, we need to use a StringBuilder to compose the result.
*/
StringBuilder
builder
=
null
;
/* the index of the first character not yet appended to the builder. */
int
start
=
pos
;
while
(
pos
<
in
.
length
())
{
int
c
=
in
.
charAt
(
pos
++);
if
(
c
==
quote
)
{
if
(
builder
==
null
)
{
// a new string avoids leaking memory
return
new
String
(
in
.
substring
(
start
,
pos
-
1
));
}
else
{
builder
.
append
(
in
,
start
,
pos
-
1
);
return
builder
.
toString
();
}
}
if
(
c
==
'\\'
)
{
if
(
pos
==
in
.
length
())
{
throw
syntaxError
(
"Unterminated escape sequence"
);
}
if
(
builder
==
null
)
{
builder
=
new
StringBuilder
();
}
builder
.
append
(
in
,
start
,
pos
-
1
);
builder
.
append
(
readEscapeCharacter
());
start
=
pos
;
}
}
throw
syntaxError
(
"Unterminated string"
);
}
/**
* Unescapes the character identified by the character or characters that
* immediately follow a backslash. The backslash '\' should have already
* been read. This supports both unicode escapes "u000A" and two-character
* escapes "\n".
*
* @throws NumberFormatException if any unicode escape sequences are
* malformed.
*/
private
char
readEscapeCharacter
()
throws
JSONException
{
char
escaped
=
in
.
charAt
(
pos
++);
switch
(
escaped
)
{
case
'u'
:
if
(
pos
+
4
>
in
.
length
())
{
throw
syntaxError
(
"Unterminated escape sequence"
);
}
String
hex
=
in
.
substring
(
pos
,
pos
+
4
);
pos
+=
4
;
return
(
char
)
Integer
.
parseInt
(
hex
,
16
);
case
't'
:
return
'\t'
;
case
'b'
:
return
'\b'
;
case
'n'
:
return
'\n'
;
case
'r'
:
return
'\r'
;
case
'f'
:
return
'\f'
;
case
'\''
:
case
'"'
:
case
'\\'
:
default
:
return
escaped
;
}
}
/**
* Reads a null, boolean, numeric or unquoted string literal value. Numeric
* values will be returned as an Integer, Long, or Double, in that order of
* preference.
*/
private
Object
readLiteral
()
throws
JSONException
{
String
literal
=
nextToInternal
(
"{}[]/\\:,=;# \t\f"
);
if
(
literal
.
length
()
==
0
)
{
throw
syntaxError
(
"Expected literal value"
);
}
else
if
(
"null"
.
equalsIgnoreCase
(
literal
))
{
return
JSONObject
.
NULL
;
}
else
if
(
"true"
.
equalsIgnoreCase
(
literal
))
{
return
Boolean
.
TRUE
;
}
else
if
(
"false"
.
equalsIgnoreCase
(
literal
))
{
return
Boolean
.
FALSE
;
}
/* try to parse as an integral type... */
if
(
literal
.
indexOf
(
'.'
)
==
-
1
)
{
int
base
=
10
;
String
number
=
literal
;
if
(
number
.
startsWith
(
"0x"
)
||
number
.
startsWith
(
"0X"
))
{
number
=
number
.
substring
(
2
);
base
=
16
;
}
else
if
(
number
.
startsWith
(
"0"
)
&&
number
.
length
()
>
1
)
{
number
=
number
.
substring
(
1
);
base
=
8
;
}
try
{
long
longValue
=
Long
.
parseLong
(
number
,
base
);
if
(
longValue
<=
Integer
.
MAX_VALUE
&&
longValue
>=
Integer
.
MIN_VALUE
)
{
return
(
int
)
longValue
;
}
else
{
return
longValue
;
}
}
catch
(
NumberFormatException
e
)
{
/*
* This only happens for integral numbers greater than
* Long.MAX_VALUE, numbers in exponential form (5e-10) and
* unquoted strings. Fall through to try floating point.
*/
}
}
/* ...next try to parse as a floating point... */
try
{
return
Double
.
valueOf
(
literal
);
}
catch
(
NumberFormatException
ignored
)
{
}
/* ... finally give up. We have an unquoted string */
return
new
String
(
literal
);
// a new string avoids leaking memory
}
/**
* Returns the string up to but not including any of the given characters or
* a newline character. This does not consume the excluded character.
*/
private
String
nextToInternal
(
String
excluded
)
{
int
start
=
pos
;
for
(;
pos
<
in
.
length
();
pos
++)
{
char
c
=
in
.
charAt
(
pos
);
if
(
c
==
'\r'
||
c
==
'\n'
||
excluded
.
indexOf
(
c
)
!=
-
1
)
{
return
in
.
substring
(
start
,
pos
);
}
}
return
in
.
substring
(
start
);
}
/**
* Reads a sequence of key/value pairs and the trailing closing brace '}' of
* an object. The opening brace '{' should have already been read.
*/
private
JSONObject
readObject
()
throws
JSONException
{
JSONObject
result
=
new
JSONObject
();
/* Peek to see if this is the empty object. */
int
first
=
nextCleanInternal
();
if
(
first
==
'}'
)
{
return
result
;
}
else
if
(
first
!=
-
1
)
{
pos
--;
}
while
(
true
)
{
Object
name
=
nextValue
();
if
(!(
name
instanceof
String
))
{
if
(
name
==
null
)
{
throw
syntaxError
(
"Names cannot be null"
);
}
else
{
throw
syntaxError
(
"Names must be strings, but "
+
name
+
" is of type "
+
name
.
getClass
().
getName
());
}
}
/*
* Expect the name/value separator to be either a colon ':', an
* equals sign '=', or an arrow "=>". The last two are bogus but we
* include them because that's what the original implementation did.
*/
int
separator
=
nextCleanInternal
();
if
(
separator
!=
':'
&&
separator
!=
'='
)
{
throw
syntaxError
(
"Expected ':' after "
+
name
);
}
if
(
pos
<
in
.
length
()
&&
in
.
charAt
(
pos
)
==
'>'
)
{
pos
++;
}
result
.
put
((
String
)
name
,
nextValue
());
switch
(
nextCleanInternal
())
{
case
'}'
:
return
result
;
case
';'
:
case
','
:
continue
;
default
:
throw
syntaxError
(
"Unterminated object"
);
}
}
}
/**
* Reads a sequence of values and the trailing closing brace ']' of an
* array. The opening brace '[' should have already been read. Note that
* "[]" yields an empty array, but "[,]" returns a two-element array
* equivalent to "[null,null]".
*/
private
JSONArray
readArray
()
throws
JSONException
{
JSONArray
result
=
new
JSONArray
();
/* to cover input that ends with ",]". */
boolean
hasTrailingSeparator
=
false
;
while
(
true
)
{
switch
(
nextCleanInternal
())
{
case
-
1
:
throw
syntaxError
(
"Unterminated array"
);
case
']'
:
if
(
hasTrailingSeparator
)
{
result
.
put
(
null
);
}
return
result
;
case
','
:
case
';'
:
/* A separator without a value first means "null". */
result
.
put
(
null
);
hasTrailingSeparator
=
true
;
continue
;
default
:
pos
--;
}
result
.
put
(
nextValue
());
switch
(
nextCleanInternal
())
{
case
']'
:
return
result
;
case
','
:
case
';'
:
hasTrailingSeparator
=
true
;
continue
;
default
:
throw
syntaxError
(
"Unterminated array"
);
}
}
}
/**
* Returns an exception containing the given message plus the current
* position and the entire input string.
*/
public
JSONException
syntaxError
(
String
message
)
{
return
new
JSONException
(
message
+
this
);
}
/**
* Returns the current position and the entire input string.
*/
@Override
public
String
toString
()
{
// consistent with the original implementation
return
" at character "
+
pos
+
" of "
+
in
;
}
/*
* Legacy APIs.
*
* None of the methods below are on the critical path of parsing JSON
* documents. They exist only because they were exposed by the original
* implementation and may be used by some clients.
*/
/**
* Returns true until the input has been exhausted.
*/
public
boolean
more
()
{
return
pos
<
in
.
length
();
}
/**
* Returns the next available character, or the null character '\0' if all
* input has been exhausted. The return value of this method is ambiguous
* for JSON strings that contain the character '\0'.
*/
public
char
next
()
{
return
pos
<
in
.
length
()
?
in
.
charAt
(
pos
++)
:
'\0'
;
}
/**
* Returns the next available character if it equals {@code c}. Otherwise an
* exception is thrown.
*/
public
char
next
(
char
c
)
throws
JSONException
{
char
result
=
next
();
if
(
result
!=
c
)
{
throw
syntaxError
(
"Expected "
+
c
+
" but was "
+
result
);
}
return
result
;
}
/**
* Returns the next character that is not whitespace and does not belong to
* a comment. If the input is exhausted before such a character can be
* found, the null character '\0' is returned. The return value of this
* method is ambiguous for JSON strings that contain the character '\0'.
*/
public
char
nextClean
()
throws
JSONException
{
int
nextCleanInt
=
nextCleanInternal
();
return
nextCleanInt
==
-
1
?
'\0'
:
(
char
)
nextCleanInt
;
}
/**
* Returns the next {@code length} characters of the input.
*
* <p>The returned string shares its backing character array with this
* tokener's input string. If a reference to the returned string may be held
* indefinitely, you should use {@code new String(result)} to copy it first
* to avoid memory leaks.
*
* @throws JSONException if the remaining input is not long enough to
* satisfy this request.
*/
public
String
next
(
int
length
)
throws
JSONException
{
if
(
pos
+
length
>
in
.
length
())
{
throw
syntaxError
(
length
+
" is out of bounds"
);
}
String
result
=
in
.
substring
(
pos
,
pos
+
length
);
pos
+=
length
;
return
result
;
}
/**
* Returns the {@link String#trim trimmed} string holding the characters up
* to but not including the first of:
* <ul>
* <li>any character in {@code excluded}
* <li>a newline character '\n'
* <li>a carriage return '\r'
* </ul>
*
* <p>The returned string shares its backing character array with this
* tokener's input string. If a reference to the returned string may be held
* indefinitely, you should use {@code new String(result)} to copy it first
* to avoid memory leaks.
*
* @return a possibly-empty string
*/
public
String
nextTo
(
String
excluded
)
{
if
(
excluded
==
null
)
{
throw
new
NullPointerException
(
"excluded == null"
);
}
return
nextToInternal
(
excluded
).
trim
();
}
/**
* Equivalent to {@code nextTo(String.valueOf(excluded))}.
*/
public
String
nextTo
(
char
excluded
)
{
return
nextToInternal
(
String
.
valueOf
(
excluded
)).
trim
();
}
/**
* Advances past all input up to and including the next occurrence of
* {@code thru}. If the remaining input doesn't contain {@code thru}, the
* input is exhausted.
*/
public
void
skipPast
(
String
thru
)
{
int
thruStart
=
in
.
indexOf
(
thru
,
pos
);
pos
=
thruStart
==
-
1
?
in
.
length
()
:
(
thruStart
+
thru
.
length
());
}
/**
* Advances past all input up to but not including the next occurrence of
* {@code to}. If the remaining input doesn't contain {@code to}, the input
* is unchanged.
*/
public
char
skipTo
(
char
to
)
{
int
index
=
in
.
indexOf
(
to
,
pos
);
if
(
index
!=
-
1
)
{
pos
=
index
;
return
to
;
}
else
{
return
'\0'
;
}
}
/**
* Unreads the most recent character of input. If no input characters have
* been read, the input is unchanged.
*/
public
void
back
()
{
if
(--
pos
==
-
1
)
{
pos
=
0
;
}
}
/**
* Returns the integer [0..15] value for the given hex character, or -1
* for non-hex input.
*
* @param hex a character in the ranges [0-9], [A-F] or [a-f]. Any other
* character will yield a -1 result.
*/
public
static
int
dehexchar
(
char
hex
)
{
if
(
hex
>=
'0'
&&
hex
<=
'9'
)
{
return
hex
-
'0'
;
}
else
if
(
hex
>=
'A'
&&
hex
<=
'F'
)
{
return
hex
-
'A'
+
10
;
}
else
if
(
hex
>=
'a'
&&
hex
<=
'f'
)
{
return
hex
-
'a'
+
10
;
}
else
{
return
-
1
;
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment