From 9b5aa73f59d7592ac9a836bf635f11e84a7970ae Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Tue, 14 Jan 2020 12:03:18 +0100 Subject: [PATCH] Fixes #3385 Modernize jetty-util-ajax. Added type parameter to methods that were using raw types. Updated the implementation to use generics. Deprecated static methods. Updated usages. Signed-off-by: Simone Bordet --- .../asyncrest/AbstractRestServlet.java | 14 +- .../example/asyncrest/AsyncRestServlet.java | 26 +- .../example/asyncrest/SerialRestServlet.java | 9 +- .../eclipse/jetty/embedded/ManyHandlers.java | 2 +- .../jetty/embedded/ManyHandlersTest.java | 5 +- .../jetty/http2/hpack/HpackPerfTest.java | 21 +- .../jetty/security/openid/JwtDecoder.java | 11 +- .../security/openid/OpenIdConfiguration.java | 4 +- .../security/openid/OpenIdCredentials.java | 4 +- .../proxy/AsyncMiddleManServletTest.java | 55 +- .../jetty/server/ErrorHandlerTest.java | 3 +- .../org/eclipse/jetty/util/ajax/JSON.java | 646 ++++++++++-------- .../util/ajax/JSONCollectionConvertor.java | 10 +- .../jetty/util/ajax/JSONDateConvertor.java | 2 +- .../jetty/util/ajax/JSONEnumConvertor.java | 27 +- .../jetty/util/ajax/JSONObjectConvertor.java | 33 +- .../jetty/util/ajax/JSONPojoConvertor.java | 224 +++--- .../util/ajax/JSONPojoConvertorFactory.java | 38 +- .../java/org/eclipse/jetty/util/ajax/Bar.java | 121 ++++ .../java/org/eclipse/jetty/util/ajax/Baz.java | 79 +++ .../org/eclipse/jetty/util/ajax/Color.java | 24 + .../java/org/eclipse/jetty/util/ajax/Foo.java | 164 +++++ .../ajax/JSONCollectionConvertorTest.java | 28 +- .../ajax/JSONPojoConvertorFactoryTest.java | 374 +--------- .../util/ajax/JSONPojoConvertorTest.java | 406 +---------- .../org/eclipse/jetty/util/ajax/JSONTest.java | 265 +++---- 26 files changed, 1180 insertions(+), 1415 deletions(-) create mode 100644 jetty-util-ajax/src/test/java/org/eclipse/jetty/util/ajax/Bar.java create mode 100644 jetty-util-ajax/src/test/java/org/eclipse/jetty/util/ajax/Baz.java create mode 100644 jetty-util-ajax/src/test/java/org/eclipse/jetty/util/ajax/Color.java create mode 100644 jetty-util-ajax/src/test/java/org/eclipse/jetty/util/ajax/Foo.java diff --git a/examples/async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/AbstractRestServlet.java b/examples/async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/AbstractRestServlet.java index ff297aa1bb9..7811257c09f 100644 --- a/examples/async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/AbstractRestServlet.java +++ b/examples/async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/AbstractRestServlet.java @@ -101,19 +101,19 @@ public class AbstractRestServlet extends HttpServlet } } - protected String generateThumbs(Queue> results) + protected String generateThumbs(Queue> results) { StringBuilder thumbs = new StringBuilder(); - for (Map m : results) + for (Map m : results) { if (!m.containsKey("GalleryURL")) continue; - thumbs.append(""); - thumbs.append(""); + thumbs.append(""); + thumbs.append(""); thumbs.append(" "); } return thumbs.toString(); diff --git a/examples/async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/AsyncRestServlet.java b/examples/async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/AsyncRestServlet.java index 76b3c035d3d..c89fda2c2bd 100644 --- a/examples/async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/AsyncRestServlet.java +++ b/examples/async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/AsyncRestServlet.java @@ -77,17 +77,18 @@ public class AsyncRestServlet extends AbstractRestServlet @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - Long start = System.nanoTime(); + long start = System.nanoTime(); // Do we have results yet? - Queue> results = (Queue>)request.getAttribute(RESULTS_ATTR); + @SuppressWarnings("unchecked") + Queue> results = (Queue>)request.getAttribute(RESULTS_ATTR); // If no results, this must be the first dispatch, so send the REST request(s) if (results == null) { // define results data structures - final Queue> resultsQueue = new ConcurrentLinkedQueue<>(); - request.setAttribute(RESULTS_ATTR, results = resultsQueue); + results = new ConcurrentLinkedQueue<>(); + request.setAttribute(RESULTS_ATTR, results); // suspend the request // This is done before scheduling async handling to avoid race of @@ -100,13 +101,14 @@ public class AsyncRestServlet extends AbstractRestServlet final AtomicInteger outstanding = new AtomicInteger(keywords.length); // Send request each keyword + Queue> resultsQueue = results; for (final String item : keywords) { _client.newRequest(restURL(item)).method(HttpMethod.GET).send( new AsyncRestRequest() { @Override - void onAuctionFound(Map auction) + void onAuctionFound(Map auction) { resultsQueue.add(auction); } @@ -163,9 +165,9 @@ public class AsyncRestServlet extends AbstractRestServlet out.close(); } - private abstract class AsyncRestRequest extends Response.Listener.Adapter + private abstract static class AsyncRestRequest extends Response.Listener.Adapter { - final Utf8StringBuilder _content = new Utf8StringBuilder(); + private final Utf8StringBuilder _content = new Utf8StringBuilder(); AsyncRestRequest() { @@ -182,13 +184,16 @@ public class AsyncRestServlet extends AbstractRestServlet public void onComplete(Result result) { // extract auctions from the results - Map query = (Map)JSON.parse(_content.toString()); + @SuppressWarnings("unchecked") + Map query = (Map)new JSON().fromJSON(_content.toString()); Object[] auctions = (Object[])query.get("Item"); if (auctions != null) { for (Object o : auctions) { - onAuctionFound((Map)o); + @SuppressWarnings("unchecked") + Map auction = (Map)o; + onAuctionFound(auction); } } onComplete(); @@ -196,8 +201,7 @@ public class AsyncRestServlet extends AbstractRestServlet abstract void onComplete(); - abstract void onAuctionFound(Map details); - + abstract void onAuctionFound(Map details); } @Override diff --git a/examples/async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/SerialRestServlet.java b/examples/async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/SerialRestServlet.java index d3fcd5ecb87..8abf15abf12 100644 --- a/examples/async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/SerialRestServlet.java +++ b/examples/async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/SerialRestServlet.java @@ -45,7 +45,7 @@ public class SerialRestServlet extends AbstractRestServlet final long start = System.nanoTime(); String[] keywords = sanitize(request.getParameter(ITEMS_PARAM)).split(","); - Queue> results = new LinkedList>(); + Queue> results = new LinkedList<>(); // make all requests serially for (String itemName : keywords) @@ -55,13 +55,16 @@ public class SerialRestServlet extends AbstractRestServlet HttpURLConnection connection = (HttpURLConnection)url.openConnection(); connection.setRequestMethod("GET"); - Map query = (Map)JSON.parse(new BufferedReader(new InputStreamReader(connection.getInputStream()))); + @SuppressWarnings("unchecked") + Map query = (Map)new JSON().fromJSON(new BufferedReader(new InputStreamReader(connection.getInputStream()))); Object[] auctions = (Object[])query.get("Item"); if (auctions != null) { for (Object o : auctions) { - results.add((Map)o); + @SuppressWarnings("unchecked") + Map auction = (Map)o; + results.add(auction); } } } diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyHandlers.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyHandlers.java index 8e705b25e7b..77dd973eafe 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyHandlers.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyHandlers.java @@ -83,7 +83,7 @@ public class ManyHandlers if (!params.isEmpty()) { response.setContentType("text/plain"); - response.getWriter().println(JSON.toString(params)); + response.getWriter().println(new JSON().toJSON(params)); baseRequest.setHandled(true); } } diff --git a/examples/embedded/src/test/java/org/eclipse/jetty/embedded/ManyHandlersTest.java b/examples/embedded/src/test/java/org/eclipse/jetty/embedded/ManyHandlersTest.java index 6af5612ff30..9f4ebcf0993 100644 --- a/examples/embedded/src/test/java/org/eclipse/jetty/embedded/ManyHandlersTest.java +++ b/examples/embedded/src/test/java/org/eclipse/jetty/embedded/ManyHandlersTest.java @@ -72,8 +72,9 @@ public class ManyHandlersTest extends AbstractEmbeddedTest // test response content String responseBody = response.getContentAsString(); - Object jsonObj = JSON.parse(responseBody); - Map jsonMap = (Map)jsonObj; + Object jsonObj = new JSON().fromJSON(responseBody); + @SuppressWarnings("unchecked") + Map jsonMap = (Map)jsonObj; assertThat("Response JSON keys.size", jsonMap.keySet().size(), is(2)); } diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackPerfTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackPerfTest.java index 5c004613cbe..bfb43a16865 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackPerfTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackPerfTest.java @@ -68,11 +68,14 @@ public class HpackPerfTest assertNotNull(files); // Parse JSON - Map[] stories = new Map[files.length]; + @SuppressWarnings("unchecked") + Map[] stories = new Map[files.length]; int i = 0; - for (String story : files) + for (String file : files) { - stories[i++] = (Map)JSON.parse(new FileReader(new File(data, story))); + @SuppressWarnings("unchecked") + var story = (Map)new JSON().fromJSON(new FileReader(new File(data, file))); + stories[i++] = story; } ByteBuffer buffer = BufferUtil.allocate(256 * 1024); @@ -88,27 +91,27 @@ public class HpackPerfTest encodeStories(buffer, stories, "response"); } - private void encodeStories(ByteBuffer buffer, Map[] stories, String type) throws Exception + private void encodeStories(ByteBuffer buffer, Map[] stories, String type) throws Exception { - for (Map story : stories) + for (Map story : stories) { if (type.equals(story.get("context"))) { HpackEncoder encoder = new HpackEncoder(_maxDynamicTableSize, _maxDynamicTableSize); encoder.setValidateEncoding(false); - // System.err.println(story); Object[] cases = (Object[])story.get("cases"); for (Object c : cases) { - // System.err.println(" "+c); - Object[] headers = (Object[])((Map)c).get("headers"); + @SuppressWarnings("unchecked") + var kase = (Map)c; + Object[] headers = (Object[])kase.get("headers"); // System.err.println(" "+headers); HttpFields fields = new HttpFields(); for (Object header : headers) { @SuppressWarnings("unchecked") - Map h = (Map)header; + var h = (Map)header; Map.Entry e = h.entrySet().iterator().next(); fields.add(e.getKey(), e.getValue()); _unencodedSize += e.getKey().length() + e.getValue().length(); diff --git a/jetty-openid/src/main/java/org/eclipse/jetty/security/openid/JwtDecoder.java b/jetty-openid/src/main/java/org/eclipse/jetty/security/openid/JwtDecoder.java index a54cf86f4ed..8d4ff89c836 100644 --- a/jetty-openid/src/main/java/org/eclipse/jetty/security/openid/JwtDecoder.java +++ b/jetty-openid/src/main/java/org/eclipse/jetty/security/openid/JwtDecoder.java @@ -54,10 +54,13 @@ public class JwtDecoder String jwtClaimString = new String(decoder.decode(padJWTSection(sections[1])), StandardCharsets.UTF_8); String jwtSignature = sections[2]; - Object parsedJwtHeader = JSON.parse(jwtHeaderString); + JSON json = new JSON(); + + Object parsedJwtHeader = json.fromJSON(jwtHeaderString); if (!(parsedJwtHeader instanceof Map)) throw new IllegalStateException("Invalid JWT header"); - Map jwtHeader = (Map)parsedJwtHeader; + @SuppressWarnings("unchecked") + Map jwtHeader = (Map)parsedJwtHeader; if (LOG.isDebugEnabled()) LOG.debug("JWT Header: {}", jwtHeader); @@ -67,10 +70,10 @@ public class JwtDecoder if (LOG.isDebugEnabled()) LOG.debug("JWT signature not validated {}", jwtSignature); - Object parsedClaims = JSON.parse(jwtClaimString); + Object parsedClaims = json.fromJSON(jwtClaimString); if (!(parsedClaims instanceof Map)) throw new IllegalStateException("Could not decode JSON for JWT claims."); - return (Map)parsedClaims; + return (Map)parsedClaims; } static byte[] padJWTSection(String unpaddedEncodedJwtSection) diff --git a/jetty-openid/src/main/java/org/eclipse/jetty/security/openid/OpenIdConfiguration.java b/jetty-openid/src/main/java/org/eclipse/jetty/security/openid/OpenIdConfiguration.java index 2cc49d35ac8..e7591f524c9 100644 --- a/jetty-openid/src/main/java/org/eclipse/jetty/security/openid/OpenIdConfiguration.java +++ b/jetty-openid/src/main/java/org/eclipse/jetty/security/openid/OpenIdConfiguration.java @@ -128,11 +128,11 @@ public class OpenIdConfiguration extends ContainerLifeCycle Map result; String responseBody = httpClient.GET(provider + CONFIG_PATH) .getContentAsString(); - Object parsedResult = JSON.parse(responseBody); + Object parsedResult = new JSON().fromJSON(responseBody); if (parsedResult instanceof Map) { - Map rawResult = (Map)parsedResult; + Map rawResult = (Map)parsedResult; result = rawResult.entrySet().stream() .collect(Collectors.toMap(it -> it.getKey().toString(), Map.Entry::getValue)); } diff --git a/jetty-openid/src/main/java/org/eclipse/jetty/security/openid/OpenIdCredentials.java b/jetty-openid/src/main/java/org/eclipse/jetty/security/openid/OpenIdCredentials.java index f87a2afcf88..20ba2ec6119 100644 --- a/jetty-openid/src/main/java/org/eclipse/jetty/security/openid/OpenIdCredentials.java +++ b/jetty-openid/src/main/java/org/eclipse/jetty/security/openid/OpenIdCredentials.java @@ -185,9 +185,9 @@ public class OpenIdCredentials implements Serializable if (LOG.isDebugEnabled()) LOG.debug("Authentication response: {}", responseBody); - Object parsedResponse = JSON.parse(responseBody); + Object parsedResponse = new JSON().fromJSON(responseBody); if (!(parsedResponse instanceof Map)) throw new IllegalStateException("Malformed response from OpenID Provider"); - return (Map)parsedResponse; + return (Map)parsedResponse; } } diff --git a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/AsyncMiddleManServletTest.java b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/AsyncMiddleManServletTest.java index b02cc30cb5d..6937aa50b5a 100644 --- a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/AsyncMiddleManServletTest.java +++ b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/AsyncMiddleManServletTest.java @@ -863,20 +863,21 @@ public class AsyncMiddleManServletTest @Test public void testAfterContentTransformer() throws Exception { - final String key0 = "id"; + String key0 = "id"; long value0 = 1; - final String key1 = "channel"; + String key1 = "channel"; String value1 = "foo"; - final String json = "{ \"" + key0 + "\":" + value0 + ", \"" + key1 + "\":\"" + value1 + "\" }"; + String jsonString = "{ \"" + key0 + "\":" + value0 + ", \"" + key1 + "\":\"" + value1 + "\" }"; startServer(new HttpServlet() { @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException { - response.getOutputStream().write(json.getBytes(StandardCharsets.UTF_8)); + response.getOutputStream().write(jsonString.getBytes(StandardCharsets.UTF_8)); } }); - final String key2 = "c"; + String key2 = "c"; + JSON json = new JSON(); startProxy(new AsyncMiddleManServlet() { @Override @@ -889,12 +890,12 @@ public class AsyncMiddleManServletTest { InputStream input = source.getInputStream(); @SuppressWarnings("unchecked") - Map obj = (Map)JSON.parse(new InputStreamReader(input, StandardCharsets.UTF_8)); + Map obj = (Map)json.fromJSON(new InputStreamReader(input, StandardCharsets.UTF_8)); // Transform the object. obj.put(key2, obj.remove(key1)); try (OutputStream output = sink.getOutputStream()) { - output.write(JSON.toString(obj).getBytes(StandardCharsets.UTF_8)); + output.write(json.toJSON(obj).getBytes(StandardCharsets.UTF_8)); return true; } } @@ -909,7 +910,7 @@ public class AsyncMiddleManServletTest assertEquals(200, response.getStatus()); @SuppressWarnings("unchecked") - Map obj = (Map)JSON.parse(response.getContentAsString()); + Map obj = (Map)json.fromJSON(response.getContentAsString()); assertNotNull(obj); assertEquals(2, obj.size()); assertEquals(value0, obj.get(key0)); @@ -984,24 +985,25 @@ public class AsyncMiddleManServletTest public void testAfterContentTransformerOverflowingToDisk() throws Exception { // Make sure the temporary directory we use exists and it's empty. - final Path targetTestsDir = prepareTargetTestsDir(); + Path targetTestsDir = prepareTargetTestsDir(); - final String key0 = "id"; + String key0 = "id"; long value0 = 1; - final String key1 = "channel"; + String key1 = "channel"; String value1 = "foo"; - final String json = "{ \"" + key0 + "\":" + value0 + ", \"" + key1 + "\":\"" + value1 + "\" }"; + String jsonString = "{ \"" + key0 + "\":" + value0 + ", \"" + key1 + "\":\"" + value1 + "\" }"; startServer(new HttpServlet() { @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException { - response.getOutputStream().write(json.getBytes(StandardCharsets.UTF_8)); + response.getOutputStream().write(jsonString.getBytes(StandardCharsets.UTF_8)); } }); - final String inputPrefix = "in_"; - final String outputPrefix = "out_"; - final String key2 = "c"; + String inputPrefix = "in_"; + String outputPrefix = "out_"; + String key2 = "c"; + JSON json = new JSON(); startProxy(new AsyncMiddleManServlet() { @Override @@ -1014,18 +1016,18 @@ public class AsyncMiddleManServletTest { InputStream input = source.getInputStream(); @SuppressWarnings("unchecked") - Map obj = (Map)JSON.parse(new InputStreamReader(input, StandardCharsets.UTF_8)); + Map obj = (Map)json.fromJSON(new InputStreamReader(input, StandardCharsets.UTF_8)); // Transform the object. obj.put(key2, obj.remove(key1)); try (OutputStream output = sink.getOutputStream()) { - output.write(JSON.toString(obj).getBytes(StandardCharsets.UTF_8)); + output.write(json.toJSON(obj).getBytes(StandardCharsets.UTF_8)); return true; } } }; transformer.setOverflowDirectory(targetTestsDir); - int maxBufferSize = json.length() / 4; + int maxBufferSize = jsonString.length() / 4; transformer.setMaxInputBufferSize(maxBufferSize); transformer.setInputFilePrefix(inputPrefix); transformer.setMaxOutputBufferSize(maxBufferSize); @@ -1041,7 +1043,7 @@ public class AsyncMiddleManServletTest assertEquals(200, response.getStatus()); @SuppressWarnings("unchecked") - Map obj = (Map)JSON.parse(response.getContentAsString()); + Map obj = (Map)json.fromJSON(response.getContentAsString()); assertNotNull(obj); assertEquals(2, obj.size()); assertEquals(value0, obj.get(key0)); @@ -1202,19 +1204,20 @@ public class AsyncMiddleManServletTest private void testAfterContentTransformerDoNoTransform(final boolean readSource, final boolean useDisk) throws Exception { - final String key0 = "id"; + String key0 = "id"; long value0 = 1; - final String key1 = "channel"; + String key1 = "channel"; String value1 = "foo"; - final String json = "{ \"" + key0 + "\":" + value0 + ", \"" + key1 + "\":\"" + value1 + "\" }"; + String jsonString = "{ \"" + key0 + "\":" + value0 + ", \"" + key1 + "\":\"" + value1 + "\" }"; startServer(new HttpServlet() { @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException { - response.getOutputStream().write(json.getBytes(StandardCharsets.UTF_8)); + response.getOutputStream().write(jsonString.getBytes(StandardCharsets.UTF_8)); } }); + JSON json = new JSON(); startProxy(new AsyncMiddleManServlet() { @Override @@ -1233,7 +1236,7 @@ public class AsyncMiddleManServletTest if (readSource) { InputStream input = source.getInputStream(); - JSON.parse(new InputStreamReader(input, StandardCharsets.UTF_8)); + json.fromJSON(new InputStreamReader(input, StandardCharsets.UTF_8)); } // No transformation. return false; @@ -1249,7 +1252,7 @@ public class AsyncMiddleManServletTest assertEquals(200, response.getStatus()); @SuppressWarnings("unchecked") - Map obj = (Map)JSON.parse(response.getContentAsString()); + Map obj = (Map)json.fromJSON(response.getContentAsString()); assertNotNull(obj); assertEquals(2, obj.size()); assertEquals(value0, obj.get(key0)); diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ErrorHandlerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ErrorHandlerTest.java index b949efc73cf..b6a6957a4a9 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ErrorHandlerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ErrorHandlerTest.java @@ -474,7 +474,8 @@ public class ErrorHandlerTest } else if (contentType.contains("text/json")) { - Map jo = (Map)JSON.parse(response.getContent()); + @SuppressWarnings("unchecked") + Map jo = (Map)new JSON().fromJSON(response.getContent()); Set acceptableKeyNames = new HashSet<>(); acceptableKeyNames.add("url"); diff --git a/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSON.java b/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSON.java index 3b4522733eb..831db53ede0 100644 --- a/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSON.java +++ b/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSON.java @@ -26,6 +26,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -35,13 +36,12 @@ import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; /** - * JSON Parser and Generator. - *

- * This class provides some static methods to convert POJOs to and from JSON - * notation. The mapping from JSON to java is: + *

JSON parser and generator.

+ *

This class provides methods to convert POJOs to and from JSON notation.

+ *

The mapping from JSON to Java is:

* *
- *   object --> Map
+ *   object --> Map<String, Object>
  *   array  --> Object[]
  *   number --> Double or Long
  *   string --> String
@@ -49,7 +49,7 @@ import org.eclipse.jetty.util.log.Logger;
  *   bool   --> Boolean
  * 
* - * The java to JSON mapping is: + *

The Java to JSON mapping is:

* *
  *   String --> string
@@ -62,49 +62,31 @@ import org.eclipse.jetty.util.log.Logger;
  *   Object --> string (dubious!)
  * 
* - * The interface {@link JSON.Convertible} may be implemented by classes that + *

The interface {@link JSON.Convertible} may be implemented by classes that * wish to externalize and initialize specific fields to and from JSON objects. - * Only directed acyclic graphs of objects are supported. - *

- * The interface {@link JSON.Generator} may be implemented by classes that know - * how to render themselves as JSON and the {@link #toString(Object)} method - * will use {@link JSON.Generator#addJSON(Appendable)} to generate the JSON. - * The class {@link JSON.Literal} may be used to hold pre-generated JSON object. - *

- * The interface {@link JSON.Convertor} may be implemented to provide static + * Only directed acyclic graphs of objects are supported.

+ *

The interface {@link JSON.Generator} may be implemented by classes that + * know how to render themselves as JSON and the {@link #toJSON(Object)} method + * will use {@link JSON.Generator#addJSON(Appendable)} to generate the JSON.

+ *

The class {@link JSON.Literal} may be used to hold pre-generated JSON object.

+ *

The interface {@link JSON.Convertor} may be implemented to provide * converters for objects that may be registered with - * {@link #registerConvertor(Class, Convertor)}. + * {@link #addConvertor(Class, Convertor)}. * These converters are looked up by class, interface and super class by - * {@link #getConvertor(Class)}. - *

- * If a JSON object has a "class" field, then a java class for that name is - * loaded and the method {@link #convertTo(Class, Map)} is used to find a - * {@link JSON.Convertor} for that class. - *

- * If a JSON object has a "x-class" field then a direct lookup for a - * {@link JSON.Convertor} for that class name is done (without loading the class). + * {@link #getConvertor(Class)}.

+ *

If a JSON object has a {@code class} field, then a Java class for that + * name is loaded and the method {@link #convertTo(Class, Map)} is used to find + * a {@link JSON.Convertor} for that class.

+ *

If a JSON object has a {@code x-class} field then a direct lookup for a + * {@link JSON.Convertor} for that class name is done (without loading the class).

*/ public class JSON { static final Logger LOG = Log.getLogger(JSON.class); - public static final JSON DEFAULT = new JSON(); - private Map _convertors = new ConcurrentHashMap(); + private final Map _convertors = new ConcurrentHashMap<>(); private int _stringBufferSize = 1024; - public JSON() - { - } - - /** - * Reset the default JSON behaviors to default - */ - public static void reset() - { - DEFAULT._convertors.clear(); - DEFAULT._stringBufferSize = 1024; - } - /** * @return the initial stringBuffer size to use when creating JSON strings * (default 1024) @@ -124,45 +106,45 @@ public class JSON } /** - * Register a {@link Convertor} for a class or interface. + *

Converts the given object to JSON.

* - * @param forClass The class or interface that the convertor applies to - * @param convertor the convertor + * @param object the object to convert + * @return the JSON string representation of the object + * @deprecated use {@link JSON#toJSON(Object)} instead */ - public static void registerConvertor(Class forClass, Convertor convertor) - { - DEFAULT.addConvertor(forClass, convertor); - } - - public static JSON getDefault() - { - return DEFAULT; - } - + @Deprecated(forRemoval = true) public static String toString(Object object) { - StringBuilder buffer = new StringBuilder(DEFAULT.getStringBufferSize()); - DEFAULT.append(buffer, object); - return buffer.toString(); + JSON json = new JSON(); + return json.toJSON(object); } - public static String toString(Map object) + /** + *

Converts the given Map to JSON.

+ * + * @param map the Map to convert + * @return the JSON string representation of the map + * @deprecated use {@link JSON#toJSON(Object)} instead + */ + @Deprecated(forRemoval = true) + public static String toString(Map map) { - StringBuilder buffer = new StringBuilder(DEFAULT.getStringBufferSize()); - DEFAULT.appendMap(buffer, object); - return buffer.toString(); + JSON json = new JSON(); + return json.toJSON(map); } + /** + *

Converts the given array to JSON.

+ * + * @param array the array to convert + * @return the JSON string representation of the array + * @deprecated use {@link JSON#toJSON(Object)} instead + */ + @Deprecated(forRemoval = true) public static String toString(Object[] array) { - StringBuilder buffer = new StringBuilder(DEFAULT.getStringBufferSize()); - DEFAULT.appendArray(buffer, array); - return buffer.toString(); - } - - protected String toString(char[] buffer, int offset, int length) - { - return new String(buffer, offset, length); + JSON json = new JSON(); + return json.toJSON(array); } private void quotedEscape(Appendable buffer, String input) @@ -171,9 +153,7 @@ public class JSON { buffer.append('"'); if (input != null && !input.isEmpty()) - { escapeString(buffer, input); - } buffer.append('"'); } catch (IOException e) @@ -182,10 +162,17 @@ public class JSON } } + /** + *

Escapes the characters of the given {@code input} string into the given buffer.

+ * + * @param buffer the buffer to escape the string into + * @param input the string to escape + * @throws IOException if appending to the buffer fails + * @see #escapeUnicode(Appendable, char) + */ public void escapeString(Appendable buffer, String input) throws IOException { - // default escaping here. - + // Default escaping algorithm. for (int i = 0; i < input.length(); ++i) { char c = input.charAt(i); @@ -193,7 +180,7 @@ public class JSON // ASCII printable range if ((c >= 0x20) && (c <= 0x7E)) { - // Special cases for quotation-mark, reverse-solidus, and solidus + // Special cases for quotation-mark, reverse-solidus, and solidus. if ((c == '"') || (c == '\\') /* solidus is optional - per Carsten Bormann (IETF) || (c == '/') */) @@ -202,15 +189,14 @@ public class JSON } else { - // ASCII printable (that isn't escaped above) + // ASCII printable (that isn't escaped above). buffer.append(c); } } else { - // All other characters are escaped (in some way) - - // First we deal with the special short-form escaping + // All other characters are escaped (in some way). + // First we deal with the special short-form escaping. if (c == '\b') // backspace buffer.append("\\b"); else if (c == '\f') // form-feed @@ -223,12 +209,12 @@ public class JSON buffer.append("\\t"); else if (c < 0x20 || c == 0x7F) // all control characters { - // default behavior is to encode - buffer.append(String.format("\\u%04x", (short)c)); + // Default behavior is to encode. + buffer.append(String.format("\\u%04x", (int)c)); } else { - // optional behavior in JSON spec + // Optional behavior in JSON spec. escapeUnicode(buffer, c); } } @@ -236,17 +222,17 @@ public class JSON } /** - * Per spec, unicode characters are by default NOT escaped. - * This overridable allows for alternate behavior to escape those with your choice - * of encoding. + *

Per JSON specification, unicode characters are by default NOT escaped.

+ *

Overriding this method allows for alternate behavior to escape those + * with your choice of encoding.

* - * + *
      * protected void escapeUnicode(Appendable buffer, char c) throws IOException
      * {
-     * // Unicode is slash-u escaped
-     * buffer.append(String.format("\\u%04x", (int)c));
+     *     // Unicode is backslash-u escaped
+     *     buffer.append(String.format("\\u%04x", (int)c));
      * }
-     * 
+     * 
*/ protected void escapeUnicode(Appendable buffer, char c) throws IOException { @@ -254,10 +240,11 @@ public class JSON } /** - * Convert Object to JSON + *

Converts any object to JSON.

* - * @param object The object to convert - * @return The JSON String + * @param object the object to convert + * @return the JSON string representation of the object + * @see #append(Appendable, Object) */ public String toJSON(Object object) { @@ -267,22 +254,13 @@ public class JSON } /** - * Convert JSON to Object - * - * @param json The json to convert - * @return The object - */ - public Object fromJSON(String json) - { - Source source = new StringSource(json); - return parse(source); - } - - /** - * Append object as JSON to string buffer. + *

Appends the given object as JSON to string buffer.

+ *

This method tests the given object type and calls other + * appends methods for each object type, see for example + * {@link #appendMap(Appendable, Map)}.

* * @param buffer the buffer to append to - * @param object the object to append + * @param object the object to convert to JSON */ public void append(Appendable buffer, Object object) { @@ -295,7 +273,7 @@ public class JSON // Most likely first else if (object instanceof Map) { - appendMap(buffer, (Map)object); + appendMap(buffer, (Map)object); } else if (object instanceof String) { @@ -327,7 +305,7 @@ public class JSON } else { - // Check Convertor before Collection to support JSONCollectionConvertor + // Check Convertor before Collection to support JSONCollectionConvertor. Convertor convertor = getConvertor(object.getClass()); if (convertor != null) { @@ -335,7 +313,7 @@ public class JSON } else if (object instanceof Collection) { - appendArray(buffer, (Collection)object); + appendArray(buffer, (Collection)object); } else { @@ -361,12 +339,12 @@ public class JSON } } - public void appendJSON(final Appendable buffer, final Convertor convertor, final Object object) + public void appendJSON(Appendable buffer, Convertor convertor, Object object) { appendJSON(buffer, new Convertible() { @Override - public void fromJSON(Map object) + public void fromJSON(Map object) { } @@ -378,7 +356,7 @@ public class JSON }); } - public void appendJSON(final Appendable buffer, Convertible converter) + public void appendJSON(Appendable buffer, Convertible converter) { ConvertableOutput out = new ConvertableOutput(buffer); converter.toJSON(out); @@ -401,17 +379,16 @@ public class JSON } buffer.append('{'); - Iterator iter = map.entrySet().iterator(); + Iterator> iter = map.entrySet().iterator(); while (iter.hasNext()) { - Map.Entry entry = (Map.Entry)iter.next(); + Map.Entry entry = iter.next(); quotedEscape(buffer, entry.getKey().toString()); buffer.append(':'); append(buffer, entry.getValue()); if (iter.hasNext()) buffer.append(','); } - buffer.append('}'); } catch (IOException e) @@ -420,7 +397,7 @@ public class JSON } } - public void appendArray(Appendable buffer, Collection collection) + public void appendArray(Appendable buffer, Collection collection) { try { @@ -431,17 +408,13 @@ public class JSON } buffer.append('['); - Iterator iter = collection.iterator(); - boolean first = true; + Iterator iter = collection.iterator(); while (iter.hasNext()) { - if (!first) - buffer.append(','); - - first = false; append(buffer, iter.next()); + if (iter.hasNext()) + buffer.append(','); } - buffer.append(']'); } catch (IOException e) @@ -462,14 +435,12 @@ public class JSON buffer.append('['); int length = Array.getLength(array); - for (int i = 0; i < length; i++) { if (i != 0) buffer.append(','); append(buffer, Array.get(array, i)); } - buffer.append(']'); } catch (IOException e) @@ -519,104 +490,95 @@ public class JSON appendNull(buffer); return; } - quotedEscape(buffer, string); } + /** + *

Factory method that creates a Map when a JSON representation of {@code {...}} is parsed.

+ * + * @return a new Map representing the JSON object + */ protected Map newMap() { - return new HashMap(); + return new HashMap<>(); } + /** + *

Factory method that creates an array when a JSON representation of {@code [...]} is parsed.

+ * + * @param size the size of the array + * @return a new array representing the JSON array + */ protected Object[] newArray(int size) { return new Object[size]; } + /** + *

Every time a JSON array representation {@code [...]} is parsed, this method is called + * to (possibly) return a different JSON instance (for example configured with different + * converters) to parse the array items.

+ * + * @return a JSON instance to parse array items + */ protected JSON contextForArray() { return this; } + /** + *

Every time a JSON object field representation {@code {"name": value}} is parsed, + * this method is called to (possibly) return a different JSON instance (for example + * configured with different converters) to parse the object field.

+ * + * @param field the field name + * @return a JSON instance to parse the object field + */ protected JSON contextFor(String field) { return this; } - protected Object convertTo(Class type, Map map) + protected Object convertTo(Class type, Map map) { - if (type != null && Convertible.class.isAssignableFrom(type)) + if (Convertible.class.isAssignableFrom(type)) { try { - Convertible conv = (Convertible)type.getDeclaredConstructor().newInstance(); - conv.fromJSON(map); - return conv; + Convertible convertible = (Convertible)type.getConstructor().newInstance(); + convertible.fromJSON(map); + return convertible; } catch (Exception e) { throw new RuntimeException(e); } } - - Convertor convertor = getConvertor(type); - if (convertor != null) + else { - return convertor.fromJSON(map); + Convertor convertor = getConvertor(type); + if (convertor != null) + return convertor.fromJSON(map); + return map; } - return map; } /** - * Register a {@link Convertor} for a class or interface. + *

Registers a {@link Convertor} for the given class.

* - * @param forClass The class or interface that the convertor applies to - * @param convertor the convertor + * @param forClass the class the convertor applies to + * @param convertor the convertor for the class */ - public void addConvertor(Class forClass, Convertor convertor) + public void addConvertor(Class forClass, Convertor convertor) { - _convertors.put(forClass.getName(), convertor); + addConvertorFor(forClass.getName(), convertor); } /** - * Lookup a convertor for a class. - *

- * If no match is found for the class, then the interfaces for the class are - * tried. If still no match is found, then the super class and it's - * interfaces are tried recursively. + *

Registers a {@link JSON.Convertor} for a named class.

* - * @param forClass The class - * @return a {@link JSON.Convertor} or null if none were found. - */ - protected Convertor getConvertor(Class forClass) - { - Class cls = forClass; - Convertor convertor = _convertors.get(cls.getName()); - if (convertor == null && this != DEFAULT) - convertor = DEFAULT.getConvertor(cls); - - while (convertor == null && cls != Object.class) - { - Class[] ifs = cls.getInterfaces(); - int i = 0; - while (convertor == null && ifs != null && i < ifs.length) - { - convertor = _convertors.get(ifs[i++].getName()); - } - if (convertor == null) - { - cls = cls.getSuperclass(); - convertor = _convertors.get(cls.getName()); - } - } - return convertor; - } - - /** - * Register a {@link JSON.Convertor} for a named class or interface. - * - * @param name name of a class or an interface that the convertor applies to - * @param convertor the convertor + * @param name the name of the class the convertor applies to + * @param convertor the convertor for the class */ public void addConvertorFor(String name, Convertor convertor) { @@ -624,59 +586,134 @@ public class JSON } /** - * Lookup a convertor for a named class. + *

Unregisters a {@link Convertor} for a class.

* - * @param name name of the class + * @param forClass the class the convertor applies to + * @return the convertor for the class + */ + public Convertor removeConvertor(Class forClass) + { + return removeConvertorFor(forClass.getName()); + } + + /** + *

Unregisters a {@link Convertor} for a named class.

+ * + * @param name the name of the class the convertor applies to + * @return the convertor for the class + */ + public Convertor removeConvertorFor(String name) + { + return _convertors.remove(name); + } + + /** + *

Looks up a convertor for a class.

+ *

If no match is found for the class, then the interfaces + * for the class are tried. + * If still no match is found, then the super class and its + * interfaces are tried iteratively.

+ * + * @param forClass the class to look up the convertor + * @return a {@link JSON.Convertor} or null if none was found for the class + */ + protected Convertor getConvertor(Class forClass) + { + Class cls = forClass; + while (cls != null) + { + Convertor convertor = _convertors.get(cls.getName()); + if (convertor != null) + return convertor; + Class[] intfs = cls.getInterfaces(); + for (Class intf : intfs) + { + convertor = _convertors.get(intf.getName()); + if (convertor != null) + return convertor; + } + cls = cls.getSuperclass(); + } + return null; + } + + /** + *

Looks up a convertor for a class name.

+ * + * @param name name of the class to look up the convertor * @return a {@link JSON.Convertor} or null if none were found. */ public Convertor getConvertorFor(String name) { - Convertor convertor = _convertors.get(name); - if (convertor == null && this != DEFAULT) - convertor = DEFAULT.getConvertorFor(name); - return convertor; + return _convertors.get(name); } /** - * @param in Reader containing JSON object or array. - * @param stripOuterComment If true, an outer comment around the JSON is ignored. - * @return A Map, Object array or primitive array parsed from the JSON. + * @param reader the Reader to read the JSON representation from + * @return the object constructed from the JSON string representation * @throws IOException if unable to parse + * @deprecated use {@link #fromJSON(Reader)} */ - public static Object parse(Reader in, boolean stripOuterComment) throws IOException + @Deprecated(forRemoval = true) + public static Object parse(Reader reader) throws IOException { - return DEFAULT.parse(new ReaderSource(in), stripOuterComment); + return new JSON().parse(new ReaderSource(reader), false); } /** - * @param s String containing JSON object or array. - * @return A Map, Object array or primitive array parsed from the JSON. - */ - public static Object parse(String s) - { - return DEFAULT.parse(new StringSource(s), false); - } - - /** - * @param s String containing JSON object or array. - * @param stripOuterComment If true, an outer comment around the JSON is ignored. - * @return A Map, Object array or primitive array parsed from the JSON. - */ - public static Object parse(String s, boolean stripOuterComment) - { - return DEFAULT.parse(new StringSource(s), stripOuterComment); - } - - /** - * @param in Reader containing JSON object or array. - * @return A Map, Object array or primitive array parsed from the JSON. + * @param reader the Reader to read the JSON representation from + * @param stripOuterComment whether to ignore an outer comment around the JSON + * @return the object constructed from the JSON string representation * @throws IOException if unable to parse + * @deprecated use {@link #fromJSON(Reader)} */ - public static Object parse(Reader in) throws IOException + @Deprecated(forRemoval = true) + public static Object parse(Reader reader, boolean stripOuterComment) throws IOException { - return DEFAULT.parse(new ReaderSource(in), false); + return new JSON().parse(new ReaderSource(reader), stripOuterComment); } + /** + * @param json the JSON string to parse + * @return the object constructed from the JSON string representation + * @deprecated use {@link #fromJSON(String)} + */ + @Deprecated(forRemoval = true) + public static Object parse(String json) + { + return new JSON().parse(new StringSource(json), false); + } + + /** + * @param json the JSON string to parse + * @param stripOuterComment whether to ignore an outer comment around the JSON + * @return the object constructed from the JSON string representation + * @deprecated use {@link #fromJSON(String)} + */ + @Deprecated(forRemoval = true) + public static Object parse(String json, boolean stripOuterComment) + { + return new JSON().parse(new StringSource(json), stripOuterComment); + } + + /** + *

Parses the given JSON source into an object.

+ *

Although the JSON specification does not allow comments (of any kind) + * this method optionally strips out outer comments of this form:

+ *
+     * // An outer comment line.
+     * /* Another outer comment, multiline.
+     * // Yet another comment line.
+     * {
+     *     "name": "the real JSON"
+     * }
+     * */ End of outer comment, multiline.
+     * 
+ * + * @param source the JSON source to parse + * @param stripOuterComment whether to strip outer comments + * @return the object constructed from the JSON string representation + */ public Object parse(Source source, boolean stripOuterComment) { int commentState = 0; // 0=no comment, 1="/", 2="/*", 3="/* *" -1="//" @@ -690,7 +727,7 @@ public class JSON { char c = source.peek(); - // handle // or /* comment + // Handle // or /* comment. if (commentState == 1) { switch (c) @@ -710,7 +747,7 @@ public class JSON break; } } - // handle /* C style */ comment + // Handle /* C style */ comment. else if (commentState > 1) { switch (c) @@ -725,14 +762,13 @@ public class JSON if (stripState == 2) return o; } - else - commentState = 2; break; default: commentState = 2; + break; } } - // handle // comment + // Handle // comment. else if (commentState < 0) { switch (c) @@ -745,7 +781,7 @@ public class JSON break; } } - // handle unknown + // Handle unknown. else { if (!Character.isWhitespace(c)) @@ -768,6 +804,47 @@ public class JSON return o; } + /** + *

Parses the given JSON string into an object.

+ * + * @param string the JSON string to parse + * @return the object constructed from the JSON string representation + */ + public Object fromJSON(String string) + { + return parse(new StringSource(string), false); + } + + /** + *

Parses the JSON from the given Reader into an object.

+ * + * @param reader the Reader to read the JSON from + * @return the object constructed from the JSON string representation + */ + public Object fromJSON(Reader reader) + { + return parse(new ReaderSource(reader), false); + } + + /** + *

Parses the given JSON source into an object.

+ *

Although the JSON specification does not allow comments (of any kind) + * this method strips out initial comments of this form:

+ *
+     * // An initial comment line.
+     * /* An initial
+     *    multiline comment */
+     * {
+     *     "name": "foo"
+     * }
+     * 
+ *

This method detects the object type and calls other + * parse methods for each object type, see for example + * {@link #parseArray(Source)}.

+ * + * @param source the JSON source to parse + * @return the object constructed from the JSON string representation + */ public Object parse(Source source) { int commentState = 0; // 0=no comment, 1="/", 2="/*", 3="/* *" -1="//" @@ -776,7 +853,7 @@ public class JSON { char c = source.peek(); - // handle // or /* comment + // Handle // or /* comment. if (commentState == 1) { switch (c) @@ -791,7 +868,7 @@ public class JSON break; } } - // handle /* C Style */ comment + // Handle /* C Style */ comment. else if (commentState > 1) { switch (c) @@ -802,14 +879,13 @@ public class JSON case '/': if (commentState == 3) commentState = 0; - else - commentState = 2; break; default: commentState = 2; + break; } } - // handle // comment + // Handle // comment. else if (commentState < 0) { switch (c) @@ -822,7 +898,7 @@ public class JSON break; } } - // handle unknown + // Handle unknown. else { switch (c) @@ -835,7 +911,6 @@ public class JSON return parseString(source); case '-': return parseNumber(source); - case 'n': complete("null", source); return null; @@ -851,11 +926,9 @@ public class JSON case 'N': complete("NaN", source); return null; - case '/': commentState = 1; break; - default: if (Character.isDigit(c)) return parseNumber(source); @@ -879,10 +952,9 @@ public class JSON { if (source.next() != '{') throw new IllegalStateException(); + Map map = newMap(); - char next = seekTo("\"}", source); - while (source.hasNext()) { if (next == '}') @@ -920,12 +992,12 @@ public class JSON { try { - Class c = Loader.loadClass(classname); + Class c = Loader.loadClass(classname); return convertTo(c, map); } catch (ClassNotFoundException e) { - LOG.warn("No Class for '{}'", classname); + LOG.warn("No class for '{}'", classname); } } @@ -938,10 +1010,9 @@ public class JSON throw new IllegalStateException(); int size = 0; - ArrayList list = null; + List list = null; Object item = null; - boolean coma = true; - + boolean comma = true; while (source.hasNext()) { char c = source.peek(); @@ -960,25 +1031,28 @@ public class JSON default: return list.toArray(newArray(list.size())); } - case ',': - if (coma) + if (comma) throw new IllegalStateException(); - coma = true; + comma = true; source.next(); break; default: if (Character.isWhitespace(c)) + { source.next(); + } else { - coma = false; + comma = false; if (size++ == 0) + { item = contextForArray().parse(source); + } else if (list == null) { - list = new ArrayList(); + list = new ArrayList<>(); list.add(item); item = contextForArray().parse(source); list.add(item); @@ -1003,10 +1077,8 @@ public class JSON throw new IllegalStateException(); boolean escape = false; - StringBuilder b = null; - final char[] scratch = source.scratchBuffer(); - + char[] scratch = source.scratchBuffer(); if (scratch != null) { int i = 0; @@ -1014,8 +1086,8 @@ public class JSON { if (i >= scratch.length) { - // we have filled the scratch buffer, so we must - // use the StringBuffer for a large string + // We have filled the scratch buffer, so we must + // use the StringBuffer for a large string. b = new StringBuilder(scratch.length * 2); b.append(scratch, 0, i); break; @@ -1068,7 +1140,7 @@ public class JSON else if (c == '\"') { // Return string that fits within scratch buffer - return toString(scratch, 0, i); + return new String(scratch, 0, i); } else { @@ -1078,17 +1150,18 @@ public class JSON // Missing end quote, but return string anyway ? if (b == null) - return toString(scratch, 0, i); + return new String(scratch, 0, i); } else + { b = new StringBuilder(getStringBufferSize()); + } // parse large string into string buffer - final StringBuilder builder = b; + StringBuilder builder = b; while (source.hasNext()) { char c = source.next(); - if (escape) { escape = false; @@ -1168,7 +1241,6 @@ public class JSON number = number * 10 + (c - '0'); source.next(); break; - case '-': case '+': if (number != 0) @@ -1176,7 +1248,6 @@ public class JSON minus = true; source.next(); break; - case '.': case 'e': case 'E': @@ -1187,7 +1258,6 @@ public class JSON buffer.append(c); source.next(); break longLoop; - default: break longLoop; } @@ -1220,7 +1290,6 @@ public class JSON buffer.append(c); source.next(); break; - default: break doubleLoop; } @@ -1250,9 +1319,7 @@ public class JSON { char c = source.peek(); if (seek.indexOf(c) >= 0) - { return c; - } if (!Character.isWhitespace(c)) throw new IllegalStateException("Unexpected '" + c + "' while seeking one of '" + seek + "'"); @@ -1279,7 +1346,7 @@ public class JSON private final class ConvertableOutput implements Output { private final Appendable _buffer; - char c = '{'; + private char c = '{'; private ConvertableOutput(Appendable buffer) { @@ -1387,7 +1454,7 @@ public class JSON } @Override - public void addClass(Class type) + public void addClass(Class type) { try { @@ -1405,6 +1472,9 @@ public class JSON } } + /** + *

A generic source for a JSON representation.

+ */ public interface Source { boolean hasNext(); @@ -1416,6 +1486,9 @@ public class JSON char[] scratchBuffer(); } + /** + *

An in-memory source for a JSON string.

+ */ public static class StringSource implements Source { private final String string; @@ -1463,6 +1536,9 @@ public class JSON } } + /** + *

A Reader source for a JSON string.

+ */ public static class ReaderSource implements Source { private Reader _reader; @@ -1537,7 +1613,7 @@ public class JSON */ public interface Output { - public void addClass(Class c); + public void addClass(Class c); public void add(Object obj); @@ -1551,45 +1627,46 @@ public class JSON } /** - * JSON Convertible object. Object can implement this interface in a similar - * way to the {@link Externalizable} interface is used to allow classes to - * provide their own serialization mechanism. - *

- * A JSON.Convertible object may be written to a JSONObject or initialized - * from a Map of field names to values. - *

- * If the JSON is to be convertible back to an Object, then the method - * {@link Output#addClass(Class)} must be called from within toJSON() + *

JSON Convertible object.

+ *

Classes can implement this interface in a similar way to the + * {@link Externalizable} interface is used to allow classes to + * provide their own serialization mechanism.

+ *

A JSON.Convertible object may be written to a JSONObject or + * initialized from a Map of field names to values.

+ *

If the JSON is to be convertible back to an Object, then the method + * {@link Output#addClass(Class)} must be called from within + * {@link #toJSON(Output)}.

*/ public interface Convertible { public void toJSON(Output out); - public void fromJSON(Map object); + public void fromJSON(Map object); } /** - * Static JSON Convertor. - *

- * may be implemented to provide static convertors for objects that may be - * registered with - * {@link JSON#registerConvertor(Class, org.eclipse.jetty.util.ajax.JSON.Convertor)} - * . These convertors are looked up by class, interface and super class by - * {@link JSON#getConvertor(Class)}. Convertors should be used when the - * classes to be converted cannot implement {@link Convertible} or - * {@link Generator}. + *

JSON Convertor.

+ *

Implementations provide convertors for objects that may be + * registered with {@link #addConvertor(Class, Convertor)}. + * These convertors are looked up by class, interfaces and super class + * by {@link JSON#getConvertor(Class)}. + * Convertors should be used when the classes to be converted cannot + * implement {@link Convertible} or {@link Generator}.

*/ public interface Convertor { public void toJSON(Object obj, Output out); - public Object fromJSON(Map object); + public Object fromJSON(Map object); } /** - * JSON Generator. A class that can add it's JSON representation directly to - * a StringBuffer. This is useful for object instances that are frequently - * converted and wish to avoid multiple Conversions + *

JSON Generator.

+ *

Implemented by classes that can add their own JSON representation + * directly to a StringBuffer. + * This is useful for object instances that are frequently + * converted and wish to avoid multiple conversions, as the result of + * the generation may be cached.

*/ public interface Generator { @@ -1597,24 +1674,21 @@ public class JSON } /** - * A Literal JSON generator A utility instance of {@link JSON.Generator} - * that holds a pre-generated string on JSON text. + *

A Literal JSON generator.

+ *

A utility instance of {@link JSON.Generator} + * that holds a pre-generated string on JSON text.

*/ public static class Literal implements Generator { private String _json; /** - * Construct a literal JSON instance for use by - * {@link JSON#toString(Object)}. If {@link Logger#isDebugEnabled()} is - * true, the JSON will be parsed to check validity + * Constructs a literal JSON instance. * - * @param json A literal JSON string. + * @param json a literal JSON string */ public Literal(String json) { - if (LOG.isDebugEnabled()) // TODO: Make this a configurable option on JSON instead! - parse(json); _json = json; } diff --git a/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSONCollectionConvertor.java b/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSONCollectionConvertor.java index cb6451ff2d6..227b44c9437 100644 --- a/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSONCollectionConvertor.java +++ b/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSONCollectionConvertor.java @@ -30,16 +30,18 @@ public class JSONCollectionConvertor implements JSON.Convertor public void toJSON(Object obj, JSON.Output out) { out.addClass(obj.getClass()); - out.add("list", ((Collection)obj).toArray()); + Collection collection = (Collection)obj; + out.add("list", collection.toArray()); } @Override - public Object fromJSON(Map object) + public Object fromJSON(Map object) { try { - Collection result = (Collection)Loader.loadClass((String)object.get("class")) - .getDeclaredConstructor().newInstance(); + Class cls = Loader.loadClass((String)object.get("class")); + @SuppressWarnings("unchecked") + Collection result = (Collection)cls.getConstructor().newInstance(); Collections.addAll(result, (Object[])object.get("list")); return result; } diff --git a/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSONDateConvertor.java b/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSONDateConvertor.java index 91771db9e3d..e192dc4e08c 100644 --- a/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSONDateConvertor.java +++ b/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSONDateConvertor.java @@ -71,7 +71,7 @@ public class JSONDateConvertor implements JSON.Convertor } @Override - public Object fromJSON(Map map) + public Object fromJSON(Map map) { if (!_fromJSON) throw new UnsupportedOperationException(); diff --git a/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSONEnumConvertor.java b/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSONEnumConvertor.java index 3f50b6889cd..077e47a3c84 100644 --- a/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSONEnumConvertor.java +++ b/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSONEnumConvertor.java @@ -18,7 +18,6 @@ package org.eclipse.jetty.util.ajax; -import java.lang.reflect.Method; import java.util.Map; import org.eclipse.jetty.util.Loader; @@ -36,19 +35,6 @@ public class JSONEnumConvertor implements JSON.Convertor { private static final Logger LOG = Log.getLogger(JSONEnumConvertor.class); private boolean _fromJSON; - private Method _valueOf; - - { - try - { - Class e = Loader.loadClass("java.lang.Enum"); - _valueOf = e.getMethod("valueOf", Class.class, String.class); - } - catch (Exception e) - { - throw new RuntimeException("!Enums", e); - } - } public JSONEnumConvertor() { @@ -61,20 +47,21 @@ public class JSONEnumConvertor implements JSON.Convertor } @Override - public Object fromJSON(Map map) + public Object fromJSON(Map map) { if (!_fromJSON) throw new UnsupportedOperationException(); try { - Class c = Loader.loadClass((String)map.get("class")); - return _valueOf.invoke(null, c, map.get("value")); + @SuppressWarnings({"rawtypes", "unchecked"}) + Class type = Loader.loadClass((String)map.get("class")); + return Enum.valueOf(type, (String)map.get("value")); } catch (Exception e) { LOG.warn(e); + return null; } - return null; } @Override @@ -83,11 +70,11 @@ public class JSONEnumConvertor implements JSON.Convertor if (_fromJSON) { out.addClass(obj.getClass()); - out.add("value", ((Enum)obj).name()); + out.add("value", ((Enum)obj).name()); } else { - out.add(((Enum)obj).name()); + out.add(((Enum)obj).name()); } } } diff --git a/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSONObjectConvertor.java b/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSONObjectConvertor.java index 6250e3fe08b..f393dfdf954 100644 --- a/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSONObjectConvertor.java +++ b/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSONObjectConvertor.java @@ -20,8 +20,6 @@ package org.eclipse.jetty.util.ajax; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.Arrays; -import java.util.HashSet; import java.util.Locale; import java.util.Map; import java.util.Set; @@ -29,36 +27,35 @@ import java.util.Set; import org.eclipse.jetty.util.ajax.JSON.Output; /** - * Convert an Object to JSON using reflection on getters methods. + * Converts an Object to JSON using reflection on getters methods. */ public class JSONObjectConvertor implements JSON.Convertor { - private boolean _fromJSON; - private Set _excluded = null; + private final boolean _fromJSON; + private final Set _excluded; public JSONObjectConvertor() { - _fromJSON = false; + this(false); } public JSONObjectConvertor(boolean fromJSON) { - _fromJSON = fromJSON; + this(fromJSON, null); } /** * @param fromJSON true to convert from JSON - * @param excluded An array of field names to exclude from the conversion + * @param excludedFieldNames An array of field names to exclude from the conversion */ - public JSONObjectConvertor(boolean fromJSON, String[] excluded) + public JSONObjectConvertor(boolean fromJSON, String[] excludedFieldNames) { _fromJSON = fromJSON; - if (excluded != null) - _excluded = new HashSet(Arrays.asList(excluded)); + _excluded = excludedFieldNames == null ? Set.of() : Set.of(excludedFieldNames); } @Override - public Object fromJSON(Map map) + public Object fromJSON(Map map) { if (_fromJSON) throw new UnsupportedOperationException(); @@ -70,16 +67,13 @@ public class JSONObjectConvertor implements JSON.Convertor { try { - Class c = obj.getClass(); + Class c = obj.getClass(); if (_fromJSON) - out.addClass(obj.getClass()); + out.addClass(c); - Method[] methods = obj.getClass().getMethods(); - - for (int i = 0; i < methods.length; i++) + for (Method m : c.getMethods()) { - Method m = methods[i]; if (!Modifier.isStatic(m.getModifiers()) && m.getParameterCount() == 0 && m.getReturnType() != null && @@ -92,7 +86,6 @@ public class JSONObjectConvertor implements JSON.Convertor name = name.substring(3, 4).toLowerCase(Locale.ENGLISH) + name.substring(4); else continue; - if (includeField(name, obj, m)) out.add(name, m.invoke(obj, (Object[])null)); } @@ -106,6 +99,6 @@ public class JSONObjectConvertor implements JSON.Convertor protected boolean includeField(String name, Object o, Method m) { - return _excluded == null || !_excluded.contains(name); + return !_excluded.contains(name); } } diff --git a/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSONPojoConvertor.java b/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSONPojoConvertor.java index b3d72500fae..9e342c5e3de 100644 --- a/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSONPojoConvertor.java +++ b/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSONPojoConvertor.java @@ -19,13 +19,11 @@ package org.eclipse.jetty.util.ajax; import java.lang.reflect.Array; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.Locale; import java.util.Map; import java.util.Set; @@ -35,18 +33,37 @@ import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; /** - * Converts POJOs to JSON and vice versa. - * The key difference: - * - returns the actual object from Convertor.fromJSON (JSONObjectConverter returns a Map) - * - the getters/setters are resolved at initialization (JSONObjectConverter resolves it at runtime) - * - correctly sets the number fields + *

Converts POJOs to JSON and vice versa.

+ *

The key differences with respect to {@link JSONObjectConvertor} are:

+ *
    + *
  • returns the actual object from Convertor.fromJSON (JSONObjectConverter returns a Map)
  • + *
  • the getters/setters are resolved at initialization (JSONObjectConverter resolves it at runtime)
  • + *
  • correctly sets the number fields
  • + *
*/ public class JSONPojoConvertor implements JSON.Convertor { private static final Logger LOG = Log.getLogger(JSONPojoConvertor.class); - public static final Object[] GETTER_ARG = new Object[]{}; - public static final Object[] NULL_ARG = new Object[]{null}; private static final Map, NumberType> __numberTypes = new HashMap<>(); + private static final NumberType SHORT = Number::shortValue; + private static final NumberType INTEGER = Number::intValue; + private static final NumberType FLOAT = Number::floatValue; + private static final NumberType LONG = Number::longValue; + private static final NumberType DOUBLE = Number::doubleValue; + + static + { + __numberTypes.put(Short.class, SHORT); + __numberTypes.put(Short.TYPE, SHORT); + __numberTypes.put(Integer.class, INTEGER); + __numberTypes.put(Integer.TYPE, INTEGER); + __numberTypes.put(Long.class, LONG); + __numberTypes.put(Long.TYPE, LONG); + __numberTypes.put(Float.class, FLOAT); + __numberTypes.put(Float.TYPE, FLOAT); + __numberTypes.put(Double.class, DOUBLE); + __numberTypes.put(Double.TYPE, DOUBLE); + } public static NumberType getNumberType(Class clazz) { @@ -55,8 +72,8 @@ public class JSONPojoConvertor implements JSON.Convertor protected boolean _fromJSON; protected Class _pojoClass; - protected Map _getters = new HashMap(); - protected Map _setters = new HashMap(); + protected Map _getters = new HashMap<>(); + protected Map _setters = new HashMap<>(); protected Set _excluded; /** @@ -64,7 +81,16 @@ public class JSONPojoConvertor implements JSON.Convertor */ public JSONPojoConvertor(Class pojoClass) { - this(pojoClass, (Set)null, true); + this(pojoClass, null, true); + } + + /** + * @param pojoClass The class to convert + * @param fromJSON If true, add a class field to the JSON + */ + public JSONPojoConvertor(Class pojoClass, boolean fromJSON) + { + this(pojoClass, null, fromJSON); } /** @@ -73,7 +99,7 @@ public class JSONPojoConvertor implements JSON.Convertor */ public JSONPojoConvertor(Class pojoClass, String[] excluded) { - this(pojoClass, new HashSet(Arrays.asList(excluded)), true); + this(pojoClass, new HashSet<>(Arrays.asList(excluded))); } /** @@ -98,21 +124,11 @@ public class JSONPojoConvertor implements JSON.Convertor init(); } - /** - * @param pojoClass The class to convert - * @param fromJSON If true, add a class field to the JSON - */ - public JSONPojoConvertor(Class pojoClass, boolean fromJSON) - { - this(pojoClass, (Set)null, fromJSON); - } - protected void init() { Method[] methods = _pojoClass.getMethods(); - for (int i = 0; i < methods.length; i++) + for (Method m : methods) { - Method m = methods[i]; if (!Modifier.isStatic(m.getModifiers()) && m.getDeclaringClass() != Object.class) { String name = m.getName(); @@ -167,53 +183,45 @@ public class JSONPojoConvertor implements JSON.Convertor return _excluded == null || !_excluded.contains(name); } - protected int getExcludedCount() - { - return _excluded == null ? 0 : _excluded.size(); - } - @Override - public Object fromJSON(Map object) + public Object fromJSON(Map object) { - Object obj = null; try { - obj = _pojoClass.getDeclaredConstructor().newInstance(); + Object obj = _pojoClass.getConstructor().newInstance(); + setProps(obj, object); + return obj; } catch (Exception e) { // TODO return Map instead? throw new RuntimeException(e); } - - setProps(obj, object); - return obj; } - public int setProps(Object obj, Map props) + private void setProps(Object obj, Map props) { - int count = 0; - for (Iterator iterator = props.entrySet().iterator(); iterator.hasNext(); ) + for (Map.Entry entry : props.entrySet()) { - Map.Entry entry = (Map.Entry)iterator.next(); - Setter setter = getSetter((String)entry.getKey()); + Setter setter = getSetter(entry.getKey()); if (setter != null) { try { setter.invoke(obj, entry.getValue()); - count++; } catch (Exception e) { // TODO throw exception? - LOG.warn(_pojoClass.getName() + "#" + setter.getPropertyName() + " not set from " + - (entry.getValue().getClass().getName()) + "=" + entry.getValue().toString()); - log(e); + LOG.warn("{}#{} not set from value {}={}: {}", + _pojoClass.getName(), + setter.getPropertyName(), + setter.getType().getName(), + entry.getValue(), + e.toString()); } } } - return count; } @Override @@ -225,23 +233,19 @@ public class JSONPojoConvertor implements JSON.Convertor { try { - out.add(entry.getKey(), entry.getValue().invoke(obj, GETTER_ARG)); + out.add(entry.getKey(), entry.getValue().invoke(obj)); } catch (Exception e) { // TODO throw exception? - LOG.warn("{} property '{}' excluded. (errors)", _pojoClass.getName(), - entry.getKey()); - log(e); + LOG.warn("{}#{} excluded: {}", + _pojoClass.getName(), + entry.getKey(), + e.toString()); } } } - protected void log(Throwable t) - { - LOG.ignore(t); - } - public static class Setter { protected String _propertyName; @@ -255,11 +259,11 @@ public class JSONPojoConvertor implements JSON.Convertor _propertyName = propertyName; _setter = method; _type = method.getParameterTypes()[0]; - _numberType = __numberTypes.get(_type); + _numberType = JSONPojoConvertor.getNumberType(_type); if (_numberType == null && _type.isArray()) { _componentType = _type.getComponentType(); - _numberType = __numberTypes.get(_componentType); + _numberType = JSONPojoConvertor.getNumberType(_componentType); } } @@ -290,79 +294,84 @@ public class JSONPojoConvertor implements JSON.Convertor public boolean isPropertyNumber() { - return _numberType != null; + return getNumberType() != null; } - public void invoke(Object obj, Object value) throws IllegalArgumentException, - IllegalAccessException, InvocationTargetException + public void invoke(Object obj, Object value) throws Exception { if (value == null) - _setter.invoke(obj, NULL_ARG); + _setter.invoke(obj, value); else invokeObject(obj, value); } - protected void invokeObject(Object obj, Object value) throws IllegalArgumentException, - IllegalAccessException, InvocationTargetException + protected void invokeObject(Object obj, Object value) throws Exception { - if (_type.isEnum()) { if (value instanceof Enum) - _setter.invoke(obj, new Object[]{value}); + { + _setter.invoke(obj, value); + } else - _setter.invoke(obj, new Object[]{Enum.valueOf((Class)_type, value.toString())}); + { + @SuppressWarnings({"rawtypes", "unchecked"}) + Class enumType = (Class)_type; + @SuppressWarnings("unchecked") + Enum enumValue = Enum.valueOf(enumType, value.toString()); + _setter.invoke(obj, enumValue); + } } - else if (_numberType != null && value instanceof Number) + else if (isPropertyNumber() && value instanceof Number) { - _setter.invoke(obj, new Object[]{_numberType.getActualValue((Number)value)}); + _setter.invoke(obj, _numberType.getActualValue((Number)value)); } else if (Character.TYPE.equals(_type) || Character.class.equals(_type)) { - _setter.invoke(obj, new Object[]{String.valueOf(value).charAt(0)}); + _setter.invoke(obj, String.valueOf(value).charAt(0)); } else if (_componentType != null && value.getClass().isArray()) { if (_numberType == null) { int len = Array.getLength(value); - Object array = Array.newInstance(_componentType, len); + Object array = Array.newInstance(getComponentType(), len); try { System.arraycopy(value, 0, array, 0, len); + _setter.invoke(obj, array); } catch (Exception e) { - // unusual array with multiple types + // Unusual array with multiple types. LOG.ignore(e); - _setter.invoke(obj, new Object[]{value}); - return; + _setter.invoke(obj, value); } - _setter.invoke(obj, new Object[]{array}); } else { Object[] old = (Object[])value; - Object array = Array.newInstance(_componentType, old.length); + Object array = Array.newInstance(getComponentType(), old.length); try { for (int i = 0; i < old.length; i++) { Array.set(array, i, _numberType.getActualValue((Number)old[i])); } + _setter.invoke(obj, array); } catch (Exception e) { // unusual array with multiple types LOG.ignore(e); - _setter.invoke(obj, new Object[]{value}); - return; + _setter.invoke(obj, value); } - _setter.invoke(obj, new Object[]{array}); } } else - _setter.invoke(obj, new Object[]{value}); + { + _setter.invoke(obj, value); + } } } @@ -370,63 +379,4 @@ public class JSONPojoConvertor implements JSON.Convertor { public Object getActualValue(Number number); } - - public static final NumberType SHORT = new NumberType() - { - @Override - public Object getActualValue(Number number) - { - return number.shortValue(); - } - }; - - public static final NumberType INTEGER = new NumberType() - { - @Override - public Object getActualValue(Number number) - { - return number.intValue(); - } - }; - - public static final NumberType FLOAT = new NumberType() - { - @Override - public Object getActualValue(Number number) - { - return number.floatValue(); - } - }; - - public static final NumberType LONG = new NumberType() - { - @Override - public Object getActualValue(Number number) - { - return number instanceof Long ? number : (Long)number.longValue(); - } - }; - - public static final NumberType DOUBLE = new NumberType() - { - @Override - public Object getActualValue(Number number) - { - return number instanceof Double ? number : (Double)number.doubleValue(); - } - }; - - static - { - __numberTypes.put(Short.class, SHORT); - __numberTypes.put(Short.TYPE, SHORT); - __numberTypes.put(Integer.class, INTEGER); - __numberTypes.put(Integer.TYPE, INTEGER); - __numberTypes.put(Long.class, LONG); - __numberTypes.put(Long.TYPE, LONG); - __numberTypes.put(Float.class, FLOAT); - __numberTypes.put(Float.TYPE, FLOAT); - __numberTypes.put(Double.class, DOUBLE); - __numberTypes.put(Double.TYPE, DOUBLE); - } } diff --git a/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSONPojoConvertorFactory.java b/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSONPojoConvertorFactory.java index 4844b94e313..164658755f1 100644 --- a/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSONPojoConvertorFactory.java +++ b/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSONPojoConvertorFactory.java @@ -31,12 +31,7 @@ public class JSONPojoConvertorFactory implements JSON.Convertor public JSONPojoConvertorFactory(JSON json) { - if (json == null) - { - throw new IllegalArgumentException(); - } - _json = json; - _fromJson = true; + this(json, true); } /** @@ -48,9 +43,7 @@ public class JSONPojoConvertorFactory implements JSON.Convertor public JSONPojoConvertorFactory(JSON json, boolean fromJSON) { if (json == null) - { throw new IllegalArgumentException(); - } _json = json; _fromJson = fromJSON; } @@ -58,31 +51,20 @@ public class JSONPojoConvertorFactory implements JSON.Convertor @Override public void toJSON(Object obj, Output out) { - String clsName = obj.getClass().getName(); + Class cls = obj.getClass(); + String clsName = cls.getName(); Convertor convertor = _json.getConvertorFor(clsName); if (convertor == null) { - try - { - Class cls = Loader.loadClass(clsName); - convertor = new JSONPojoConvertor(cls, _fromJson); - _json.addConvertorFor(clsName, convertor); - } - catch (ClassNotFoundException e) - { - JSON.LOG.warn(e); - } - } - if (convertor != null) - { - convertor.toJSON(obj, out); + convertor = new JSONPojoConvertor(cls, _fromJson); + _json.addConvertorFor(clsName, convertor); } + convertor.toJSON(obj, out); } @Override - public Object fromJSON(Map object) + public Object fromJSON(Map map) { - Map map = object; String clsName = (String)map.get("class"); if (clsName != null) { @@ -91,7 +73,7 @@ public class JSONPojoConvertorFactory implements JSON.Convertor { try { - Class cls = Loader.loadClass(clsName); + Class cls = Loader.loadClass(clsName); convertor = new JSONPojoConvertor(cls, _fromJson); _json.addConvertorFor(clsName, convertor); } @@ -101,9 +83,7 @@ public class JSONPojoConvertorFactory implements JSON.Convertor } } if (convertor != null) - { - return convertor.fromJSON(object); - } + return convertor.fromJSON(map); } return map; } diff --git a/jetty-util-ajax/src/test/java/org/eclipse/jetty/util/ajax/Bar.java b/jetty-util-ajax/src/test/java/org/eclipse/jetty/util/ajax/Bar.java new file mode 100644 index 00000000000..e9e41cda34d --- /dev/null +++ b/jetty-util-ajax/src/test/java/org/eclipse/jetty/util/ajax/Bar.java @@ -0,0 +1,121 @@ +// +// ======================================================================== +// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under +// the terms of the Eclipse Public License 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0 +// +// This Source Code may also be made available under the following +// Secondary Licenses when the conditions for such availability set +// forth in the Eclipse Public License, v. 2.0 are satisfied: +// the Apache License v2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0 +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + +package org.eclipse.jetty.util.ajax; + +public class Bar +{ + private String _title; + private String _nullTest; + private Baz _baz; + private boolean _boolean1; + private Baz[] _bazs; + private Color _color; + + public Bar() + { + // Required by the POJO convertor. + } + + public Bar(String title, boolean boolean1, Baz baz) + { + this(title, boolean1, baz, null); + } + + public Bar(String title, boolean boolean1, Baz baz, Baz[] bazs) + { + setTitle(title); + setBoolean1(boolean1); + setBaz(baz); + setBazs(bazs); + } + + // Getters and setters required by the POJO convertor. + + public void setTitle(String title) + { + _title = title; + } + + public String getTitle() + { + return _title; + } + + public void setNullTest(String nullTest) + { + assert (nullTest == null); + _nullTest = nullTest; + } + + public String getNullTest() + { + return _nullTest; + } + + public void setBaz(Baz baz) + { + _baz = baz; + } + + public Baz getBaz() + { + return _baz; + } + + public void setBoolean1(boolean boolean1) + { + _boolean1 = boolean1; + } + + public boolean isBoolean1() + { + return _boolean1; + } + + public void setBazs(Baz[] bazs) + { + _bazs = bazs; + } + + public Baz[] getBazs() + { + return _bazs; + } + + public Color getColor() + { + return _color; + } + + public void setColor(Color color) + { + _color = color; + } + + @Override + public String toString() + { + return "\n=== " + getClass().getSimpleName() + " ===" + + "\ntitle: " + getTitle() + + "\nboolean1: " + isBoolean1() + + "\nnullTest: " + getNullTest() + + "\nbaz: " + getBaz() + + "\ncolor: " + getColor(); + } +} diff --git a/jetty-util-ajax/src/test/java/org/eclipse/jetty/util/ajax/Baz.java b/jetty-util-ajax/src/test/java/org/eclipse/jetty/util/ajax/Baz.java new file mode 100644 index 00000000000..9691c91b25c --- /dev/null +++ b/jetty-util-ajax/src/test/java/org/eclipse/jetty/util/ajax/Baz.java @@ -0,0 +1,79 @@ +// +// ======================================================================== +// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under +// the terms of the Eclipse Public License 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0 +// +// This Source Code may also be made available under the following +// Secondary Licenses when the conditions for such availability set +// forth in the Eclipse Public License, v. 2.0 are satisfied: +// the Apache License v2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0 +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + +package org.eclipse.jetty.util.ajax; + +public class Baz +{ + private String _message; + private Foo _foo; + private Boolean _boolean2; + + public Baz() + { + // Required by the POJO convertor. + } + + public Baz(String message, Boolean boolean2, Foo foo) + { + setMessage(message); + setBoolean2(boolean2); + setFoo(foo); + } + + // Getters and setters required by the POJO convertor. + + public void setMessage(String message) + { + _message = message; + } + + public String getMessage() + { + return _message; + } + + public void setFoo(Foo foo) + { + _foo = foo; + } + + public Foo getFoo() + { + return _foo; + } + + public void setBoolean2(Boolean boolean2) + { + _boolean2 = boolean2; + } + + public Boolean isBoolean2() + { + return _boolean2; + } + + @Override + public String toString() + { + return "\n=== " + getClass().getSimpleName() + " ===" + + "\nmessage: " + getMessage() + + "\nboolean2: " + isBoolean2() + + "\nfoo: " + getFoo(); + } +} diff --git a/jetty-util-ajax/src/test/java/org/eclipse/jetty/util/ajax/Color.java b/jetty-util-ajax/src/test/java/org/eclipse/jetty/util/ajax/Color.java new file mode 100644 index 00000000000..fce452b1b06 --- /dev/null +++ b/jetty-util-ajax/src/test/java/org/eclipse/jetty/util/ajax/Color.java @@ -0,0 +1,24 @@ +// +// ======================================================================== +// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under +// the terms of the Eclipse Public License 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0 +// +// This Source Code may also be made available under the following +// Secondary Licenses when the conditions for such availability set +// forth in the Eclipse Public License, v. 2.0 are satisfied: +// the Apache License v2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0 +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + +package org.eclipse.jetty.util.ajax; + +public enum Color +{ + Green, Blue +} diff --git a/jetty-util-ajax/src/test/java/org/eclipse/jetty/util/ajax/Foo.java b/jetty-util-ajax/src/test/java/org/eclipse/jetty/util/ajax/Foo.java new file mode 100644 index 00000000000..872e6d9ae80 --- /dev/null +++ b/jetty-util-ajax/src/test/java/org/eclipse/jetty/util/ajax/Foo.java @@ -0,0 +1,164 @@ +// +// ======================================================================== +// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under +// the terms of the Eclipse Public License 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0 +// +// This Source Code may also be made available under the following +// Secondary Licenses when the conditions for such availability set +// forth in the Eclipse Public License, v. 2.0 are satisfied: +// the Apache License v2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0 +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + +package org.eclipse.jetty.util.ajax; + +public class Foo +{ + private String _name; + private int _int1; + private Integer _int2; + private long _long1; + private Long _long2; + private float _float1; + private Float _float2; + private double _double1; + private Double _double2; + + public Foo() + { + // Required by the POJO convertor. + } + + // Getters and setters required by the POJO convertor. + + public String getName() + { + return _name; + } + + public void setName(String name) + { + _name = name; + } + + public int getInt1() + { + return _int1; + } + + public void setInt1(int int1) + { + _int1 = int1; + } + + public Integer getInt2() + { + return _int2; + } + + public void setInt2(Integer int2) + { + _int2 = int2; + } + + public long getLong1() + { + return _long1; + } + + public void setLong1(long long1) + { + _long1 = long1; + } + + public Long getLong2() + { + return _long2; + } + + public void setLong2(Long long2) + { + _long2 = long2; + } + + public float getFloat1() + { + return _float1; + } + + public void setFloat1(float float1) + { + _float1 = float1; + } + + public Float getFloat2() + { + return _float2; + } + + public void setFloat2(Float float2) + { + _float2 = float2; + } + + public double getDouble1() + { + return _double1; + } + + public void setDouble1(double double1) + { + _double1 = double1; + } + + public Double getDouble2() + { + return _double2; + } + + public void setDouble2(Double double2) + { + _double2 = double2; + } + + @Override + public boolean equals(Object another) + { + if (another instanceof Foo) + { + Foo foo = (Foo)another; + return _name.equals(foo.getName()) && + _int1 == foo.getInt1() && + _int2.equals(foo.getInt2()) && + _long1 == foo.getLong1() && + _long2.equals(foo.getLong2()) && + _float1 == foo.getFloat1() && + _float2.equals(foo.getFloat2()) && + _double1 == foo.getDouble1() && + _double2.equals(foo.getDouble2()); + } + + return false; + } + + @Override + public String toString() + { + return "\n=== " + getClass().getSimpleName() + " ===" + + "\nname: " + _name + + "\nint1: " + _int1 + + "\nint2: " + _int2 + + "\nlong1: " + _long1 + + "\nlong2: " + _long2 + + "\nfloat1: " + _float1 + + "\nfloat2: " + _float2 + + "\ndouble1: " + _double1 + + "\ndouble2: " + _double2; + } +} diff --git a/jetty-util-ajax/src/test/java/org/eclipse/jetty/util/ajax/JSONCollectionConvertorTest.java b/jetty-util-ajax/src/test/java/org/eclipse/jetty/util/ajax/JSONCollectionConvertorTest.java index 02661a0b733..156724f73f9 100644 --- a/jetty-util-ajax/src/test/java/org/eclipse/jetty/util/ajax/JSONCollectionConvertorTest.java +++ b/jetty-util-ajax/src/test/java/org/eclipse/jetty/util/ajax/JSONCollectionConvertorTest.java @@ -39,35 +39,35 @@ import static org.junit.jupiter.api.Assertions.assertSame; public class JSONCollectionConvertorTest { @Test - public void testArrayList() throws Exception + public void testArrayList() { - List list = new ArrayList(); + List list = new ArrayList<>(); Collections.addAll(list, "one", "two"); testList(list); } @Test - public void testLinkedList() throws Exception + public void testLinkedList() { - List list = new LinkedList(); + List list = new LinkedList<>(); Collections.addAll(list, "one", "two"); testList(list); } @Test - public void testCopyOnWriteArrayList() throws Exception + public void testCopyOnWriteArrayList() { - List list = new CopyOnWriteArrayList(); + List list = new CopyOnWriteArrayList<>(); Collections.addAll(list, "one", "two"); testList(list); } - private void testList(List list1) throws Exception + private void testList(List list1) { JSON json = new JSON(); json.addConvertor(List.class, new JSONCollectionConvertor()); - Map object1 = new HashMap(); + Map object1 = new HashMap<>(); String field = "field"; object1.put(field, list1); @@ -75,7 +75,7 @@ public class JSONCollectionConvertorTest assertThat(string, containsString(list1.getClass().getName())); @SuppressWarnings("unchecked") - Map object2 = (Map)json.parse(new JSON.StringSource(string)); + Map object2 = (Map)json.fromJSON(string); @SuppressWarnings("unchecked") List list2 = (List)object2.get(field); @@ -84,17 +84,17 @@ public class JSONCollectionConvertorTest } @Test - public void testHashSet() throws Exception + public void testHashSet() { - Set set = new HashSet(); + Set set = new HashSet<>(); Collections.addAll(set, "one", "two", "three"); testSet(set); } @Test - public void testTreeSet() throws Exception + public void testTreeSet() { - Set set = new TreeSet(); + Set set = new TreeSet<>(); Collections.addAll(set, "one", "two", "three"); testSet(set); } @@ -108,7 +108,7 @@ public class JSONCollectionConvertorTest assertThat(string, containsString(set1.getClass().getName())); @SuppressWarnings("unchecked") - Set set2 = (Set)json.parse(new JSON.StringSource(string)); + Set set2 = (Set)json.fromJSON(string); assertSame(set1.getClass(), set2.getClass()); assertEquals(set1, set2); diff --git a/jetty-util-ajax/src/test/java/org/eclipse/jetty/util/ajax/JSONPojoConvertorFactoryTest.java b/jetty-util-ajax/src/test/java/org/eclipse/jetty/util/ajax/JSONPojoConvertorFactoryTest.java index 7a1aa82e55d..8ff376774da 100644 --- a/jetty-util-ajax/src/test/java/org/eclipse/jetty/util/ajax/JSONPojoConvertorFactoryTest.java +++ b/jetty-util-ajax/src/test/java/org/eclipse/jetty/util/ajax/JSONPojoConvertorFactoryTest.java @@ -24,6 +24,8 @@ import java.util.concurrent.TimeUnit; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; /** @@ -43,15 +45,15 @@ public class JSONPojoConvertorFactoryTest jsonIn.addConvertor(Enum.class, new JSONEnumConvertor()); Foo foo = new Foo(); - foo._name = "Foo @ " + TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); - foo._int1 = 1; - foo._int2 = 2; - foo._long1 = 1000001L; - foo._long2 = 1000002L; - foo._float1 = 10.11f; - foo._float2 = 10.22f; - foo._double1 = 10000.11111d; - foo._double2 = 10000.22222d; + foo.setName("Foo @ " + TimeUnit.NANOSECONDS.toMillis(System.nanoTime())); + foo.setInt1(1); + foo.setInt2(2); + foo.setLong1(1000001L); + foo.setLong2(1000002L); + foo.setFloat1(10.11f); + foo.setFloat2(10.22f); + foo.setDouble1(10000.11111d); + foo.setDouble2(10000.22222d); Bar bar = new Bar("Hello", true, new Baz("World", Boolean.FALSE, foo), new Baz[]{ new Baz("baz0", Boolean.TRUE, null), new Baz("baz1", Boolean.FALSE, null) @@ -59,19 +61,16 @@ public class JSONPojoConvertorFactoryTest bar.setColor(Color.Green); String s = jsonOut.toJSON(bar); - - Object obj = jsonIn.parse(new JSON.StringSource(s)); + Object obj = jsonIn.fromJSON(s); assertTrue(obj instanceof Bar); Bar br = (Bar)obj; - Baz bz = br.getBaz(); - Foo f = bz.getFoo(); assertEquals(f, foo); - assertTrue(br.getBazs().length == 2); + assertEquals(2, br.getBazs().length); assertEquals(br.getBazs()[0].getMessage(), "baz0"); assertEquals(br.getBazs()[1].getMessage(), "baz1"); assertEquals(Color.Green, br.getColor()); @@ -89,15 +88,15 @@ public class JSONPojoConvertorFactoryTest jsonIn.addConvertor(Enum.class, new JSONEnumConvertor()); Foo foo = new Foo(); - foo._name = "Foo @ " + TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); - foo._int1 = 1; - foo._int2 = 2; - foo._long1 = 1000001L; - foo._long2 = 1000002L; - foo._float1 = 10.11f; - foo._float2 = 10.22f; - foo._double1 = 10000.11111d; - foo._double2 = 10000.22222d; + foo.setName("Foo @ " + TimeUnit.NANOSECONDS.toMillis(System.nanoTime())); + foo.setInt1(1); + foo.setInt2(2); + foo.setLong1(1000001L); + foo.setLong2(1000002L); + foo.setFloat1(10.11f); + foo.setFloat2(10.22f); + foo.setDouble1(10000.11111d); + foo.setDouble2(10000.22222d); Bar bar = new Bar("Hello", true, new Baz("World", Boolean.FALSE, foo), new Baz[]{ new Baz("baz0", Boolean.TRUE, null), new Baz("baz1", Boolean.FALSE, null) @@ -106,331 +105,28 @@ public class JSONPojoConvertorFactoryTest String s = jsonOut.toJSON(bar); - assertTrue(s.indexOf("class") < 0); + assertFalse(s.contains("class")); Object obj = jsonIn.parse(new JSON.StringSource(s)); assertTrue(obj instanceof Map); + @SuppressWarnings("unchecked") Map br = (Map)obj; - + @SuppressWarnings("unchecked") Map bz = (Map)br.get("baz"); - + @SuppressWarnings("unchecked") Map f = (Map)bz.get("foo"); - assertTrue(f != null); + + assertNotNull(f); Object[] bazs = (Object[])br.get("bazs"); - assertTrue(bazs.length == 2); - assertEquals(((Map)bazs[0]).get("message"), "baz0"); - assertEquals(((Map)bazs[1]).get("message"), "baz1"); + assertEquals(2, bazs.length); + @SuppressWarnings("unchecked") + Map map1 = (Map)bazs[0]; + assertEquals(map1.get("message"), "baz0"); + @SuppressWarnings("unchecked") + Map map2 = (Map)bazs[1]; + assertEquals(map2.get("message"), "baz1"); assertEquals("Green", br.get("color")); } - - enum Color - { - Red, Green, Blue - } - - ; - - public static class Bar - { - private String _title; - private String _nullTest; - private Baz _baz; - private boolean _boolean1; - private Baz[] _bazs; - private Color _color; - - public Bar() - { - - } - - public Bar(String title, boolean boolean1, Baz baz) - { - setTitle(title); - setBoolean1(boolean1); - setBaz(baz); - } - - public Bar(String title, boolean boolean1, Baz baz, Baz[] bazs) - { - this(title, boolean1, baz); - setBazs(bazs); - } - - @Override - public String toString() - { - return new StringBuffer().append("\n=== ").append(getClass().getSimpleName()).append(" ===") - .append("\ntitle: ").append(getTitle()) - .append("\nboolean1: ").append(isBoolean1()) - .append("\nnullTest: ").append(getNullTest()) - .append("\nbaz: ").append(getBaz()) - .append("\ncolor: ").append(_color).toString(); - } - - public void setTitle(String title) - { - _title = title; - } - - public String getTitle() - { - return _title; - } - - public void setNullTest(String nullTest) - { - assert (nullTest == null); - _nullTest = nullTest; - } - - public String getNullTest() - { - return _nullTest; - } - - public void setBaz(Baz baz) - { - _baz = baz; - } - - public Baz getBaz() - { - return _baz; - } - - public void setBoolean1(boolean boolean1) - { - _boolean1 = boolean1; - } - - public boolean isBoolean1() - { - return _boolean1; - } - - public void setBazs(Baz[] bazs) - { - _bazs = bazs; - } - - public Baz[] getBazs() - { - return _bazs; - } - - public Color getColor() - { - return _color; - } - - public void setColor(Color color) - { - _color = color; - } - } - - public static class Baz - { - private String _message; - private Foo _foo; - private Boolean _boolean2; - - public Baz() - { - - } - - public Baz(String message, Boolean boolean2, Foo foo) - { - setMessage(message); - setBoolean2(boolean2); - setFoo(foo); - } - - @Override - public String toString() - { - return new StringBuffer().append("\n=== ").append(getClass().getSimpleName()).append(" ===") - .append("\nmessage: ").append(getMessage()) - .append("\nboolean2: ").append(isBoolean2()) - .append("\nfoo: ").append(getFoo()).toString(); - } - - public void setMessage(String message) - { - _message = message; - } - - public String getMessage() - { - return _message; - } - - public void setFoo(Foo foo) - { - _foo = foo; - } - - public Foo getFoo() - { - return _foo; - } - - public void setBoolean2(Boolean boolean2) - { - _boolean2 = boolean2; - } - - public Boolean isBoolean2() - { - return _boolean2; - } - } - - public static class Foo - { - private String _name; - private int _int1; - private Integer _int2; - private long _long1; - private Long _long2; - private float _float1; - private Float _float2; - private double _double1; - private Double _double2; - - public Foo() - { - - } - - @Override - public String toString() - { - return new StringBuffer().append("\n=== ").append(getClass().getSimpleName()).append(" ===") - .append("\nname: ").append(_name) - .append("\nint1: ").append(_int1) - .append("\nint2: ").append(_int2) - .append("\nlong1: ").append(_long1) - .append("\nlong2: ").append(_long2) - .append("\nfloat1: ").append(_float1) - .append("\nfloat2: ").append(_float2) - .append("\ndouble1: ").append(_double1) - .append("\ndouble2: ").append(_double2) - .toString(); - } - - @Override - public boolean equals(Object another) - { - if (another instanceof Foo) - { - Foo foo = (Foo)another; - return getName().equals(foo.getName()) && - getInt1() == foo.getInt1() && - getInt2().equals(foo.getInt2()) && - getLong1() == foo.getLong1() && - getLong2().equals(foo.getLong2()) && - getFloat1() == foo.getFloat1() && - getFloat2().equals(foo.getFloat2()) && - getDouble1() == foo.getDouble1() && - getDouble2().equals(foo.getDouble2()); - } - - return false; - } - - public String getName() - { - return _name; - } - - public void setName(String name) - { - _name = name; - } - - public int getInt1() - { - return _int1; - } - - public void setInt1(int int1) - { - _int1 = int1; - } - - public Integer getInt2() - { - return _int2; - } - - public void setInt2(Integer int2) - { - _int2 = int2; - } - - public long getLong1() - { - return _long1; - } - - public void setLong1(long long1) - { - _long1 = long1; - } - - public Long getLong2() - { - return _long2; - } - - public void setLong2(Long long2) - { - _long2 = long2; - } - - public float getFloat1() - { - return _float1; - } - - public void setFloat1(float float1) - { - _float1 = float1; - } - - public Float getFloat2() - { - return _float2; - } - - public void setFloat2(Float float2) - { - _float2 = float2; - } - - public double getDouble1() - { - return _double1; - } - - public void setDouble1(double double1) - { - _double1 = double1; - } - - public Double getDouble2() - { - return _double2; - } - - public void setDouble2(Double double2) - { - _double2 = double2; - } - } } diff --git a/jetty-util-ajax/src/test/java/org/eclipse/jetty/util/ajax/JSONPojoConvertorTest.java b/jetty-util-ajax/src/test/java/org/eclipse/jetty/util/ajax/JSONPojoConvertorTest.java index bf388a1192e..8dd3e8abd21 100644 --- a/jetty-util-ajax/src/test/java/org/eclipse/jetty/util/ajax/JSONPojoConvertorTest.java +++ b/jetty-util-ajax/src/test/java/org/eclipse/jetty/util/ajax/JSONPojoConvertorTest.java @@ -23,7 +23,7 @@ import java.util.concurrent.TimeUnit; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -39,20 +39,17 @@ public class JSONPojoConvertorTest json.addConvertor(Foo.class, new JSONPojoConvertor(Foo.class)); json.addConvertor(Bar.class, new JSONPojoConvertor(Bar.class)); json.addConvertor(Baz.class, new JSONPojoConvertor(Baz.class)); - // json.addConvertor(Enum.class, new JSONEnumConvertor(true)); Foo foo = new Foo(); - foo._name = "Foo @ " + TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); - foo._int1 = 1; - foo._int2 = 2; - foo._long1 = 1000001L; - foo._long2 = 1000002L; - foo._float1 = 10.11f; - foo._float2 = 10.22f; - foo._double1 = 10000.11111d; - foo._double2 = 10000.22222d; - foo._char1 = 'a'; - foo._char2 = 'b'; + foo.setName("Foo @ " + TimeUnit.NANOSECONDS.toMillis(System.nanoTime())); + foo.setInt1(1); + foo.setInt2(2); + foo.setLong1(1000001L); + foo.setLong2(1000002L); + foo.setFloat1(10.11f); + foo.setFloat2(10.22f); + foo.setDouble1(10000.11111d); + foo.setDouble2(10000.22222d); Bar bar = new Bar("Hello", true, new Baz("World", Boolean.FALSE, foo), new Baz[]{ new Baz("baz0", Boolean.TRUE, null), new Baz("baz1", Boolean.FALSE, null) @@ -60,19 +57,16 @@ public class JSONPojoConvertorTest bar.setColor(Color.Green); String s = json.toJSON(bar); - Object obj = json.parse(new JSON.StringSource(s)); assertTrue(obj instanceof Bar); Bar br = (Bar)obj; - Baz bz = br.getBaz(); - Foo f = bz.getFoo(); assertEquals(foo, f); - assertTrue(br.getBazs().length == 2); + assertEquals(2, br.getBazs().length); assertEquals(br.getBazs()[0].getMessage(), "baz0"); assertEquals(br.getBazs()[1].getMessage(), "baz1"); assertEquals(Color.Green, br.getColor()); @@ -82,28 +76,22 @@ public class JSONPojoConvertorTest public void testExclude() { JSON json = new JSON(); - json.addConvertor(Foo.class, new JSONPojoConvertor(Foo.class, - new String[]{"name", "long1", "int2"})); - json.addConvertor(Bar.class, new JSONPojoConvertor(Bar.class, - new String[]{"title", "boolean1"})); - json.addConvertor(Baz.class, new JSONPojoConvertor(Baz.class, - new String[]{"boolean2"})); + json.addConvertor(Foo.class, new JSONPojoConvertor(Foo.class, new String[]{"name", "long1", "int2"})); + json.addConvertor(Bar.class, new JSONPojoConvertor(Bar.class, new String[]{"title", "boolean1"})); + json.addConvertor(Baz.class, new JSONPojoConvertor(Baz.class, new String[]{"boolean2"})); Foo foo = new Foo(); - foo._name = "Foo @ " + TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); - foo._int1 = 1; - foo._int2 = 2; - foo._long1 = 1000001L; - foo._long2 = 1000002L; - foo._float1 = 10.11f; - foo._float2 = 10.22f; - foo._double1 = 10000.11111d; - foo._double2 = 10000.22222d; - foo._char1 = 'a'; - foo._char2 = 'b'; + foo.setName("Foo @ " + TimeUnit.NANOSECONDS.toMillis(System.nanoTime())); + foo.setInt1(1); + foo.setInt2(2); + foo.setLong1(1000001L); + foo.setLong2(1000002L); + foo.setFloat1(10.11f); + foo.setFloat2(10.22f); + foo.setDouble1(10000.11111d); + foo.setDouble2(10000.22222d); Bar bar = new Bar("Hello", true, new Baz("World", Boolean.FALSE, foo)); - // bar.setColor(Color.Blue); String s = json.toJSON(bar); Object obj = json.parse(new JSON.StringSource(s)); @@ -115,350 +103,14 @@ public class JSONPojoConvertorTest Foo f = bz.getFoo(); assertNull(br.getTitle()); - assertFalse(bar.getTitle().equals(br.getTitle())); - assertFalse(br.isBoolean1() == bar.isBoolean1()); + assertNotEquals(bar.getTitle(), br.getTitle()); + assertNotEquals(br.isBoolean1(), bar.isBoolean1()); assertNull(bz.isBoolean2()); - assertFalse(bar.getBaz().isBoolean2().equals(bz.isBoolean2())); - assertFalse(f.getLong1() == foo.getLong1()); + assertNotEquals(bar.getBaz().isBoolean2(), bz.isBoolean2()); + assertNotEquals(f.getLong1(), foo.getLong1()); assertNull(f.getInt2()); - assertFalse(foo.getInt2().equals(f.getInt2())); + assertNotEquals(foo.getInt2(), f.getInt2()); assertNull(f.getName()); - assertEquals(null, br.getColor()); - } - - enum Color - { - Red, Green, Blue - } - - ; - - public static class Bar - { - private String _title; - private String _nullTest; - private Baz _baz; - private boolean _boolean1; - private Baz[] _bazs; - private Color _color; - - public Bar() - { - - } - - public Bar(String title, boolean boolean1, Baz baz) - { - setTitle(title); - setBoolean1(boolean1); - setBaz(baz); - } - - public Bar(String title, boolean boolean1, Baz baz, Baz[] bazs) - { - this(title, boolean1, baz); - setBazs(bazs); - } - - @Override - public String toString() - { - return new StringBuffer() - .append("\n=== ").append(getClass().getSimpleName()).append(" ===") - .append("\ntitle: ").append(getTitle()) - .append("\nboolean1: ").append(isBoolean1()) - .append("\nnullTest: ").append(getNullTest()) - .append("\nbaz: ").append(getBaz()) - .append("\ncolor: ").append(_color).toString(); - } - - public void setTitle(String title) - { - _title = title; - } - - public String getTitle() - { - return _title; - } - - public void setNullTest(String nullTest) - { - assert (nullTest == null); - _nullTest = nullTest; - } - - public String getNullTest() - { - return _nullTest; - } - - public void setBaz(Baz baz) - { - _baz = baz; - } - - public Baz getBaz() - { - return _baz; - } - - public void setBoolean1(boolean boolean1) - { - _boolean1 = boolean1; - } - - public boolean isBoolean1() - { - return _boolean1; - } - - public void setBazs(Baz[] bazs) - { - _bazs = bazs; - } - - public Baz[] getBazs() - { - return _bazs; - } - - public Color getColor() - { - return _color; - } - - public void setColor(Color color) - { - _color = color; - } - } - - public static class Baz - { - private String _message; - private Foo _foo; - private Boolean _boolean2; - - public Baz() - { - - } - - public Baz(String message, Boolean boolean2, Foo foo) - { - setMessage(message); - setBoolean2(boolean2); - setFoo(foo); - } - - @Override - public String toString() - { - return new StringBuffer().append("\n=== ").append(getClass().getSimpleName()).append(" ===") - .append("\nmessage: ").append(getMessage()) - .append("\nboolean2: ").append(isBoolean2()) - .append("\nfoo: ").append(getFoo()).toString(); - } - - public void setMessage(String message) - { - _message = message; - } - - public String getMessage() - { - return _message; - } - - public void setFoo(Foo foo) - { - _foo = foo; - } - - public Foo getFoo() - { - return _foo; - } - - public void setBoolean2(Boolean boolean2) - { - _boolean2 = boolean2; - } - - public Boolean isBoolean2() - { - return _boolean2; - } - } - - public static class Foo - { - private String _name; - private int _int1; - private Integer _int2; - private long _long1; - private Long _long2; - private float _float1; - private Float _float2; - private double _double1; - private Double _double2; - private char _char1; - private Character _char2; - - public Foo() - { - - } - - @Override - public String toString() - { - return new StringBuffer().append("\n=== ").append(getClass().getSimpleName()).append(" ===") - .append("\nname: ").append(_name) - .append("\nint1: ").append(_int1) - .append("\nint2: ").append(_int2) - .append("\nlong1: ").append(_long1) - .append("\nlong2: ").append(_long2) - .append("\nfloat1: ").append(_float1) - .append("\nfloat2: ").append(_float2) - .append("\ndouble1: ").append(_double1) - .append("\ndouble2: ").append(_double2) - .append("\nchar1: ").append(_char1) - .append("\nchar2: ").append(_char2) - .toString(); - } - - @Override - public boolean equals(Object another) - { - if (another instanceof Foo) - { - Foo foo = (Foo)another; - return getName().equals(foo.getName()) && - getInt1() == foo.getInt1() && - getInt2().equals(foo.getInt2()) && - getLong1() == foo.getLong1() && - getLong2().equals(foo.getLong2()) && - getFloat1() == foo.getFloat1() && - getFloat2().equals(foo.getFloat2()) && - getDouble1() == foo.getDouble1() && - getDouble2().equals(foo.getDouble2()) && - getChar1() == foo.getChar1() && - getChar2().equals(foo.getChar2()); - } - - return false; - } - - public String getName() - { - return _name; - } - - public void setName(String name) - { - _name = name; - } - - public int getInt1() - { - return _int1; - } - - public void setInt1(int int1) - { - _int1 = int1; - } - - public Integer getInt2() - { - return _int2; - } - - public void setInt2(Integer int2) - { - _int2 = int2; - } - - public long getLong1() - { - return _long1; - } - - public void setLong1(long long1) - { - _long1 = long1; - } - - public Long getLong2() - { - return _long2; - } - - public void setLong2(Long long2) - { - _long2 = long2; - } - - public float getFloat1() - { - return _float1; - } - - public void setFloat1(float float1) - { - _float1 = float1; - } - - public Float getFloat2() - { - return _float2; - } - - public void setFloat2(Float float2) - { - _float2 = float2; - } - - public double getDouble1() - { - return _double1; - } - - public void setDouble1(double double1) - { - _double1 = double1; - } - - public Double getDouble2() - { - return _double2; - } - - public void setDouble2(Double double2) - { - _double2 = double2; - } - - public char getChar1() - { - return _char1; - } - - public void setChar1(char char1) - { - _char1 = char1; - } - - public Character getChar2() - { - return _char2; - } - - public void setChar2(Character char2) - { - _char2 = char2; - } + assertNull(br.getColor()); } } diff --git a/jetty-util-ajax/src/test/java/org/eclipse/jetty/util/ajax/JSONTest.java b/jetty-util-ajax/src/test/java/org/eclipse/jetty/util/ajax/JSONTest.java index 5220aa93267..adfbecb7958 100644 --- a/jetty-util-ajax/src/test/java/org/eclipse/jetty/util/ajax/JSONTest.java +++ b/jetty-util-ajax/src/test/java/org/eclipse/jetty/util/ajax/JSONTest.java @@ -19,7 +19,6 @@ package org.eclipse.jetty.util.ajax; import java.io.IOException; -import java.io.StringReader; import java.lang.reflect.Array; import java.math.BigDecimal; import java.util.Date; @@ -38,11 +37,14 @@ import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.startsWith; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; public class JSONTest { - String test = "\n\n\n\t\t " + + private JSON json; + private String test = "\n\n\n\t\t " + "// ignore this ,a [ \" \n" + "/* and this \n" + "/* and * // this \n" + @@ -62,17 +64,16 @@ public class JSONTest @BeforeEach public void resetJSON() { - // Reset JSON configuration to default with each testcase - JSON.reset(); + json = new JSON(); } @Test public void testToString() { - JSON.registerConvertor(Gadget.class, new JSONObjectConvertor(false)); - HashMap map = new HashMap(); - HashMap obj6 = new HashMap(); - HashMap obj7 = new HashMap(); + json.addConvertor(Gadget.class, new JSONObjectConvertor(false)); + Map map = new HashMap<>(); + Map obj6 = new HashMap<>(); + Map obj7 = new HashMap<>(); Woggle w0 = new Woggle(); Woggle w1 = new Woggle(); @@ -97,26 +98,27 @@ public class JSONTest obj7.put("x", "value"); - String s = JSON.toString(map); - assertTrue(s.indexOf("\"n1\":null") >= 0); - assertTrue(s.indexOf("\"n2\":2") >= 0); - assertTrue(s.indexOf("\"n3\":-3.0E-11") >= 0); - assertTrue(s.indexOf("\"n4\":\"4\\n") >= 0); - assertTrue(s.indexOf("\"n5\":[\"a\",\"b\",") >= 0); - assertTrue(s.indexOf("\"n6\":{}") >= 0); - assertTrue(s.indexOf("\"n7\":{\"x\":\"value\"}") >= 0); - assertTrue(s.indexOf("\"n8\":[1,2,3,4]") >= 0); - assertTrue(s.indexOf("\"n9\":[{}, [], {}]") >= 0); - assertTrue(s.indexOf("\"w0\":{\"class\":\"org.eclipse.jetty.util.ajax.JSONTest$Woggle\",\"name\":\"woggle0\",\"nested\":{\"class\":\"org.eclipse.jetty.util.ajax.JSONTest$Woggle\",\"name\":\"woggle1\",\"nested\":null,\"number\":-101},\"number\":100}") >= 0); + String s = json.toJSON(map); + assertTrue(s.contains("\"n1\":null")); + assertTrue(s.contains("\"n2\":2")); + assertTrue(s.contains("\"n3\":-3.0E-11")); + assertTrue(s.contains("\"n4\":\"4\\n")); + assertTrue(s.contains("\"n5\":[\"a\",\"b\",")); + assertTrue(s.contains("\"n6\":{}")); + assertTrue(s.contains("\"n7\":{\"x\":\"value\"}")); + assertTrue(s.contains("\"n8\":[1,2,3,4]")); + assertTrue(s.contains("\"n9\":[{}, [], {}]")); + assertTrue(s.contains("\"w0\":{\"class\":\"org.eclipse.jetty.util.ajax.JSONTest$Woggle\",\"name\":\"woggle0\",\"nested\":{\"class\":\"org.eclipse.jetty.util.ajax.JSONTest$Woggle\",\"name\":\"woggle1\",\"nested\":null,\"number\":-101},\"number\":100}")); Gadget gadget = new Gadget(); + gadget.setModulated(true); gadget.setShields(42); gadget.setWoggles(new Woggle[]{w0, w1}); - s = JSON.toString(new Gadget[]{gadget}); + s = json.toJSON(new Gadget[]{gadget}); assertThat(s, startsWith("[")); - assertThat(s, containsString("\"modulated\":false")); - assertThat(s, containsString("\"shields\":42")); + assertThat(s, containsString("\"modulated\":" + gadget.isModulated())); + assertThat(s, containsString("\"shields\":" + gadget.getShields())); assertThat(s, containsString("\"name\":\"woggle0\"")); assertThat(s, containsString("\"name\":\"woggle1\"")); } @@ -124,7 +126,8 @@ public class JSONTest @Test public void testParse() { - Map map = (Map)JSON.parse(test); + @SuppressWarnings("unchecked") + Map map = (Map)json.fromJSON(test); assertEquals((long)100, map.get("onehundred")); assertEquals("fred", map.get("name")); assertEquals(-0.2, map.get("small")); @@ -133,12 +136,9 @@ public class JSONTest assertTrue(((Woggle)map.get("w0")).nested instanceof Woggle); assertEquals(-101, ((Woggle)((Woggle)map.get("w0")).nested).number); assertTrue(map.containsKey("NaN")); - assertEquals(null, map.get("NaN")); + assertNull(map.get("NaN")); assertTrue(map.containsKey("undefined")); - assertEquals(null, map.get("undefined")); - - test = "{\"data\":{\"source\":\"15831407eqdaawf7\",\"widgetId\":\"Magnet_8\"},\"channel\":\"/magnets/moveStart\",\"connectionId\":null,\"clientId\":\"15831407eqdaawf7\"}"; - map = (Map)JSON.parse(test); + assertNull(map.get("undefined")); } @Test @@ -146,7 +146,7 @@ public class JSONTest { Map map = new HashMap<>(); map.put("str", "line\nfeed"); - String jsonStr = JSON.toString(map); + String jsonStr = json.toJSON(map); assertThat(jsonStr, is("{\"str\":\"line\\nfeed\"}")); } @@ -155,7 +155,7 @@ public class JSONTest { Map map = new HashMap<>(); map.put("str", "tab\tchar"); - String jsonStr = JSON.toString(map); + String jsonStr = json.toJSON(map); assertThat(jsonStr, is("{\"str\":\"tab\\tchar\"}")); } @@ -164,7 +164,7 @@ public class JSONTest { Map map = new HashMap<>(); map.put("str", "ascii\u0007bel"); - String jsonStr = JSON.toString(map); + String jsonStr = json.toJSON(map); assertThat(jsonStr, is("{\"str\":\"ascii\\u0007bel\"}")); } @@ -173,7 +173,7 @@ public class JSONTest { Map map = new HashMap<>(); map.put("str", "japanese: 桟橋"); - String jsonStr = JSON.toString(map); + String jsonStr = json.toJSON(map); assertThat(jsonStr, is("{\"str\":\"japanese: 桟橋\"}")); } @@ -199,7 +199,8 @@ public class JSONTest public void testParse_Utf8_JsonEncoded() { String jsonStr = "{\"str\": \"japanese: \\u685f\\u6a4b\"}"; - Map map = (Map)JSON.parse(jsonStr); + @SuppressWarnings("unchecked") + Map map = (Map)json.fromJSON(jsonStr); assertThat(map.get("str"), is("japanese: 桟橋")); } @@ -207,7 +208,8 @@ public class JSONTest public void testParse_Utf8_JavaEncoded() { String jsonStr = "{\"str\": \"japanese: \u685f\u6a4b\"}"; - Map map = (Map)JSON.parse(jsonStr); + @SuppressWarnings("unchecked") + Map map = (Map)json.fromJSON(jsonStr); assertThat(map.get("str"), is("japanese: 桟橋")); } @@ -215,23 +217,22 @@ public class JSONTest public void testParse_Utf8_Raw() { String jsonStr = "{\"str\": \"japanese: 桟橋\"}"; - Map map = (Map)JSON.parse(jsonStr); + @SuppressWarnings("unchecked") + Map map = (Map)json.fromJSON(jsonStr); assertThat(map.get("str"), is("japanese: 桟橋")); } @Test - public void testParseReader() throws Exception + public void testParseReader() { - Map map = (Map)JSON.parse(new StringReader(test)); + @SuppressWarnings("unchecked") + Map map = (Map)json.fromJSON(test); assertEquals((long)100, map.get("onehundred")); assertEquals("fred", map.get("name")); assertTrue(map.get("array").getClass().isArray()); assertTrue(map.get("w0") instanceof Woggle); assertTrue(((Woggle)map.get("w0")).nested instanceof Woggle); - - test = "{\"data\":{\"source\":\"15831407eqdaawf7\",\"widgetId\":\"Magnet_8\"},\"channel\":\"/magnets/moveStart\",\"connectionId\":null,\"clientId\":\"15831407eqdaawf7\"}"; - map = (Map)JSON.parse(test); } @Test @@ -248,30 +249,31 @@ public class JSONTest "\"array\" : [\"a\",-1.0e2,[],null,true,false] ," + "} */"; - Object o = JSON.parse(test, false); - assertTrue(o == null); - o = JSON.parse(test, true); + Object o = json.fromJSON(test); + assertNull(o); + o = json.parse(new JSON.StringSource(test), true); assertTrue(o instanceof Map); - assertEquals("fred", ((Map)o).get("name")); + @SuppressWarnings("unchecked") + Map map = (Map)o; + assertEquals("fred", map.get("name")); } @Test public void testQuote() { String test = "\"abc123|\\\"|\\\\|\\/|\\b|\\f|\\n|\\r|\\t|\\uaaaa|\""; - - String result = (String)JSON.parse(test, false); + String result = (String)json.fromJSON(test); assertEquals("abc123|\"|\\|/|\b|\f|\n|\r|\t|\uaaaa|", result); } @Test public void testBigDecimal() { - Object obj = JSON.parse("1.0E7"); + Object obj = json.fromJSON("1.0E7"); assertTrue(obj instanceof Double); BigDecimal bd = BigDecimal.valueOf(10000000d); - String string = JSON.toString(new Object[]{bd}); - obj = Array.get(JSON.parse(string), 0); + String string = json.toJSON(new Object[]{bd}); + obj = Array.get(json.fromJSON(string), 0); assertTrue(obj instanceof Double); } @@ -279,7 +281,7 @@ public class JSONTest public void testZeroByte() { String withzero = "\u0000"; - JSON.toString(withzero); + assertEquals("\"\\u0000\"", json.toJSON(withzero)); } public static class Gadget @@ -288,6 +290,8 @@ public class JSONTest private long shields; private Woggle[] woggles; + // Getters and setters required by the POJO convertor. + /** * @return the modulated */ @@ -348,15 +352,15 @@ public class JSONTest Woggle w0 = new Woggle(); Gizmo g0 = new Gizmo(); - w0.name = "woggle0"; - w0.nested = g0; - w0.number = 100; - g0.name = "woggle1"; - g0.nested = null; - g0.number = -101; - g0.tested = true; + w0.setName("woggle0"); + w0.setNested(g0); + w0.setNumber(100); + g0.setName("woggle1"); + g0.setNested(null); + g0.setNumber(-101); + g0.setTested(true); - HashMap map = new HashMap(); + Map map = new HashMap<>(); Date dummyDate = new Date(1); map.put("date", dummyDate); map.put("w0", w0); @@ -365,29 +369,24 @@ public class JSONTest json.append(buf, map); String js = buf.toString(); - assertTrue(js.indexOf("\"date\":\"01/01/1970 00:00:00 GMT\"") >= 0); - assertTrue(js.indexOf("org.eclipse.jetty.util.ajax.JSONTest$Woggle") >= 0); - assertTrue(js.indexOf("org.eclipse.jetty.util.ajax.JSONTest$Gizmo") < 0); - assertTrue(js.indexOf("\"tested\":true") >= 0); + assertTrue(js.contains("\"date\":\"01/01/1970 00:00:00 GMT\"")); + assertTrue(js.contains("org.eclipse.jetty.util.ajax.JSONTest$Woggle")); + assertFalse(js.contains("org.eclipse.jetty.util.ajax.JSONTest$Gizmo")); + assertTrue(js.contains("\"tested\":true")); // test case#3 TimeZone tzone = TimeZone.getTimeZone("JST"); - String tzone3Letter = tzone.getDisplayName(false, TimeZone.SHORT); String format = "EEE MMMMM dd HH:mm:ss zzz yyyy"; Locale l = new Locale("ja", "JP"); - if (l != null) - { - json.addConvertor(Date.class, new JSONDateConvertor(format, tzone, false, l)); - buf = new StringBuffer(); - json.append(buf, map); - js = buf.toString(); - //assertTrue(js.indexOf("\"date\":\"\u6728 1\u6708 01 09:00:00 JST 1970\"")>=0); - assertTrue(js.indexOf(" 01 09:00:00 JST 1970\"") >= 0); - assertTrue(js.indexOf("org.eclipse.jetty.util.ajax.JSONTest$Woggle") >= 0); - assertTrue(js.indexOf("org.eclipse.jetty.util.ajax.JSONTest$Gizmo") < 0); - assertTrue(js.indexOf("\"tested\":true") >= 0); - } + json.addConvertor(Date.class, new JSONDateConvertor(format, tzone, false, l)); + buf = new StringBuffer(); + json.append(buf, map); + js = buf.toString(); + assertTrue(js.contains(" 01 09:00:00 JST 1970\"")); + assertTrue(js.contains("org.eclipse.jetty.util.ajax.JSONTest$Woggle")); + assertFalse(js.contains("org.eclipse.jetty.util.ajax.JSONTest$Gizmo")); + assertTrue(js.contains("\"tested\":true")); // test case#4 json.addConvertor(Date.class, new JSONDateConvertor(true)); @@ -395,23 +394,17 @@ public class JSONTest buf = new StringBuffer(); json.append(buf, map); js = buf.toString(); - assertTrue(js.indexOf("\"date\":\"Thu Jan 01 00:00:00 GMT 1970\"") < 0); - assertTrue(js.indexOf("org.eclipse.jetty.util.ajax.JSONTest$Woggle") >= 0); - assertTrue(js.indexOf("org.eclipse.jetty.util.ajax.JSONTest$Gizmo") < 0); + assertFalse(js.contains("\"date\":\"Thu Jan 01 00:00:00 GMT 1970\"")); + assertTrue(js.contains("org.eclipse.jetty.util.ajax.JSONTest$Woggle")); + assertFalse(js.contains("org.eclipse.jetty.util.ajax.JSONTest$Gizmo")); - map = (HashMap)json.parse(new JSON.StringSource(js)); + @SuppressWarnings("unchecked") + Map map1 = (Map)json.fromJSON(js); - assertTrue(map.get("date") instanceof Date); - assertTrue(map.get("w0") instanceof Woggle); + assertTrue(map1.get("date") instanceof Date); + assertTrue(map1.get("w0") instanceof Woggle); } - enum Color - { - Red, Green, Blue - } - - ; - @Test public void testEnumConvertor() { @@ -424,60 +417,66 @@ public class JSONTest Woggle w0 = new Woggle(); Gizmo g0 = new Gizmo(); - w0.name = "woggle0"; - w0.nested = g0; - w0.number = 100; - w0.other = Color.Blue; - g0.name = "woggle1"; - g0.nested = null; - g0.number = -101; - g0.tested = true; - g0.other = Color.Green; + w0.setName("woggle0"); + w0.setNested(g0); + w0.setNumber(100); + w0.setOther(Color.Blue); + g0.setName("woggle1"); + g0.setNested(null); + g0.setNumber(-101); + g0.setTested(true); + g0.setOther(Color.Green); - HashMap map = new HashMap(); + Map map = new HashMap<>(); map.put("date", new Date(1)); map.put("w0", w0); map.put("g0", g0); StringBuffer buf = new StringBuffer(); - json.append((Appendable)buf, map); + json.append(buf, map); String js = buf.toString(); - assertTrue(js.indexOf("\"date\":\"Thu Jan 01 00:00:00 GMT 1970\"") >= 0); - assertTrue(js.indexOf("org.eclipse.jetty.util.ajax.JSONTest$Woggle") >= 0); - assertTrue(js.indexOf("org.eclipse.jetty.util.ajax.JSONTest$Gizmo") < 0); - assertTrue(js.indexOf("\"tested\":true") >= 0); - assertTrue(js.indexOf("\"Green\"") >= 0); - assertTrue(js.indexOf("\"Blue\"") < 0); + assertTrue(js.contains("\"date\":\"Thu Jan 01 00:00:00 GMT 1970\"")); + assertTrue(js.contains("org.eclipse.jetty.util.ajax.JSONTest$Woggle")); + assertFalse(js.contains("org.eclipse.jetty.util.ajax.JSONTest$Gizmo")); + assertTrue(js.contains("\"tested\":true")); + assertTrue(js.contains("\"Green\"")); + assertFalse(js.contains("\"Blue\"")); json.addConvertor(Date.class, new JSONDateConvertor(DateCache.DEFAULT_FORMAT, TimeZone.getTimeZone("GMT"), true, l)); json.addConvertor(Enum.class, new JSONEnumConvertor(false)); w0.nested = null; buf = new StringBuffer(); - json.append((Appendable)buf, map); + json.append(buf, map); js = buf.toString(); - assertTrue(js.indexOf("\"date\":\"Thu Jan 01 00:00:00 GMT 1970\"") < 0); - assertTrue(js.indexOf("org.eclipse.jetty.util.ajax.JSONTest$Woggle") >= 0); - assertTrue(js.indexOf("org.eclipse.jetty.util.ajax.JSONTest$Gizmo") < 0); + assertFalse(js.contains("\"date\":\"Thu Jan 01 00:00:00 GMT 1970\"")); + assertTrue(js.contains("org.eclipse.jetty.util.ajax.JSONTest$Woggle")); + assertFalse(js.contains("org.eclipse.jetty.util.ajax.JSONTest$Gizmo")); - Map map2 = (HashMap)json.parse(new JSON.StringSource(js)); + @SuppressWarnings("unchecked") + Map map2 = (Map)json.fromJSON(js); assertTrue(map2.get("date") instanceof Date); assertTrue(map2.get("w0") instanceof Woggle); - assertEquals(null, ((Woggle)map2.get("w0")).getOther()); - assertEquals(Color.Green.toString(), ((Map)map2.get("g0")).get("other")); + assertNull(((Woggle)map2.get("w0")).other); + @SuppressWarnings("unchecked") + Map map3 = (Map)map2.get("g0"); + assertEquals(Color.Green.toString(), map3.get("other")); json.addConvertor(Date.class, new JSONDateConvertor(DateCache.DEFAULT_FORMAT, TimeZone.getTimeZone("GMT"), true, l)); json.addConvertor(Enum.class, new JSONEnumConvertor(true)); buf = new StringBuffer(); - json.append((Appendable)buf, map); + json.append(buf, map); js = buf.toString(); - map2 = (HashMap)json.parse(new JSON.StringSource(js)); + @SuppressWarnings("unchecked") + Map map4 = (Map)json.fromJSON(js); - assertTrue(map2.get("date") instanceof Date); - assertTrue(map2.get("w0") instanceof Woggle); - assertEquals(null, ((Woggle)map2.get("w0")).getOther()); - Object o = ((Map)map2.get("g0")).get("other"); + assertTrue(map4.get("date") instanceof Date); + assertTrue(map4.get("w0") instanceof Woggle); + assertNull(((Woggle)map4.get("w0")).other); + @SuppressWarnings("unchecked") + Map map5 = (Map)map4.get("g0"); + Object o = map5.get("other"); assertEquals(Color.Green, o); } @@ -489,41 +488,67 @@ public class JSONTest boolean tested; Object other; + // Getters and setters required by the POJO convertor. + public String getName() { return name; } + public void setName(String name) + { + this.name = name; + } + public Gizmo getNested() { return nested; } + public void setNested(Gizmo nested) + { + this.nested = nested; + } + public long getNumber() { return number; } + public void setNumber(long number) + { + this.number = number; + } + public boolean isTested() { return tested; } + public void setTested(boolean tested) + { + this.tested = tested; + } + public Object getOther() { return other; } + + public void setOther(Object other) + { + this.other = other; + } } public static class Woggle extends Gizmo implements JSON.Convertible { - public Woggle() { } @Override - public void fromJSON(Map object) + public void fromJSON(Map object) { name = (String)object.get("name"); nested = (Gizmo)object.get("nested");