diff --git a/api/src/main/java/javax/json/EmptyArray.java b/api/src/main/java/javax/json/EmptyArray.java new file mode 100644 index 0000000..03afdbe --- /dev/null +++ b/api/src/main/java/javax/json/EmptyArray.java @@ -0,0 +1,136 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://oss.oracle.com/licenses/CDDL+GPL-1.1 + * or LICENSE.txt. See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at LICENSE.txt. + * + * GPL Classpath Exception: + * Oracle designates this particular file as subject to the "Classpath" + * exception as provided by Oracle in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ +package javax.json; + +import java.io.Serializable; +import java.util.AbstractList; +import java.util.Collections; +import java.util.List; +import java.util.RandomAccess; + +/** + * Private implementation of immutable {@link JsonArray}. + * + * @author Lukas Jungmann + */ +final class EmptyArray extends AbstractList implements JsonArray, Serializable, RandomAccess { + + private static final long serialVersionUID = 7295439472061642859L; + + @Override + public JsonValue get(int index) { + throw new IndexOutOfBoundsException("Index: " + index); + } + + @Override + public int size() { + return 0; + } + + @Override + public JsonObject getJsonObject(int index) { + return (JsonObject) get(index); + } + + @Override + public JsonArray getJsonArray(int index) { + return (JsonArray) get(index); + } + + @Override + public JsonNumber getJsonNumber(int index) { + return (JsonNumber) get(index); + } + + @Override + public JsonString getJsonString(int index) { + return (JsonString) get(index); + } + + @Override + public List getValuesAs(Class clazz) { + return Collections.emptyList(); + } + + @Override + public String getString(int index) { + return getJsonString(index).getString(); + } + + @Override + public String getString(int index, String defaultValue) { + return defaultValue; + } + + @Override + public int getInt(int index) { + return getJsonNumber(index).intValue(); + } + + @Override + public int getInt(int index, int defaultValue) { + return defaultValue; + } + + @Override + public boolean getBoolean(int index) { + return get(index) == JsonValue.TRUE; + } + + @Override + public boolean getBoolean(int index, boolean defaultValue) { + return defaultValue; + } + + @Override + public boolean isNull(int index) { + return get(index) == JsonValue.NULL; + } + + @Override + public ValueType getValueType() { + return ValueType.ARRAY; + } + + // Preserves singleton property + private Object readResolve() { + return JsonValue.EMPTY_JSON_ARRAY; + } +} diff --git a/api/src/main/java/javax/json/EmptyObject.java b/api/src/main/java/javax/json/EmptyObject.java new file mode 100644 index 0000000..d7f4d02 --- /dev/null +++ b/api/src/main/java/javax/json/EmptyObject.java @@ -0,0 +1,126 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://oss.oracle.com/licenses/CDDL+GPL-1.1 + * or LICENSE.txt. See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at LICENSE.txt. + * + * GPL Classpath Exception: + * Oracle designates this particular file as subject to the "Classpath" + * exception as provided by Oracle in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ + +package javax.json; + +import java.io.Serializable; +import java.util.AbstractMap; +import java.util.Collections; +import java.util.Set; + +/** + * Private implementation of immutable {@link JsonObject}. + * + * @author Lukas Jungmann + */ +final class EmptyObject extends AbstractMap implements JsonObject, Serializable { + + private static final long serialVersionUID = -1461653546889072583L; + + @Override + public Set> entrySet() { + return Collections.>emptySet(); + } + + @Override + public JsonArray getJsonArray(String name) { + return (JsonArray) get(name); + } + + @Override + public JsonObject getJsonObject(String name) { + return (JsonObject) get(name); + } + + @Override + public JsonNumber getJsonNumber(String name) { + return (JsonNumber) get(name); + } + + @Override + public JsonString getJsonString(String name) { + return (JsonString) get(name); + } + + @Override + public String getString(String name) { + return getJsonString(name).getString(); + } + + @Override + public String getString(String name, String defaultValue) { + return defaultValue; + } + + @Override + public int getInt(String name) { + return getJsonNumber(name).intValue(); + } + + @Override + public int getInt(String name, int defaultValue) { + return defaultValue; + } + + @Override + public boolean getBoolean(String name) { + throw new NullPointerException(); + } + + @Override + public boolean getBoolean(String name, boolean defaultValue) { + return defaultValue; + } + + @Override + public boolean isNull(String name) { + throw new NullPointerException(); + } + + @Override + public ValueType getValueType() { + return ValueType.OBJECT; + } + + // Preserves singleton property + private Object readResolve() { + return JsonValue.EMPTY_JSON_OBJECT; + } +} diff --git a/api/src/main/java/javax/json/JsonArray.java b/api/src/main/java/javax/json/JsonArray.java index 90d6281..ae0fc2b 100644 --- a/api/src/main/java/javax/json/JsonArray.java +++ b/api/src/main/java/javax/json/JsonArray.java @@ -291,7 +291,7 @@ default List getValuesAs(Function func) { * * @param index index of the JSON null value * @return return true if the value at the specified location is - * {@code JsonValue.NUL}, otherwise false + * {@code JsonValue.NULL}, otherwise false * @throws IndexOutOfBoundsException if the index is out of range */ boolean isNull(int index); diff --git a/api/src/main/java/javax/json/JsonValue.java b/api/src/main/java/javax/json/JsonValue.java index 9b9a5e2..72d93da 100644 --- a/api/src/main/java/javax/json/JsonValue.java +++ b/api/src/main/java/javax/json/JsonValue.java @@ -43,11 +43,11 @@ /** * JsonValue represents an immutable JSON value. * - * + * *

A JSON value is one of the following: * an object ({@link JsonObject}), an array ({@link JsonArray}), * a number ({@link JsonNumber}), a string ({@link JsonString}), - * {@code true} ({@link JsonValue#TRUE JsonValue.TRUE}), {@code false} + * {@code true} ({@link JsonValue#TRUE JsonValue.TRUE}), {@code false} * ({@link JsonValue#FALSE JsonValue.FALSE}), * or {@code null} ({@link JsonValue#NULL JsonValue.NULL}). */ @@ -55,17 +55,17 @@ public interface JsonValue { /** * The empty JSON object. - * + * * @since 1.1 */ - static final JsonObject EMPTY_JSON_OBJECT = Json.createObjectBuilder().build(); + static final JsonObject EMPTY_JSON_OBJECT = new EmptyObject(); /** * The empty JSON array. - * + * * @since 1.1 */ - static final JsonArray EMPTY_JSON_ARRAY = Json.createArrayBuilder().build(); + static final JsonArray EMPTY_JSON_ARRAY = new EmptyArray(); /** * Indicates the type of a {@link JsonValue} object. diff --git a/tests/src/test/java/org/glassfish/json/tests/JsonValueTest.java b/tests/src/test/java/org/glassfish/json/tests/JsonValueTest.java index 09c2dab..1a22eac 100644 --- a/tests/src/test/java/org/glassfish/json/tests/JsonValueTest.java +++ b/tests/src/test/java/org/glassfish/json/tests/JsonValueTest.java @@ -37,7 +37,6 @@ * only if the new code is made subject to such option by the copyright * holder. */ - package org.glassfish.json.tests; import java.io.ByteArrayInputStream; @@ -45,6 +44,9 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.util.Collections; +import javax.json.JsonObject; +import javax.json.JsonString; import javax.json.JsonValue; import org.junit.Assert; import org.junit.Test; @@ -55,6 +57,99 @@ */ public class JsonValueTest { + @Test(expected = IndexOutOfBoundsException.class) + public void arrayGetJsonObjectIdx() { + JsonValue.EMPTY_JSON_ARRAY.getJsonObject(0); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void arrayGetJsonArrayIdx() { + JsonValue.EMPTY_JSON_ARRAY.getJsonArray(0); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void arrayGetJsonNumberIdx() { + JsonValue.EMPTY_JSON_ARRAY.getJsonNumber(0); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void arrayGetJsonStringIdx() { + JsonValue.EMPTY_JSON_ARRAY.getJsonString(0); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void arrayGetStringIdx() { + JsonValue.EMPTY_JSON_ARRAY.getString(0); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void arrayGetIntIdx() { + JsonValue.EMPTY_JSON_ARRAY.getInt(0); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void arrayGetBooleanIdx() { + JsonValue.EMPTY_JSON_ARRAY.getBoolean(0); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void arrayIsNull() { + JsonValue.EMPTY_JSON_ARRAY.isNull(0); + } + + @Test + public void arrayMethods() { + Assert.assertEquals(JsonValue.ValueType.ARRAY, JsonValue.EMPTY_JSON_ARRAY.getValueType()); + Assert.assertEquals(Collections.emptyList(), JsonValue.EMPTY_JSON_ARRAY.getValuesAs(JsonObject.class)); + Assert.assertEquals(Collections.emptyList(), JsonValue.EMPTY_JSON_ARRAY.getValuesAs(JsonString::getString)); + Assert.assertEquals(true, JsonValue.EMPTY_JSON_ARRAY.getBoolean(0, true)); + Assert.assertEquals(42, JsonValue.EMPTY_JSON_ARRAY.getInt(0, 42)); + Assert.assertEquals("Sasek", JsonValue.EMPTY_JSON_ARRAY.getString(0, "Sasek")); + } + + @Test(expected = UnsupportedOperationException.class) + public void arrayIsImmutable() { + JsonValue.EMPTY_JSON_ARRAY.add(JsonValue.EMPTY_JSON_OBJECT); + } + + @Test(expected = NullPointerException.class) + public void objectGetString() { + JsonValue.EMPTY_JSON_OBJECT.getString("normalni string"); + } + + @Test(expected = NullPointerException.class) + public void objectGetInt() { + JsonValue.EMPTY_JSON_OBJECT.getInt("hledej cislo"); + } + + @Test(expected = NullPointerException.class) + public void objectGetBoolean() { + JsonValue.EMPTY_JSON_OBJECT.getBoolean("booo"); + } + + @Test(expected = NullPointerException.class) + public void objectIsNull() { + JsonValue.EMPTY_JSON_OBJECT.isNull("???"); + } + + @Test + public void objectMethods() { + Assert.assertNull(JsonValue.EMPTY_JSON_OBJECT.getJsonArray("pole")); + Assert.assertNull(JsonValue.EMPTY_JSON_OBJECT.getJsonObject("objekt")); + Assert.assertNull(JsonValue.EMPTY_JSON_OBJECT.getJsonNumber("cislo")); + Assert.assertNull(JsonValue.EMPTY_JSON_OBJECT.getJsonString("divnej string")); + + Assert.assertEquals("ja jo", JsonValue.EMPTY_JSON_OBJECT.getString("nejsem tu", "ja jo")); + Assert.assertEquals(false, JsonValue.EMPTY_JSON_OBJECT.getBoolean("najdes mne", false)); + Assert.assertEquals(98, JsonValue.EMPTY_JSON_OBJECT.getInt("spatnej dotaz", 98)); + } + + + @Test(expected = UnsupportedOperationException.class) + public void objectImmutable() { + JsonValue.EMPTY_JSON_OBJECT.put("klauni", JsonValue.EMPTY_JSON_ARRAY); + } + @Test public void serialization() { byte[] data = serialize(JsonValue.TRUE); @@ -68,6 +163,14 @@ public void serialization() { data = serialize(JsonValue.NULL); value = deserialize(JsonValue.class, data); Assert.assertEquals(JsonValue.NULL, value); + + data = serialize(JsonValue.EMPTY_JSON_ARRAY); + value = deserialize(JsonValue.class, data); + Assert.assertEquals(JsonValue.EMPTY_JSON_ARRAY, value); + + data = serialize(JsonValue.EMPTY_JSON_OBJECT); + value = deserialize(JsonValue.class, data); + Assert.assertEquals(JsonValue.EMPTY_JSON_OBJECT, value); } private byte[] serialize(Object o) {