[JSONP-29] JsonPaser#getString() returns wrong value Created: 09/Jun/15  Updated: 23/Sep/16

Status: Open
Project: jsonp
Component/s: None
Affects Version/s: 1.0.4
Fix Version/s: None

Type: Bug Priority: Major
Reporter: jspiegel Assignee: kchung
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

JDK7



 Description   

The reference implementation fails to raise an error when the input JSON is invalid. Here is a reproducer:

JsonParser parser = Json.createParser(new StringReader("{\"a\":13"));
parser.next(); // START_OBJECT
parser.next(); // KEY_NAME
parser.next(); // VALUE_NUMBER
System.out.println(parser.getString()); // "13a":1



 Comments   
Comment by ren.zhijun.oracle [ 23/Sep/16 ]

I tested with 1.1.0-SNAPSHOT implementation, and the output is (is this your expected):

13,

not:

"13a":1

Comment by jspiegel [ 23/Sep/16 ]

I assume you mean the result is "13" and not "13,"?

13 would be acceptable as long as an additional call to parser.next() raises a parse error since the input is missing the final right curly bracket.





[JSONP-36] Put a space after the colon that separates key and value (JsonWriter#writeObject) Created: 22/Sep/16  Updated: 22/Sep/16

Status: Open
Project: jsonp
Component/s: None
Affects Version/s: 1.0.4
Fix Version/s: None

Type: Improvement Priority: Minor
Reporter: jpangamarca Assignee: kchung
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Java 1.8


Tags: pretty-print

 Description   

As a aesthetic improvement, it'd be nice to have a space after the colon that separates the key and value when writing a JSON object to a output stream (like when we want to write the JSON string to a file or a byteostream):

JsonWriterFactory writerFactory = Json.createWriterFactory(props);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
JsonWriter writer = writerFactory.createWriter(baos);
writer.writeObject(model);
writer.close();

The result is:

{ "firstName":"Duke", "lastName":"Java", "age":18 }

It'd be nice to have instead (like GSON does):

{ "firstName": "Duke", "lastName": "Java", "age": 18 }

It looks better and follows recommended typing rules for spacing after a colon (for instance, see http://www.grammarbook.com/punctuation/spacing.asp).

After taking a quick look to the src code, I guess the fix would be to add a line

writeChar(' ');

after writing colons in org.glassfish.json.JsonGeneratorImpl.

Thanks for yout attention.






[JSONP-35] Unnecessary use of BigDecimal in JsonNumberImpl$JsonLongNumber. Created: 29/Jun/16  Updated: 22/Aug/16

Status: Open
Project: jsonp
Component/s: None
Affects Version/s: 1.0.4
Fix Version/s: None

Type: Improvement Priority: Major
Reporter: martinandersson.com Assignee: ren.zhijun.oracle
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

JsonNumberImpl$JsonLongNumber does not override JsonNumberImp.intValueExact() with the effect that a BigDecimal object will be constructed. JsonLongNumber should override intValueExact() and use Math.toIntExact() instead of going the long way through a BigDecimal.






[JSONP-32] Doubt about writeEscapedString() Created: 08/May/16  Updated: 05/Jul/16

Status: Open
Project: jsonp
Component/s: None
Affects Version/s: 1.0.4
Fix Version/s: None

Type: Bug Priority: Major
Reporter: j4nbur53 Assignee: kchung
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

All



 Description   

There are some doubts about writeEscapedString(). This method
char c = s.charAt; but then at some place it compares c < 0x10FFFF.

But this test trivially always true since char data type is in the range
0x0000 to 0xFFFF. Is the intention of the code to use s.codePointAt()?



 Comments   
Comment by j4nbur53 [ 08/May/16 ]

Given that a Java String uses surrogate pairs for ranges above 0xFFFF, the code
somehow does what it should do, since the escaped codes 0x00-0x1F, 0x22 and 0x5c
are anyway in the lowest Unicode plane, not needing surrogate pairs.

Comment by Robin479 [ 04/Jul/16 ]

There is another subtle error near those lines: the character U+007F ("delete") and the character range U+0080 through U+009F ("C1 control codes") are control characters, which require escaping according to the JSON specification. The solution might be to escape JSON special characters U+0022 and U+005C (and optionally, U+002F), as well as characters for which java.lang.Character.isISOControl() is true.

Additionally, most JavaScript clients (erroneously) require the escaping of ALL line-terminating characters, which includes characters of the type java.lang.Character#LINE_SEPARATOR (currently only U+2028) and java.lang.Character#PARAGRAPH_SEPARATOR (currently only U+2029). Since JSON allows optional escaping of any character, the escaping of these problematic types of characters would be appreciated (see java.lang.Character.getType()).

Here's a replacement for writeEscapedString() which does all that:

    void writeEscapedString(String string) {
        writeChar('"');
        int b = 0, len = string.length(); // b =: start of to-be-written characters (buffer)
        for (int i = b; i < len; i++) {
            final char c = string.charAt(i);
            if (c == '"' || c == '\\' || c == '/') {
                writeString(string, b, i); b = i+1; // flush/reset buffer
                writeChar('\\'); writeChar(c); // escape JSON special character
            } else if (c < ' ' || '~' < c) { // (outside printable ASCII range)
                switch (Character.getType(c)) {
                    case Character.CONTROL:
                        final int idx = "\n\r\t\f\b".indexOf(c);
                        if (0 <= idx) {
                            writeString(string, b, i); b = i+1; // flush/reset buffer
                            writeChar('\\'); writeChar("nrtfb".charAt(idx)); // escape well-known controls
                            break; // from switch
                        } // else: fall through
                    case Character.LINE_SEPARATOR: // most JavaScript consumers require escaping...
                    case Character.PARAGRAPH_SEPARATOR:  // ...of ALL line-terminating characters
                        writeString(string, b, i); b = i+1; // flush/reset buffer
                        final String hex = Integer.toHexString(c);
                        writeString("\\u0000", 0, 6 - hex.length());
                        writeString(hex);
                }
            }
        }
        writeString(string, b, len); // flush buffer
        writeChar('"');
    }




[JSONP-34] JSONP don't include the license file Created: 28/Jun/16  Updated: 28/Jun/16

Status: Open
Project: jsonp
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Major
Reporter: puntogil Assignee: kchung
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

Hi
Not available LICENSE file in source directory structure
Please. Added license and copyright notice.
the fedora pakaging guideline is very strictly precise about this problem
https://fedoraproject.org/wiki/Packaging:LicensingGuidelines?rd=Packaging/LicensingGuidelines#License_Text

Seem the LICENSE file used in the Glassfish projects report the old address of GNU Free Software Foundation
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
can you correct with
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 ?
for Fedora is considered as a bug, see https://fedoraproject.org/wiki/Common_Rpmlint_issues#incorrect-fsf-address

Thanks in advance
Regards






[JSONP-33] JsonParser raises error when it should not Created: 15/Jun/16  Updated: 15/Jun/16

Status: Open
Project: jsonp
Component/s: None
Affects Version/s: 1.0.4
Fix Version/s: None

Type: Bug Priority: Major
Reporter: jspiegel Assignee: kchung
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

JsonParserFactory f = Json.createParserFactory(null);
JsonObject obj = Json.createObjectBuilder().add("a", BigDecimal.ONE).build();
JsonParser parser = f.createParser(obj);
System.out.println(parser.next());
System.out.println(parser.next());
System.out.println(parser.next());
System.out.println(parser.getString());

START_OBJECT
KEY_NAME
VALUE_NUMBER
Exception in thread "main" java.lang.IllegalStateException: JsonParser#getString() is valid only KEY_NAME, VALUE_STRING, VALUE_NUMBER parser states. But current parser state is VALUE_NUMBER






[JSONP-31] JsonObject.get and containsKey are O(n) Created: 29/Sep/15  Updated: 01/Oct/15  Resolved: 01/Oct/15

Status: Resolved
Project: jsonp
Component/s: None
Affects Version/s: 1.0.4
Fix Version/s: None

Type: Bug Priority: Minor
Reporter: bjkail Assignee: kchung
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

JsonObjectImpl does not override the get or containsKey methods, so AbstractMap implements these methods using entrySet, which means the operations are O even though the underlying valueMap is a LinkedHashMap. These methods should be overridden to improve performance for large objects.

Other methods could also be overridden to avoid the entrySet indirection (notably size but other methods could also be considered), but this is less significant.



 Comments   
Comment by kchung [ 01/Oct/15 ]

Thanks for reporting. Fix committed to master branch





[JSONP-30] Improve primitive number parsing Created: 27/Aug/15  Updated: 01/Sep/15  Resolved: 01/Sep/15

Status: Resolved
Project: jsonp
Component/s: None
Affects Version/s: 1.0.4
Fix Version/s: None

Type: Improvement Priority: Minor
Reporter: braghest Assignee: kchung
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

Primitive number parsing has a couple of low hanging fruits for performance improvements:

  1. JsonTokenizer#isDefinitelyInt returns true for negative numbers only if they have exactly 9 places. This results in a BigDecimal being created even if it has fewer places. However negative numbers with less than nine place are definitely int as well.
  2. There is no JsonTokenizer#isDefinitelyLong

The attached patch includes the following changes:

  1. change JsonTokenizer#isDefinitelyInt to return true as well for negative numbers with less than 9 places
  2. add JsonTokenizer#isDefinitelyLong for numbers with 18 or fewer places
  3. change JsonParserImpl to use #isDefinitelyLong
  4. add tests for various borderline cases around max values

Ideally we would like to have this merged to 1.0.x but we could not find a maintenance branch.



 Comments   
Comment by braghest [ 27/Aug/15 ]

Patch

Update:

  1. updated JsonTokenizer#getInt to match #isDefinitelyInt
  2. added JsonTokenizer#getLong similar to #getInt
diff --git a/impl/src/main/java/org/glassfish/json/JsonParserImpl.java b/impl/src/main/java/org/glassfish/json/JsonParserImpl.java
index 7172b8e..dad8681 100644
--- a/impl/src/main/java/org/glassfish/json/JsonParserImpl.java
+++ b/impl/src/main/java/org/glassfish/json/JsonParserImpl.java
@@ -116,6 +116,10 @@ public class JsonParserImpl implements JsonParser {
     boolean isDefinitelyInt() {
         return tokenizer.isDefinitelyInt();
     }
+    
+    boolean isDefinitelyLong() {
+    	return tokenizer.isDefinitelyLong();
+    }
 
     @Override
     public long getLong() {
@@ -123,7 +127,7 @@ public class JsonParserImpl implements JsonParser {
             throw new IllegalStateException(
                     JsonMessages.PARSER_GETLONG_ERR(currentEvent));
         }
-        return tokenizer.getBigDecimal().longValue();
+        return tokenizer.getLong();
     }
 
     @Override
@@ -166,6 +170,8 @@ public class JsonParserImpl implements JsonParser {
             case VALUE_NUMBER:
                 if (isDefinitelyInt()) {
                     return JsonNumberImpl.getJsonNumber(getInt());
+                } else if (isDefinitelyLong()) {
+                    return JsonNumberImpl.getJsonNumber(getLong());
                 }
                 return JsonNumberImpl.getJsonNumber(getBigDecimal());
             case VALUE_TRUE:
diff --git a/impl/src/main/java/org/glassfish/json/JsonTokenizer.java b/impl/src/main/java/org/glassfish/json/JsonTokenizer.java
index c6281ca..7bdf38d 100644
--- a/impl/src/main/java/org/glassfish/json/JsonTokenizer.java
+++ b/impl/src/main/java/org/glassfish/json/JsonTokenizer.java
@@ -544,7 +544,7 @@ final class JsonTokenizer implements Closeable {
     int getInt() {
         // no need to create BigDecimal for common integer values (1-9 digits)
         int storeLen = storeEnd-storeBegin;
-        if (!fracOrExp && (storeLen <= 9 || (minus && storeLen == 10))) {
+        if (!fracOrExp && (storeLen <= 9 || (minus && storeLen <= 10))) {
             int num = 0;
             int i = minus ? 1 : 0;
             for(; i < storeLen; i++) {
@@ -555,12 +555,34 @@ final class JsonTokenizer implements Closeable {
             return getBigDecimal().intValue();
         }
     }
+    
+    long getLong() {
+        // no need to create BigDecimal for common integer values (1-18 digits)
+        int storeLen = storeEnd-storeBegin;
+        if (!fracOrExp && (storeLen <= 18 || (minus && storeLen <= 19))) {
+            long num = 0;
+            int i = minus ? 1 : 0;
+            for(; i < storeLen; i++) {
+                num = num * 10 + (buf[storeBegin+i] - '0');
+            }
+            return minus ? -num : num;
+        } else {
+            return getBigDecimal().intValue();
+        }
+    }
 
     // returns true for common integer values (1-9 digits).
     // So there are cases it will return false even though the number is int
     boolean isDefinitelyInt() {
         int storeLen = storeEnd-storeBegin;
-        return !fracOrExp && (storeLen <= 9 || (minus && storeLen == 10));
+        return !fracOrExp && (storeLen <= 9 || (minus && storeLen <= 10));
+    }
+    
+    // returns true for common long values (1-18 digits).
+    // So there are cases it will return false even though the number is long
+    boolean isDefinitelyLong() {
+    	int storeLen = storeEnd-storeBegin;
+    	return !fracOrExp && (storeLen <= 18 || (minus && storeLen <= 19));
     }
 
     boolean isIntegral() {
diff --git a/tests/src/test/java/org/glassfish/json/tests/JsonReaderTest.java b/tests/src/test/java/org/glassfish/json/tests/JsonReaderTest.java
index c2bf2d9..92a989a 100644
--- a/tests/src/test/java/org/glassfish/json/tests/JsonReaderTest.java
+++ b/tests/src/test/java/org/glassfish/json/tests/JsonReaderTest.java
@@ -40,14 +40,26 @@
 
 package org.glassfish.json.tests;
 
-import junit.framework.TestCase;
-import org.glassfish.json.api.BufferPool;
-
-import javax.json.*;
-import java.io.*;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
+import java.math.BigDecimal;
+import java.math.BigInteger;
 import java.util.HashMap;
 import java.util.Map;
 
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonNumber;
+import javax.json.JsonObject;
+import javax.json.JsonReader;
+import javax.json.JsonReaderFactory;
+import javax.json.JsonValue;
+
+import org.glassfish.json.api.BufferPool;
+
+import junit.framework.TestCase;
+
 /**
  * @author Jitendra Kotamraju
  */
@@ -70,6 +82,48 @@ public class JsonReaderTest extends TestCase {
         assertEquals("\u0000\u00ff\u00ff", str);
     }
 
+    public void testPrimitiveIntNumbers() {
+        String[] borderlineCases = new String[]{
+                "214748364",
+                Integer.toString(Integer.MAX_VALUE),
+                Long.toString(Integer.MAX_VALUE + 1L),
+                "-214748364",
+                Integer.toString(Integer.MIN_VALUE),
+                Long.toString(Integer.MIN_VALUE - 1L)
+        };
+        for (String num : borderlineCases) {
+            JsonReader reader = Json.createReader(new StringReader("["+num+"]"));
+            try {
+                JsonArray array = reader.readArray();
+                JsonNumber value = (JsonNumber) array.get(0);
+                assertEquals("Fails for num="+num, new BigInteger(num).longValue(), value.longValue());
+            } finally {
+                reader.close();
+            }
+        }
+    }
+    
+    public void testPrimitiveLongNumbers() {
+        String[] borderlineCases = new String[]{
+                "922337203685477580",
+                Long.toString(Long.MAX_VALUE),
+                new BigInteger(Long.toString(Long.MAX_VALUE)).add(BigInteger.ONE).toString(),
+                "-922337203685477580",
+                Long.toString(Long.MIN_VALUE),
+                new BigInteger(Long.toString(Long.MIN_VALUE)).subtract(BigInteger.ONE).toString()
+        };
+        for (String num : borderlineCases) {
+            JsonReader reader = Json.createReader(new StringReader("["+num+"]"));
+            try {
+                JsonArray array = reader.readArray();
+                JsonNumber value = (JsonNumber) array.get(0);
+                assertEquals("Fails for num="+num, new BigInteger(num), value.bigIntegerValueExact());
+            } finally {
+                reader.close();
+            }
+        }
+    }
+
     public void testUnknownFeature() throws Exception {
         Map<String, Object> config = new HashMap<>();
         config.put("foo", true);

Comment by kchung [ 01/Sep/15 ]

Patch applied to the mater branch. Thanks for the patch.





[JSONP-28] Dead link(s) on project page Created: 11/Mar/15  Updated: 11/Mar/15

Status: Open
Project: jsonp
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Major
Reporter: keilw Assignee: kchung
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: links

 Description   

At least the "Documentation" link on https://jsonp.java.net/ is dead/no longer working. Should be fixed, at least pointing to an empty or new page.






[JSONP-27] Using OSGi cannot load the service Created: 19/Sep/14  Updated: 19/Sep/14

Status: Open
Project: jsonp
Component/s: None
Affects Version/s: 1.0.4
Fix Version/s: None

Type: Bug Priority: Major
Reporter: bakos.gabor Assignee: kchung
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

OSGi (4.x)



 Description   

I was trying to use the jsonp project as a default implementation for the json-api in an OSGi environment (eclipse 3.7), although the ServiceLoader is not quite OSGi-friendly solution, so no services found for JsonProvider#provider() and because the JsonProvider from the javax.json-api (1.0) was also loaded if I use that JsonProvider from that bundle (that is loaded first, so most probably this happens) it cannot find the default implementation either.
As a workaround we had to use a different (from the javax.json-api bundle, the one of org.glassfish.javax.json) ContextClassLoader for the thread calling the JsonProvider#provider() method and add a service reference to the jsonp bundle (so it can find that service with the provided classloader).
Ideally the would be to make loading the services load in OSGi environments (that would be the goal of the spi-fly project, but unfortunately that is not an option for us yet, it requires OSGi R5 or above, be we have to support eclipse 3.7 for a while), though for us, currently the exposed service would be sufficient with the workaround.
Could you add a service reference to the default implementation or give other satisfying solution that make this plugin work in OSGi R4 environments?






[JSONP-26] JsonProvider should not create a new ServiceLoader for each provider() invocation Created: 22/Jun/14  Updated: 26/Jun/14  Resolved: 23/Jun/14

Status: Resolved
Project: jsonp
Component/s: None
Affects Version/s: 1.0.4
Fix Version/s: None

Type: Bug Priority: Major
Reporter: stIncMale Assignee: kchung
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Oracle Java SE Runtime Environment (build 1.8.0-b132)



 Description   

Affected versions (it's strange, but javax.json.spi.JsonProvider is located both in javax.json:javax.json-api and org.glassfish:javax.json):
javax.json:javax.json-api:1.0 and org.glassfish:javax.json:1.0.4

JsonProvider.provide() is called from Json.createObjectBuilder() and does the following:

public static JsonProvider provider() {
	ServiceLoader<JsonProvider> loader = ServiceLoader.load(JsonProvider.class);
	Iterator<JsonProvider> it = loader.iterator();
	...
}

As you can see it creates a new instance of ServiceLoader (via load(Class) method) each time the method provide() is invoked. Because of this cache of providers maintained by ServiceLoader is not used and loader.iterator() performs heavy search again and again...

The trace looks like

	at java.util.zip.ZipFile.getEntry(Native Method)
	at java.util.zip.ZipFile.getEntry(ZipFile.java:311)
	- locked <0x00000000f801b3b8> (a java.util.jar.JarFile)
	at java.util.jar.JarFile.getEntry(JarFile.java:240)
	at java.util.jar.JarFile.getJarEntry(JarFile.java:223)
	at sun.misc.URLClassPath$JarLoader.getResource(URLClassPath.java:841)
	at sun.misc.URLClassPath$JarLoader.findResource(URLClassPath.java:819)
	at sun.misc.URLClassPath$1.next(URLClassPath.java:226)
	at sun.misc.URLClassPath$1.hasMoreElements(URLClassPath.java:236)
	at java.net.URLClassLoader$3$1.run(URLClassLoader.java:589)
	at java.net.URLClassLoader$3$1.run(URLClassLoader.java:587)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader$3.next(URLClassLoader.java:586)
	at java.net.URLClassLoader$3.hasMoreElements(URLClassLoader.java:611)
	at sun.misc.CompoundEnumeration.next(CompoundEnumeration.java:45)
	at sun.misc.CompoundEnumeration.hasMoreElements(CompoundEnumeration.java:54)
	at java.util.ServiceLoader$LazyIterator.hasNextService(ServiceLoader.java:354)
	at java.util.ServiceLoader$LazyIterator.hasNext(ServiceLoader.java:393)
	at java.util.ServiceLoader$1.hasNext(ServiceLoader.java:474)
	at javax.json.spi.JsonProvider.provider(JsonProvider.java:89)
	at javax.json.Json.createObjectBuilder(Json.java:266)

In order to solve this performance problem one should create instance of ServiceLoader only once and reuse it in the JsonProvider.provide() method.



 Comments   
Comment by kchung [ 23/Jun/14 ]

Thanks for reporting. Fixed in the next branch

--- a/api/src/main/java/javax/json/spi/JsonProvider.java
+++ b/api/src/main/java/javax/json/spi/JsonProvider.java
@@ -71,6 +71,7 @@ public abstract class JsonProvider {
      */
     private static final String DEFAULT_PROVIDER
             = "org.glassfish.json.JsonProviderImpl";
+    private static ServiceLoader<JsonProvider> loader = ServiceLoader.load(JsonProvider.class);
 
     protected JsonProvider() {
     }
@@ -85,7 +86,6 @@ public abstract class JsonProvider {
      * @return a JSON provider
      */
     public static JsonProvider provider() {
-        ServiceLoader<JsonProvider> loader = ServiceLoader.load(JsonProvider.class);
         Iterator<JsonProvider> it = loader.iterator();
         if (it.hasNext()) {
             return it.next();
Comment by stIncMale [ 24/Jun/14 ]

No no no You can't just use static ServiceLoader<JsonProvider> loader field because ServiceLoader is not thread-safe (see documentation: Instances of this class are not safe for use by multiple concurrent threads) So I suppose you should use a ThreadLocal reference to ServiceLoader.

There is also one more consideration. JsonProvider is thread-safe according to its documentation so there is no need to create a new instance of DEFAULT_PROVIDER each time ServiceLoader didn't found any provider: create instance of DEFAULT_PROVIDER once and reuse it. I.e. the following code in the method JsonProvider.provide() should also be refactored:

Class<?> clazz = Class.forName(DEFAULT_PROVIDER);
return (JsonProvider)clazz.newInstance();

P.S unfortunately there is no way to reopen the ticket, but I hope you'll react to this comment.

Comment by kchung [ 24/Jun/14 ]

Good catch! How about:

--- a/api/src/main/java/javax/json/spi/JsonProvider.java
+++ b/api/src/main/java/javax/json/spi/JsonProvider.java
@@ -71,7 +71,14 @@ public abstract class JsonProvider {
      */
     private static final String DEFAULT_PROVIDER
             = "org.glassfish.json.JsonProviderImpl";
-    private static ServiceLoader<JsonProvider> loader = ServiceLoader.load(JsonProvider.class);
+    private static JsonProvider defaultJsonProvider;
+    private static final ThreadLocal<ServiceLoader<JsonProvider>> threadLoader =
+        new ThreadLocal<ServiceLoader<JsonProvider>>() {
+            @Override
+            protected ServiceLoader<JsonProvider> initialValue() {
+                return ServiceLoader.load(JsonProvider.class);
+            }
+        };
 
     protected JsonProvider() {
     }
@@ -86,14 +93,19 @@ public abstract class JsonProvider {
      * @return a JSON provider
      */
     public static JsonProvider provider() {
-        Iterator<JsonProvider> it = loader.iterator();
+        Iterator<JsonProvider> it = threadLoader.get().iterator();
         if (it.hasNext()) {
             return it.next();
         }
 
+        if (defaultJsonProvider != null) {
+            return defaultJsonProvider;
+        }
+
         try {
             Class<?> clazz = Class.forName(DEFAULT_PROVIDER);
-            return (JsonProvider)clazz.newInstance();
+            defaultJsonProvider = (JsonProvider)clazz.newInstance();
+            return defaultJsonProvider;
         } catch (ClassNotFoundException x) {
             throw new JsonException(
                     "Provider " + DEFAULT_PROVIDER + " not found", x);
Comment by stIncMale [ 24/Jun/14 ]

Unfortunately this code isn't correctly synchronized according to JLS. I see you want to initialize defaultJsonProvider only if it's required (lazy initialization),but you must do it right. According to your notations and the original code, the following code should be correct (note that defaultJsonProvider is volatile)

private static final String DEFAULT_PROVIDER
		= "org.glassfish.json.JsonProviderImpl";
private static volatile JsonProvider defaultJsonProvider;
private static final Object mutex = new Object();
private static final ThreadLocal<ServiceLoader<JsonProvider>> threadLoader
		= new ThreadLocal<ServiceLoader<JsonProvider>>() {
			@Override
			protected ServiceLoader<JsonProvider> initialValue() {
				return ServiceLoader.load(JsonProvider.class);
			}
		};

public static JsonProvider provider() {
	Iterator<JsonProvider> it = threadLoader.get().iterator();
	if (it.hasNext()) {
		return it.next();
	}
	return getDefaultProvider();
}

private static JsonProvider getDefaultProvider() {
	JsonProvider result = defaultJsonProvider;//use local variable in order to reduce number of volatile reads
	if (result == null) {
		synchronized (mutex) {
			result = defaultJsonProvider;
			if (result == null) {
				result = createDefaultProvider();
				defaultJsonProvider = result;
			}
		}
	}
	return result;
}

private static JsonProvider createDefaultProvider() {
	try {
		Class<?> clazz = Class.forName(DEFAULT_PROVIDER);
		return (JsonProvider)clazz.newInstance();
	} catch (ClassNotFoundException x) {
		throw new JsonException(
				"Provider " + DEFAULT_PROVIDER + " not found", x);
	} catch (Exception x) {
		throw new JsonException(
				"Provider " + DEFAULT_PROVIDER + " could not be instantiated: " + x,
				x);
	}
}
Comment by stIncMale [ 25/Jun/14 ]

I also wonder if there is a place where I could find a roadmap with dates so I could see when version with fix (1.0.5 I suppose) may be released?

Comment by kchung [ 25/Jun/14 ]

The code is not synchronized, but it is harmless. There is no race condition here. The worst that can happen is more than one instance of default JsonProvider may be created, and two threads may get different instances. I don't see how it can fail.

I should make defaultJsonProvide volatile, though.

Comment by stIncMale [ 25/Jun/14 ]
The code is not synchronized, but it is harmless

No, JLS do allows your code to return null from provider() method; also if it returns not null there is no guarantee that internals of the returned object will be seen correctly.

There is no race condition here

That's not true. There is both race condition and data race (see Race Condition vs. Data Race if you don't know the difference). As you said, "more than one instance of default JsonProvider may be created" - this is a race condition, because timing/ordering of operations affects behavior.

Now let's see if there is a data race. Let's refer to JLS:
JLS 17.4.5. Happens-before Order - "When a program contains two conflicting accesses that are not ordered by a happens-before relationship, it is said to contain a data race."
JLS 17.4.1. Shared Variables - "Two accesses to (reads of or writes to) the same variable are said to be conflicting if at least one of the accesses is a write."

In your code there are reads and writes of the field defaultJsonProvider and these actions aren't ordered with happens-before, so by definition there is a data rece.

I should make defaultJsonProvide volatile, though.

This will remove data race but race condition still will be there ("more than one instance of default JsonProvider may be created"). This won't be critical, but why you don't want to write more stable code?

I don't see how it can fail.

Yeah, yeah..., reminds me this Benign Data Races: What Could Possibly Go Wrong?

If you still think that your code is OK and harmless, I would suggest you to ask someone who you trust and who do understand Java memory model (yep, such programmers are rarity), or write a question to concurrency-interest mail group. But please don't commit code as specified in your second try.

Comment by kchung [ 26/Jun/14 ]

The way defaultProvider is initialized lazily is known as "single check idiom" (Effective Java, Item 71). It may create more than one instance, but it IS harmless.

However, I've discovered a better way of doing this, which is known as "lazy initialization holder class idiom".

--- a/api/src/main/java/javax/json/spi/JsonProvider.java
+++ b/api/src/main/java/javax/json/spi/JsonProvider.java
@@ -71,7 +71,32 @@ public abstract class JsonProvider {
      */
     private static final String DEFAULT_PROVIDER
             = "org.glassfish.json.JsonProviderImpl";
-    private static ServiceLoader<JsonProvider> loader = ServiceLoader.load(JsonProvider.class);
+    private static final ThreadLocal<ServiceLoader<JsonProvider>> threadLoader =
+        new ThreadLocal<ServiceLoader<JsonProvider>>() {
+            @Override
+            protected ServiceLoader<JsonProvider> initialValue() {
+                return ServiceLoader.load(JsonProvider.class);
+            }
+        };
+
+    //Lazy initialization holder class idiom
+    private static class JsonProviderHolder {
+        static final JsonProvider defaultJsonProvider = initDefault();
+
+        static JsonProvider initDefault() {
+            try {
+                Class<?> clazz = Class.forName(DEFAULT_PROVIDER);
+                return (JsonProvider)clazz.newInstance();
+            } catch (ClassNotFoundException x) {
+                throw new JsonException(
+                        "Provider " + DEFAULT_PROVIDER + " not found", x);
+            } catch (Exception x) {
+                throw new JsonException(
+                        "Provider " + DEFAULT_PROVIDER + " could not be instantiated: " + x,
+                        x);
+            }
+        }
+    }
  
     protected JsonProvider() {
     }
@@ -86,22 +111,12 @@ public abstract class JsonProvider {
      * @return a JSON provider
      */
     public static JsonProvider provider() {
-        Iterator<JsonProvider> it = loader.iterator();
+        Iterator<JsonProvider> it = threadLoader.get().iterator();
         if (it.hasNext()) {
             return it.next();
         }
 
-        try {
-            Class<?> clazz = Class.forName(DEFAULT_PROVIDER);
-            return (JsonProvider)clazz.newInstance();
-        } catch (ClassNotFoundException x) {
-            throw new JsonException(
-                    "Provider " + DEFAULT_PROVIDER + " not found", x);
-        } catch (Exception x) {
-            throw new JsonException(
-                    "Provider " + DEFAULT_PROVIDER + " could not be instantiated: " + x,
-                    x);
-        }
+        return JsonProviderHolder.defaultJsonProvider;
     }
Comment by stIncMale [ 26/Jun/14 ]
The way defaultProvider is initialized lazily is known as "single check idiom" (Effective Java, Item 71). It may create more than one instance, but it IS harmless.

Effective Java tells us that field must be volatile for "single check idiom" (as I said, in this case we will not have a data race, but will have a harmless race condition; still the code is correctly synchronized and can be commited)

Without volatile modificator one must use a local variable and the reference must be of primitive (except long and double) or immutable type. So instead of

if (defaultJsonProvider != null) {
	return defaultJsonProvider;// counterintuitive, but JLS do allow this to return null if defaultJsonProvider isn't volatile
}

one must write

JsonProvider result = defaultJsonProvider;// use local variable, so defaultJsonProvider is read only once
if (result != null) {
	return result;// this can never return null
}

Effective Java refers to this idiom as "racy single-check idiom".

Code in the comment 24/Jun/14 9:30 PM is not a "single check idiom" because of the lack of volatile and not a "racy single-check idiom" because there is no local variable and JsonProvider is not immutable (only thread-safety is required by its specification).

I've discovered a better way of doing this, which is known as "lazy initialization holder class idiom"

Yep, this is a good alternative to "double-check idiom". I'm OK with it

Comment by kchung [ 26/Jun/14 ]

Thanks for taking time helping me to get this right. I've learned much.

Comment by stIncMale [ 26/Jun/14 ]

You are welcome.

Is there a place where I could find a roadmap with dates so I could see when version with this fix (1.0.5 I suppose) may be released?





[JSONP-25] Build fails using javac 1.6.0 Created: 08/Nov/13  Updated: 12/Nov/13  Resolved: 12/Nov/13

Status: Resolved
Project: jsonp
Component/s: None
Affects Version/s: None
Fix Version/s: 1.0.4

Type: Bug Priority: Major
Reporter: Przemyslaw Bielicki Assignee: Unassigned
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

javac 1.6.0_45



 Description   

pom.xml defines source and target level at 1.6 but JSONP build fails using javac 1.6:

[ERROR] D:\git_clones\java\jsonp~git\tests\src\test\java\org\glassfish\json\tests\JsonParserTest.java:[696,22] cannot find symbol
[ERROR] symbol  : constructor AssertionError(java.lang.String,java.lang.AssertionError)
[ERROR] location: class java.lang.AssertionError
[ERROR] D:\git_clones\java\jsonp~git\tests\src\test\java\org\glassfish\json\tests\JsonParserTest.java:[724,22] cannot find symbol
[ERROR] symbol  : constructor AssertionError(java.lang.String,java.lang.AssertionError)
[ERROR] location: class java.lang.AssertionError
[ERROR] D:\git_clones\java\jsonp~git\tests\src\test\java\org\glassfish\json\tests\JsonParserTest.java:[766,26] cannot find symbol
[ERROR] symbol  : constructor AssertionError(java.lang.String,java.lang.AssertionError)
[ERROR] location: class java.lang.AssertionError

In order to build JSONP correctly one needs to use javac version 1.7.x



 Comments   
Comment by Przemyslaw Bielicki [ 12/Nov/13 ]

sent patch to users (at) jsonp.java.net

Comment by jitu [ 12/Nov/13 ]

Fixing it in 1.0.4. Using Throwable instead of two-arg constructor of AssertionError.





[JSONP-23] Json array key is broken when the data size is special Created: 26/Oct/13  Updated: 28/Oct/13  Resolved: 27/Oct/13

Status: Resolved
Project: jsonp
Component/s: None
Affects Version/s: 1.0.4
Fix Version/s: 1.0.4

Type: Bug Priority: Major
Reporter: Coo Assignee: jitu
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

With the following code, JsonReader fails to decode string "key3" when data size is 16364.
I guess this is a buffer size problem.

printArray(16363); // key3: [1], empty:null
printArray(16364); // key3: null, empty:[1]
printArray(16365); // key3: [1], empty:null

private static void printArray(int magicNumber) {
StringBuilder sb = new StringBuilder();
sb.append('{');
sb.append("\"key1\":\"");
for (int i = 0; i < magicNumber; ++i) {
sb.append("a");
}
sb.append("\",");
sb.append("\"key2\":[

{\"empty\":\"\",\"key3\":[1]}

]}");
JsonObject obj = Json.createReader(new StringReader(sb.toString())).readObject();
Object result = obj.getJsonArray("key2").getJsonObject(0).getJsonArray("key3");
Object result2 = obj.getJsonArray("key2").getJsonObject(0).getJsonArray("");
System.out.println("key3: " + result + ", empty:" + result2);
}



 Comments   
Comment by jitu [ 26/Oct/13 ]

Cached value from empty name is getting returned for the next key "key3"
Will fix in 1.0.4.

Comment by jitu [ 27/Oct/13 ]

Now value is not cached at all. This works ok since JsonParser#getString() is not usually called multiple
times by an application.

Comment by Coo [ 28/Oct/13 ]

Fix confirmed with the latest code in git repository.
Thanks!





[JSONP-24] Sequence of adding a JsonArrayBuilder into a JsonObjectBuilder interferes in the final result Created: 27/Oct/13  Updated: 27/Oct/13

Status: Open
Project: jsonp
Component/s: None
Affects Version/s: 1.0.3
Fix Version/s: None

Type: Bug Priority: Critical
Reporter: Hildeberto Mendonça Assignee: Unassigned
Resolution: Unresolved Votes: 2
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

JDK 1.7, Glassfish 3.1.2.2, Jersey 1.8


Tags: JsonArrayBuilder, JsonObject, JsonObjectBuilder

 Description   

While creating some Json content using the Object Model API, I realised that the sequence of adding a JsonArrayBuilder into a JsonObjectBuilder interferes in the final result. The following code won't include the categories in the resulting Json because the line, indicated with an arrow, adds the JsonArrayBuilder to the JsonObjectBuilder before JsonArrayBuilder is loaded with data :

List<CategoryMenu> categories = categoryMenuBean.findCategoriesByMenu(menu);
JsonObjectBuilder objectBuilder = Json.createObjectBuilder();
JsonArrayBuilder arrayBuilderCategories = Json.createArrayBuilder();

objectBuilder.add("categories", arrayBuilderCategories); // <--

for(CategoryMenu category: categories) {
     arrayBuilderCategories.add(Json.createObjectBuilder()
                 .add("id", category.getId())
                 .add("name", category.getName()));
}

JsonObject model = objectBuilder.build();
StringWriter strWriter = new StringWriter();
try (JsonWriter jsonWriter = Json.createWriter(strWriter)) {
     jsonWriter.writeObject(model);
}

System.out.println(strWriter.toString()); // output = []

To work around with the problem, I had to move that highlighted line to after the iteration:

List<CategoryMenu> categories = categoryMenuBean.findCategoriesByMenu(menu);
JsonObjectBuilder objectBuilder = Json.createObjectBuilder();
JsonArrayBuilder arrayBuilderCategories = Json.createArrayBuilder();

for(CategoryMenu category: categories) {
     arrayBuilderCategories.add(Json.createObjectBuilder()
                 .add("id", category.getId())
                 .add("name", category.getName()));
}

objectBuilder.add("categories", arrayBuilderCategories); // <--

JsonObject model = objectBuilder.build();
StringWriter strWriter = new StringWriter();
try (JsonWriter jsonWriter = Json.createWriter(strWriter)) {
     jsonWriter.writeObject(model);
}
System.out.println(strWriter.toString()); // output = {"categories":[{"id":1,"name":"Plat du Jour"},{"id":2,"name":"Permanent"}]}

Apparently, the build is performed right away, while data is added to those builder objects. In fact, it should be built only when the method build() is finally invoked. In both examples, it always happen when all data is added to the builders and it is time to build the final JsonObject model. Therefore, both examples above should work normally.






[JSONP-6] licensee source bundle improvement Created: 23/Apr/13  Updated: 23/Oct/13  Resolved: 23/Oct/13

Status: Resolved
Project: jsonp
Component/s: None
Affects Version/s: None
Fix Version/s: 1.0.4

Type: Improvement Priority: Major
Reporter: jitu Assignee: jitu
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

Current licensee source bundle includes sources in a jar. Instead of that, consider workspace view (api and impl directories with the corresponding sources)






[JSONP-8] JsonTokenizer to JsonParser improvements Created: 23/Apr/13  Updated: 23/Oct/13  Resolved: 23/Oct/13

Status: Resolved
Project: jsonp
Component/s: None
Affects Version/s: None
Fix Version/s: 1.0.2

Type: Improvement Priority: Major
Reporter: jitu Assignee: Unassigned
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   
  • No need to convert char[] -> String -> BigDecimal(String). Instead directly create BigDecimal(char[])
  • Take advantage of tokenizer which knows if the number is integral or not (based on . or exponential notation). Then avoid creating BigDecimal for JsonParser#intValue(), JsonParser#longValue() in those circumstances.





[JSONP-7] Memory Improvement : while building empty arrays and objects Created: 23/Apr/13  Updated: 23/Oct/13  Resolved: 23/Oct/13

Status: Resolved
Project: jsonp
Component/s: None
Affects Version/s: None
Fix Version/s: 1.0.2

Type: Improvement Priority: Major
Reporter: jitu Assignee: Unassigned
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

In the following check for empty valueList, and use Collections.emptyList()

public JsonArray build()

{ ArrayList<JsonValue> snapshot = new ArrayList<JsonValue>(valueList); return new JsonArrayImpl(Collections.unmodifiableList(snapshot)); }

Similarly, while building JSON objects






[JSONP-22] JsonNumberImpl improvement Created: 04/Oct/13  Updated: 23/Oct/13  Resolved: 23/Oct/13

Status: Resolved
Project: jsonp
Component/s: None
Affects Version/s: None
Fix Version/s: 1.0.4

Type: Improvement Priority: Major
Reporter: jitu Assignee: Unassigned
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

Create BigDecimal lazily for int and long number values.



 Comments   
Comment by jitu [ 23/Oct/13 ]

JsonNumberImpl.JsonIntNumber, JsonNumberImpl.JsonLongNumber are using to represent JsonNumber when built using int and long. They create BigDecimal lazily.





[JSONP-21] Update parent version in bundle packages Created: 24/Sep/13  Updated: 23/Oct/13  Resolved: 23/Oct/13

Status: Resolved
Project: jsonp
Component/s: None
Affects Version/s: 1.0.3
Fix Version/s: 1.0.4

Type: Bug Priority: Minor
Reporter: paulkmoore Assignee: Unassigned
Resolution: Fixed Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: maven

 Description   

The version of the <parent> is incorrect (should be "1.0.3-SNAPSHOT")in the following bundle pom.xml's:

bundles/pom.xml
bundles/ri/pom.xml
bundles/licensee/pom.xml

Note: this currently causes the build to fail



 Comments   
Comment by Przemyslaw Bielicki [ 19/Oct/13 ]

Guys,

I just cloned Git repo and the build works fine. Git log says that Jitendra fixed it.

There is, however, another small issue with the build:

[INFO] JSR 353 (JSON Processing) API ..................... SUCCESS [5.808s]
[INFO] JSR 353 (JSON Processing) RI ...................... SUCCESS [0.214s]
[INFO] JSR 353 (JSON Processing) Default Provider ........ SUCCESS [4.102s]
[INFO] JSR 353 (JSON Processing) Media for JAX-RS ........ SUCCESS [5.084s]
[INFO] JSR 353 (JSON Processing) Tests ................... SUCCESS [23.421s]
[INFO] providers ......................................... SUCCESS [6.837s]
[INFO] customprovider .................................... SUCCESS [2.769s]
[INFO] defaultprovider ................................... SUCCESS [0.471s]
[INFO] demos ............................................. SUCCESS [0.022s]
[INFO] jsondemos-jaxrs ................................... SUCCESS [0.598s]
[INFO] jsondemos-twitter ................................. SUCCESS [0.708s]
[INFO] jsondemos-facebook ................................ SUCCESS [0.381s]
[INFO] JSR 353 (JSON Processing) bundles ................. SUCCESS [0.016s]
[INFO] RI bundle ......................................... SUCCESS [0.666s]
[INFO] Licensee source bundle ............................ FAILURE [0.091s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 54.911s
[INFO] Finished at: Sat Oct 19 09:54:26 CEST 2013
[INFO] Final Memory: 32M/427M

caused by unknown host http://hudson-sca.us.oracle.com/job/tlda-license/lastSuccessfulBuild/artifact

Could you please fix it?

Cheers,
Przemyslaw

Comment by jitu [ 23/Oct/13 ]

licensee bundle is created using a profile and is not activated by default. Now, everything should build fine.





[JSONP-20] Localization of exception text Created: 20/Sep/13  Updated: 15/Oct/13  Resolved: 15/Oct/13

Status: Resolved
Project: jsonp
Component/s: None
Affects Version/s: None
Fix Version/s: 1.0.4

Type: New Feature Priority: Minor
Reporter: curtisr7 Assignee: jitu
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: localization

 Description   

Are there any plans to factor Exception text out into .properties files to allow for proper localization?



 Comments   
Comment by curtisr7 [ 30/Sep/13 ]

Is anyone monitoring this tracker?

Comment by jitu [ 30/Sep/13 ]

1.0.3 is just released. Will target for 1.0.4

Comment by jitu [ 15/Oct/13 ]

Fixed in 1.0.4





[JSONP-19] JsonString improperly scaped Created: 01/Sep/13  Updated: 03/Sep/13  Resolved: 03/Sep/13

Status: Resolved
Project: jsonp
Component/s: None
Affects Version/s: 1.0.2
Fix Version/s: 1.0.3

Type: Bug Priority: Major
Reporter: zmarcos Assignee: jitu
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

Quick test app:

App.java
public class App 
{
    public static void main( String[] args )
    {
        JsonArray jsonArray = Json.createArrayBuilder().add("test\"\\/").build();
        System.out.println(jsonArray.toString());
        System.out.println(jsonArray.get(0).toString());
        
        JsonArray jsonArray2 = Json.createArrayBuilder().add(jsonArray.get(0)).build();        
        System.out.println(jsonArray2.toString());
        System.out.println(jsonArray2.get(0).toString());
        
        JsonArray jsonArray3 = Json.createReader(new StringReader(jsonArray.toString())).readArray();        
        System.out.println(jsonArray3.toString());
        System.out.println(jsonArray3.get(0).toString());
        
        JsonArray jsonArray4 = Json.createReader(new StringReader("["+jsonArray.get(0).toString()+"]")).readArray();        
        System.out.println(jsonArray4.toString());
        System.out.println(jsonArray4.get(0).toString());
    }
}

Output:

["test\"\\/"]
"test"\/"
["test\"\\/"]
"test"\/"
["test\"\\/"]
"test"\/"
Exception in thread "main" javax.json.stream.JsonParsingException: Unexpected char=\
at org.glassfish.json.JsonTokenizer.nextToken(JsonTokenizer.java:409)
at org.glassfish.json.JsonParserImpl.nextToken(JsonParserImpl.java:154)
at org.glassfish.json.JsonParserImpl.access$400(JsonParserImpl.java:60)
at org.glassfish.json.JsonParserImpl$ArrayContext.getNextEvent(JsonParserImpl.java:286)
at org.glassfish.json.JsonParserImpl$StateIterator.next(JsonParserImpl.java:180)
at org.glassfish.json.JsonParserImpl.next(JsonParserImpl.java:149)
at org.glassfish.json.JsonReaderImpl.readArray(JsonReaderImpl.java:137)
at org.glassfish.json.JsonReaderImpl.readArray(JsonReaderImpl.java:119)
at br.com.test.jsontest.App.main(App.java:27)



 Comments   
Comment by jitu [ 03/Sep/13 ]

Fixed in 1.0.3 snapshot, will be available with 1.0.3 release





[JSONP-18] JsonGenerator#flush() is not flushing the underlying stream Created: 23/Aug/13  Updated: 26/Aug/13  Resolved: 26/Aug/13

Status: Resolved
Project: jsonp
Component/s: None
Affects Version/s: 1.0.2
Fix Version/s: 1.0.3

Type: Bug Priority: Major
Reporter: jitu Assignee: Unassigned
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

JsonGenerator#flush() javadoc says :

" * Flushes the underlying output source. If the generator has saved

  • any characters in a buffer, writes them immediately to the underlying
  • output source before flushing it."


 Comments   
Comment by jitu [ 26/Aug/13 ]

Fixed in 1.0.3





[JSONP-11] JsonWriterImpl does not write until close() is invoked Created: 01/May/13  Updated: 04/Aug/13  Resolved: 04/Aug/13

Status: Resolved
Project: jsonp
Component/s: None
Affects Version/s: None
Fix Version/s: 1.0.2

Type: Bug Priority: Major
Reporter: gawix Assignee: jitu
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

I'm not sure if this is the right place to file problems with the Glassfish JSON API RI.

Consider the following code:

public static void main(String[] args)

{ StringWriter stringWriter = new StringWriter(); stringWriter.write("(before)"); JsonObjectBuilder builder = JsonProvider.provider().createObjectBuilder(); builder.add("a", "a"); builder.add("b", "b"); JsonWriter jsonWriter = JsonProvider.provider().createWriter(stringWriter); jsonWriter.write(builder.build()); jsonWriter.close(); stringWriter.write("(after)"); System.out.println(stringWriter.toString()); }

If I omit the jsonWriter.close() statement, the content is not written on the writer. In this case, since I'm using a StringWriter, it has no effect (StringWriter.close() is a no-op) but for other cases, like a Writer backed by a file or a socket, this is a problem since jsonWriter.close() closes the underlying stream or writer and I can no longer write on it.



 Comments   
Comment by gawix [ 01/May/13 ]

Sorry about the layout. Here it is again:

    public static void main(String[] args) {

        StringWriter stringWriter = new StringWriter();
        stringWriter.write("(before)");

        JsonObjectBuilder builder = JsonProvider.provider().createObjectBuilder();
        builder.add("a", "a");
        builder.add("b", "b");

        JsonWriter jsonWriter = JsonProvider.provider().createWriter(stringWriter);
        jsonWriter.write(builder.build());
        jsonWriter.close();

        stringWriter.write("(after)");
        System.out.println(stringWriter.toString());
    }
Comment by jitu [ 01/May/13 ]

I don't consider that as a bug. It is similar to writing something to OutputStream after OutputStream.close() is called. The current pattern is similar to how JDK streams are chained.

If you really want to write something to underlying output source, you just wrap it in FilterOutputStream/FilterWriter and override the close() method.

Also, you don't have to use JsonProvider since that is primarily to plugin providers. You can use Json.createObjectBuilder() or use the corresponding factory.

Comment by gawix [ 01/May/13 ]

The problem is that write()/writeObject()/writeArray() don't write to the underlying writer as specified by the API. I'm forced to close() the underlying stream/writer to see the effects of the write*() methods.

There is no flush() method in the API for JsonWriter neither, so you can't add one in the JsonWriterImpl to fix this problem.

Comment by jitu [ 01/May/13 ]

As per the contract, you have to call close() so that any resources may be released.

In the impl, the passed in stream is wrapped into buffered stream. The write methods do write to the buffered stream. One could flush the buffered stream in the impl after a write() call, though it is not necessary. It is similar to
OutputStream os = new BufferedOutputStream(...); os.write(...);

If you don't call os.close(), the data may not be written to the actual underlying stream.

flush() is not provided on JsonWriter, since it is only one write method is allowed. So it is not necessary. Wherese, we provided flush() on JsonGenerator, since the data may be written using multiple methods.

Comment by gawix [ 01/May/13 ]

Why close() is needed when only one write() is possible?

The BufferWriter wrapper is indeed the root of my problem. I cannot call flush() on it because I do not have access to it. I could avoid creating a wrapper by providing a BufferedWriter to JsonWritter and keep the reference so I can call flush() on it but it's not a good solution (implementation-dependant).

If you run this slightly modified example, you'll see as output: (before)(after)

{"a":"a","b":"b"}

This is not the expected result, I'm sure you will agree.

    public static void main(String[] args) {

        StringWriter stringWriter = new StringWriter();
        stringWriter.write("(before)");

        JsonObjectBuilder builder = JsonProvider.provider().createObjectBuilder();
        builder.add("a", "a");
        builder.add("b", "b");

        JsonWriter jsonWriter = JsonProvider.provider().createWriter(stringWriter);
        jsonWriter.write(builder.build());

        stringWriter.write("(after)");
        jsonWriter.close();

        System.out.println(stringWriter.toString());
    }

However, consider the following patch:

diff --git a/impl/src/main/java/org/glassfish/json/JsonWriterImpl.java b/impl/src/main/java/org/glassfish/json/JsonWriterImpl.java
index fe4ba10..505c724 100644
--- a/impl/src/main/java/org/glassfish/json/JsonWriterImpl.java
+++ b/impl/src/main/java/org/glassfish/json/JsonWriterImpl.java
@@ -91,6 +91,7 @@ class JsonWriterImpl implements JsonWriter {
             generator.write(value);
         }
         generator.writeEnd();
+        generator.flush();
     }
 
     @Override
@@ -104,6 +105,7 @@ class JsonWriterImpl implements JsonWriter {
             generator.write(e.getKey(), e.getValue());
         }
         generator.writeEnd();
+        generator.flush();
     }
 
     @Override
Comment by jitu [ 01/May/13 ]

close is there to close any other resources. We don't know how implementations implement JsonWriter.

You could something like the following:

    StringWriter strWriter = new StringWriter();
    strWriter.write("(before)");
    Writer writer = new FilterWriter(strWriter) {
        public void close() {
            // no-op as we don't want to close strWriter
        }
    };

    JsonWriter jw = Json.createWriter(writer);
    jw.writeObject(Json.createObjectBuilder().build());
    jw.close();
    
    strWriter.write("(after)");
Comment by gawix [ 02/May/13 ]

Sorry I'm late for the public review of JSR-353. Nevertheless...

There is no need in the API for a close() method. Implementation could free up resources in write() since there is only one call allowed on either of the write() methods. The fact that you must invoke the two methods in a row, as you suggest, proves that there is something wrong with it.

Your BufferedOutputStream example is not appropriate because BufferedOutputStream never forces the caller to invoke the close() method and thus leaves the caller with the decision to call BufferedOutputStream.close() if writing is over for this stream or BufferedOutputStream.flush() if something else will be added later. So close() is optional on BufferedOutputStream as long as you close() the underlying InputStream yourself. I was expecting the same thing from JsonWriter and thought that close() would only close the underlying writer (what other resource JsonWriter could possibly require anyway).

I understand the FilterOutputStream hack and it's my workaround for the moment. I don't think it's reasonable to expect everyone to use this pattern and this is why I was suggesting to at least call generator.flush() before ending the function in order to make the call to close() optional. I have a ServletOutputStream, I don't want to close() it, it is the responsibility of the servlet container to do so.

If you leave JsonWriter as is, I might as well use the JsonGenerator directly and avoid the pitfall.

Comment by jitu [ 02/May/13 ]

You are right that BufferedOutputStream#close() doesn't flush the buffer. My guess is that it is not fixed due to compatibility reasons. But see BufferedWriter#close() which flushes the internal buffer and closes the underlying writer. Thus in turn, it forces you to call close(). Doing that allows chaining of writers, ARM blocks will also work with close(). Closing the underlying stream is the common case, hence that was chosen as the default.

There are some usecases (less common), where closing of the underlying stream is not desirable (say writing multipart MIME, and one part is JSON). Either, one could use some feature (at present it would be a provider-specific behaviour) to configure the close behaviour or override the close() method of underlying writer.

Let us see if calling generator.flush() helps or there are some other implications. In the servlet containers, calling flush() may produce a immediate data flush on the socket channel resulting in a unnecessary chunk. But the data can be written without flushing using a private contract of JsonGeneratorImpl.

Comment by gawix [ 02/May/13 ]

I'm not saying that BufferedOutputStream#close() doesn't flush the buffer (in fact, it does). I'm saying that the contract does not force me to do so. I can also choose between the inner OutputStream or the BufferedOutputStream for ARM depending on the requirements.

Let's look at a solution from another angle. If you modify JsonGeneratorImpl not to wrap the Writer, the user still has control over the writer (and may call flush() IF required):

diff --git a/impl/src/main/java/org/glassfish/json/JsonGeneratorImpl.java b/impl/src/main/java/org/glassfish/json/JsonGeneratorImpl.java
index 24915c5..d1f3fe8 100644
--- a/impl/src/main/java/org/glassfish/json/JsonGeneratorImpl.java
+++ b/impl/src/main/java/org/glassfish/json/JsonGeneratorImpl.java
@@ -62,9 +62,6 @@ class JsonGeneratorImpl implements JsonGenerator {
     private final Deque<Context> stack = new ArrayDeque<Context>();
 
     JsonGeneratorImpl(Writer writer) {
-        if (!(writer instanceof  BufferedWriter)) {
-            writer = new BufferedWriter(writer);
-        }
         this.writer = writer;
     }

Without this wrapping of Writer, there is no need for JsonGenerator.flush() as Writer.write() operations are guaranteed to be done on the provided Writer directly.

I know that your intent here is to provide a possible performance gain but it is the responsibility of the caller to provide a BufferedWriter if appropriate. In my example, I'm using a StringWriter, there is no need to wrap it since it is backed by a StringBuilder which already has a buffer. Also, you cannot guess which Writer implementations do some buffering internally (e.g. a FilterWriter might wrap a BufferedWriter).

I've talked about this issue with my experienced co-workers and they agree with me. I'm expecting other people to run in the same issue with JsonWriter.

Comment by jitu [ 02/May/13 ]

JsonGeneratorImpl may not use BufferedWriter in future for different reasons(for e.g. it uses synchronization). But that is an implementation detail. Your application shouldn't rely on the implementation detail.

Also, it may consider some other buffering mechanism. I am sure other implementations also using some buffering mechanism. For example, take a look at popular Jackson's generator (not based on JSR 353)

http://grepcode.com/file/repo1.maven.org/maven2/com.fasterxml.jackson.core/jackson-core/2.0.0-RC1/com/fasterxml/jackson/core/json/WriterBasedJsonGenerator.java

Comment by gawix [ 02/May/13 ]

Let's start over.

From the spec:

void JsonWriter.write(JsonStructure value)

Writes the specified JSON object or array to the output source. This method needs to be called only once for a writer instance.

With the Glassfish implementation, a call to write() does not in fact write the object/array on the output source (unless output source is an instance of BufferedWriter).

Nowhere is mentioned that close() will write to the output source.

Removing the BufferedWriter in JsonGenerator would fix this bug.

Comment by jitu [ 04/Aug/13 ]

JsonWriter's writeArray(), writeObject() write to the output source in 1.0.2. But it doesn't mean one can forget calling close().





[JSONP-12] Improve JsonGenerator.write(int) performance Created: 04/May/13  Updated: 04/Aug/13  Resolved: 04/Aug/13

Status: Resolved
Project: jsonp
Component/s: None
Affects Version/s: None
Fix Version/s: 1.0.1

Type: Improvement Priority: Major
Reporter: jitu Assignee: Unassigned
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

Now, essentially Integer.toSting() is used which unnecessarily creates intermediate string (that can be avoided either by writing to character stream or converting to char[] and writing the array)






[JSONP-13] Don't use buffered streams as they synchronize the method access Created: 20/May/13  Updated: 04/Aug/13  Resolved: 04/Aug/13

Status: Resolved
Project: jsonp
Component/s: None
Affects Version/s: None
Fix Version/s: 1.0.2

Type: Improvement Priority: Major
Reporter: jitu Assignee: jitu
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

JsonParser, JsonGenerator use buffered streams. But buffered streams synchronize some of the methods and hence I suggest doing buffering differently.



 Comments   
Comment by jitu [ 04/Aug/13 ]

Fixed in 1.0.2





[JSONP-17] Method toString() of JsonString lacking double quotes Created: 27/Jul/13  Updated: 04/Aug/13  Resolved: 04/Aug/13

Status: Resolved
Project: jsonp
Component/s: None
Affects Version/s: None
Fix Version/s: 1.0.2

Type: Bug Priority: Major
Reporter: zmarcos Assignee: Unassigned
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

GlassFish 4.0 - Web Profile - Linux



 Description   

JSON strings are enclosed with double quotes, but method toString() acts like getString().



 Comments   
Comment by jitu [ 04/Aug/13 ]

Fixed in 1.0.2





[JSONP-16] JsonTokenizer assertion fails when buffer is full before reading a string token Created: 23/Jul/13  Updated: 04/Aug/13  Resolved: 04/Aug/13

Status: Resolved
Project: jsonp
Component/s: None
Affects Version/s: 1.0.1
Fix Version/s: 1.0.2

Type: Bug Priority: Major
Reporter: jake-daniel-collins Assignee: Unassigned
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

The assertion on line 391 fails under certain conditions.

Please run the following test to recreate the issue:

public void testTokenizer() {
int iterations = 1024;
StringBuilder sb = new StringBuilder(iterations * 4 + 7);
sb.append("[\"aaa\",");
for(int i = 0; i < iterations; i++)

{ if (i > 0) sb.append(","); sb.append("\""); sb.append("a"); sb.append("\""); }

sb.append("]");
String json = sb.toString();
JsonParser parser = Json.createParser(new StringReader(json));
int i = 0;
while (parser.hasNext())

{ parser.next(); // set a conditional break point here for i == iterations i++; }

parser.close();
}

Stack trace:

java.lang.AssertionError
at org.glassfish.json.JsonTokenizer.readChar(JsonTokenizer.java:391)
at org.glassfish.json.JsonTokenizer.read(JsonTokenizer.java:103)
at org.glassfish.json.JsonTokenizer.readString(JsonTokenizer.java:129)
at org.glassfish.json.JsonTokenizer.nextToken(JsonTokenizer.java:315)
at org.glassfish.json.JsonParserImpl$StateIterator.nextToken(JsonParserImpl.java:158)
at org.glassfish.json.JsonParserImpl$StateIterator.next(JsonParserImpl.java:183)
at org.glassfish.json.JsonParserImpl.next(JsonParserImpl.java:151)
at org.glassfish.json.tests.JsonParserTest.testTokenizer(JsonParserTest.java:95)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at com.intellij.junit3.JUnit3IdeaTestRunner.doRun(JUnit3IdeaTestRunner.java:139)
at com.intellij.junit3.JUnit3IdeaTestRunner.startRunnerWithArgs(JUnit3IdeaTestRunner.java:52)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:195)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:63)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)



 Comments   
Comment by jitu [ 23/Jul/13 ]

I think this is duplicate of JSONP-15. It is fixed in the trunk and I hope to release 1.0.2 in a week or two. In the mean time, use 1.0. It would be great if you try with the trunk and verify that it is fixed indeed(I tried it but good to get a confirmation)

Comment by jake-daniel-collins [ 28/Jul/13 ]

Test passes for me now with latest trunk, thanks. Look forward to the next release.

Comment by jitu [ 04/Aug/13 ]

Fixed in 1.0.2





[JSONP-15]  ArrayIndexOutOfBoundsException using JsonTokenizer.readChar() Created: 22/Jul/13  Updated: 04/Aug/13  Resolved: 04/Aug/13

Status: Resolved
Project: jsonp
Component/s: None
Affects Version/s: 1.0.1
Fix Version/s: 1.0.2

Type: Bug Priority: Critical
Reporter: jitu Assignee: jitu
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException:
4096
at
org.glassfish.json.JsonTokenizer.readChar(JsonTokenizer.java:388)
at org.glassfish.json.JsonTokenizer.read(JsonTokenizer.java:98)
at
org.glassfish.json.JsonTokenizer.readString(JsonTokenizer.java:124)
at
org.glassfish.json.JsonTokenizer.nextToken(JsonTokenizer.java:310)
at
org.glassfish.json.JsonParserImpl$StateIterator.nextToken(JsonParserImp
l.java:157)
at
org.glassfish.json.JsonParserImpl$StateIterator.next(JsonParserImpl.jav
a:182)
at
org.glassfish.json.JsonParserImpl.next(JsonParserImpl.java:150)
at
org.glassfish.json.JsonReaderImpl.readObject(JsonReaderImpl.java:184)
at
org.glassfish.json.JsonReaderImpl.readArray(JsonReaderImpl.java:152)
at
org.glassfish.json.JsonReaderImpl.readObject(JsonReaderImpl.java:187)
at
org.glassfish.json.JsonReaderImpl.readArray(JsonReaderImpl.java:152)
at
org.glassfish.json.JsonReaderImpl.readObject(JsonReaderImpl.java:187)
at
org.glassfish.json.JsonReaderImpl.readArray(JsonReaderImpl.java:152)
at
org.glassfish.json.JsonReaderImpl.readObject(JsonReaderImpl.java:187)
at
org.glassfish.json.JsonReaderImpl.readArray(JsonReaderImpl.java:152)
at
org.glassfish.json.JsonReaderImpl.readObject(JsonReaderImpl.java:187)
at
org.glassfish.json.JsonReaderImpl.read(JsonReaderImpl.java:91)
at test.TestJson.main(TestJson.java:12)






[JSONP-14] Conversion of Java primitives to JSON Objects Created: 30/May/13  Updated: 30/May/13

Status: Open
Project: jsonp
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: New Feature Priority: Minor
Reporter: daveagp Assignee: Unassigned
Resolution: Unresolved Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

Currently, there is no API method that I can see to convert a String, int, etc. into a JSON primitive. It requires a line of code like

static JsonNumber jsonInt(long l)

{ return Json.createArrayBuilder().add(l).build().getJsonNumber(0); }

static JsonNumber jsonReal(double d)

{ return Json.createArrayBuilder().add(d).build().getJsonNumber(0); }

static JsonString jsonString(String S)

{ return Json.createArrayBuilder().add(S).build().getJsonString(0); }

but this is obviously wasteful in its use of an array.

I can try to implement changes to the API and reference implementation to add this functionality without the array, if it would be desired.

Because all Json value objects are interfaces, it seems one would have to add static methods somewhere rather than constructors to anything. It might make the most sense as one of the following

static JsonNumber Json.jsonNumber(long l)
or
static JsonNumber Json.createJsonNumber(long l)
or
static JsonNumber JsonNumber.create(long l)

or Json.mirror(), etc... Not sure if this already fits in some overarching plan. But if you want me to try to contribute just let me know what you think!






[JSONP-10] JsonValue.MISSING Created: 26/Apr/13  Updated: 26/Apr/13

Status: Open
Project: jsonp
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Improvement Priority: Major
Reporter: eric.jain Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

Given the following JSON:

{ 
    "settings" : {
        "dashboard" : { 
            "width" : 42
        }
    }
}

This code extracts the value of the width property:

int width = 0;
JsonObject settings = value.getJsonObject("settings");
if (settings != null) {
    JsonObject dashboard = settings.getJsonObject("dashboard");
    if (dashboard != null) {
        width = dashboard.getInt("width", 0)
    }
}

It would be nice if this could be accomplished in a more concise manner, e.g.

int width = value.findJsonObject("settings").findJsonObject("dashboard").getInt("width", 0)

The findJsonObject would behave like getJsonObject, but return an empty JsonObject instead of null for missing properties.






[JSONP-9] ObjectBuilder from JsonObject Created: 26/Apr/13  Updated: 26/Apr/13

Status: Open
Project: jsonp
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Improvement Priority: Major
Reporter: eric.jain Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

JsonObject is immutable, so in order to update one or more values, a new JsonObject has to be created. To avoid having to copy each unchanged value explicitly, the JsonObjectBuilder could be initialized with a JsonObject:

JsonObject oldValue = Json.createObjectBuilder()
    .add("firstName", "John")
    .add("lastName", "Smith")
    .add("age", 25).build();
JsonObject newValue = factory.createObjectBuilder(oldValue)
    .add("age", 26).build();

As an optimization, the new JsonObject could be backed by the old JsonObject.






[JSONP-5] Better JsonGenerator and JsonObjectBuilder Created: 18/Apr/13  Updated: 23/Apr/13

Status: Open
Project: jsonp
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Improvement Priority: Major
Reporter: anthavio Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

Recently I've did some builder pattern related coding and then I've come across javax.json api and I think that it can be improved

1. JsonGenerator allows user wrong method calls that throws exceptions.

JsonGenerator jg = javax.json.Json.createGenerator(System.out);
jg.writeStartObject().write("whatever").writeEnd(); //javax.json.stream.JsonGenerationException: write(String) can only be called in array context

2. JsonObjectBuilder methods for nested objects and arrays is somewhat cumbersome because of JsonBuilderFactory usage

Java 5 generics allows to create much neater builders. I've wrote article about this topic today http://anthavio.blogspot.co.uk/2013/04/building-fluent-builder.html
Please consider reusing ideas from my JsonBuilder into javax.json API making it more pleasant to work with



 Comments   
Comment by jitu [ 23/Apr/13 ]

In EA versions, we used builders with generics. JsonGenerator was also based on the builders. Based on other issues like the following, EG settled on the current approach.

https://java.net/jira/browse/JSON_PROCESSING_SPEC-36
https://java.net/jira/browse/JSON_PROCESSING_SPEC-11





[JSONP-4] Exception "Provider org.glassfish.json.JsonProviderImpl not found" when changing dependency groupId from "org.glassfish" to "javax.json". Created: 12/Apr/13  Updated: 12/Apr/13  Resolved: 12/Apr/13

Status: Resolved
Project: jsonp
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Critical
Reporter: Mohamed Taman Assignee: Unassigned
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: dependencies, fishcat

 Description   

When I do a change to the dependency in my project pom.xml from

<dependency>  
   <groupId>org.glassfish</groupId> 
   <artifactId>javax.json</artifactId> 
   <version>1.0-SNAPSHOT</version> 
   <type>jar</type>
   <scope>test</scope>
</dependency>

To

<dependency> 
    <groupId>javax.json</groupId> 
    <artifactId>javax.json-api</artifactId> 
    <version>1.0-SNAPSHOT</version> 
</dependency> 

And this is what is recommended by many users in the JSR-353 group mailing list and also listed at Java EE 7 Maven Coordinates

I got the following error in my JUnit testing environment:

"Provider org.glassfish.json.JsonProviderImpl not found"



 Comments   
Comment by Mohamed Taman [ 12/Apr/13 ]

Note: it works with the following dependency

<dependency>  
   <groupId>org.glassfish</groupId> 
   <artifactId>javax.json</artifactId> 
   <version>1.0-SNAPSHOT</version> 
   <type>jar</type>
   <scope>test</scope>
</dependency>
Comment by jitu [ 12/Apr/13 ]

org.glassfish:javax.json is RI jar which contains both api+impl.

javax.json:javax.json-api contains only API which is there for compile time dependency. But if you want to run your app, you need a provider/impl. RI bundle provides them.

Comment by Mohamed Taman [ 12/Apr/13 ]

Thanks





[JSONP-3] JsonWriter closes the underlying output stream Created: 18/Feb/13  Updated: 18/Feb/13  Resolved: 18/Feb/13

Status: Resolved
Project: jsonp
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Major
Reporter: arungupta Assignee: jitu
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

I've the following code in a Servlet:

PrintWriter out = response.getWriter();
JsonObject jsonObject = new JsonObjectBuilder().build();
new JsonWriter(out).writeObject(jsonObject);
jsonObject = new JsonObjectBuilder()
.add("apple", "red")
.add("banana", "yellow")
.build();
new JsonWriter(out).writeObject(jsonObject);

Only the first jsonObject is written to the output stream. If the call to first writeObject is commented then the second jsonObject is written to the stream as well.

Seems like the underlying OutputStream is closed along with writeObject call.



 Comments   
Comment by jitu [ 18/Feb/13 ]

Fixed in the repo. Will be part of b04 promotion.





[JSONP-2] java.lang.NoSuchMethodError: javax.json.stream.JsonGenerator.writeStartObject() [GF b69] Created: 02/Jan/13  Updated: 11/Jan/13  Resolved: 11/Jan/13

Status: Closed
Project: jsonp
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Major
Reporter: b_faissal Assignee: Unassigned
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

mac Os . JDK7


Tags: adoptajsr

 Description   

I've tried to play with some exemple given at http://java.net/projects/jsonp/sources/git/show/demos/jaxrs?rev=6897259e97eef8caeeea7ca4d9cc030177b465f4

But It seems like the latest version of JSONP is not integrated yet into glassfish 4 b69. This is the exception I'm facing :

[#|2013-01-02T02:47:08.886-0500|WARNING|glassfish4.0|javax.enterprise.web|_ThreadID=84;_ThreadName=http-listener-1(3);_TimeMillis=1357112828886;_LevelValue=900;|StandardWrapperValve[jsonServlet]: Servlet.service() for servlet jsonServlet threw exception
java.lang.NoSuchMethodError: javax.json.stream.JsonGenerator.writeStartObject()Ljavax/json/stream/JsonGenerator;
at mjug.adopjsr.jaxrs2.tasks.jsonServlet.writeWikiExample(jsonServlet.java:35)
at mjug.adopjsr.jaxrs2.tasks.jsonServlet.doGet(jsonServlet.java:30)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:687)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1682)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:342)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:160)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:732)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:671)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:176)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:357)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:260)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:172)
at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:164)
at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:175)
at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:265)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:200)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:134)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:112)
at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:781)
at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:112)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:115)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:55)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:135)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:578)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:558)
at java.lang.Thread.run(Thread.java:722)

#]

I've attached the servlet i've used to test the exemple.



 Comments   
Comment by b_faissal [ 02/Jan/13 ]

package mjug.adopjsr.jaxrs2.tasks;

import javax.json.Json;
import javax.json.JsonArrayBuilder;
import javax.json.JsonObject;
import javax.json.JsonObjectBuilder;
import javax.json.stream.JsonGenerator;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;

/**

  • Created with IntelliJ IDEA.
  • User: faissalboutaounte
  • Date: 13-01-01
  • Time: 15:35
  • To change this template use File | Settings | File Templates.
    */
    @WebServlet(name = "jsonServlet", urlPatterns = "/json")
    public class JsonServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

}

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException

{ writeWikiExample(response.getOutputStream()); }

private void writeWikiExample(OutputStream os) {
try (JsonGenerator gene = Json.createGenerator(os))

{ gene.writeStartObject() .write("firstName", "John") .write("lastName", "Smith") .write("age", 25) .writeStartObject("address") .write("streetAddress", "21 2nd Street") .write("city", "New York") .write("state", "NY") .write("postalCode", "10021") .writeEnd() .writeStartArray("phoneNumber") .writeStartObject() .write("type", "home") .write("number", "212 555-1234") .writeEnd() .writeStartObject() .write("type", "fax") .write("number", "646 555-4567") .writeEnd() .writeEnd() .writeEnd(); }

}
}

Comment by b_faissal [ 02/Jan/13 ]

I've also runned into this one :

[#|2013-01-02T03:06:56.065-0500|WARNING|glassfish4.0|javax.enterprise.web|_ThreadID=82;_ThreadName=http-listener-1(1);_TimeMillis=1357114016065;_LevelValue=900;|StandardWrapperValve[jsonServlet]: Servlet.service() for servlet jsonServlet threw exception
java.lang.InstantiationError: javax.json.JsonObjectBuilder
at mjug.adopjsr.jaxrs2.tasks.jsonServlet.doGet(jsonServlet.java:30)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:687)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1682)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:342)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:160)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:732)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:671)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:176)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:357)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:260)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:172)
at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:164)
at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:175)
at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:265)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:200)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:134)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:112)
at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:781)
at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:112)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:115)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:55)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:135)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:578)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:558)
at java.lang.Thread.run(Thread.java:722)

#]

the code is :

JsonObject value = new JsonObjectBuilder()
.add("firstName", "John")
.add("lastName", "Smith")
.add("age", 25)
.add("address", new JsonObjectBuilder()
.add("streetAddress", "21 2nd Street")
.add("city", "New York")
.add("state", "NY")
.add("postalCode", "10021"))
.add("phoneNumber", new JsonArrayBuilder()
.add(new JsonObjectBuilder()
.add("type", "home")
.add("number", "212 555-1234"))
.add(new JsonObjectBuilder()
.add("type", "fax")
.add("number", "646 555-4567")))
.build();
response.getWriter().write(value.toString());
response.getWriter().close();

Comment by jitu [ 08/Jan/13 ]

Try with glassfish 4 promoted build : b70

Comment by b_faissal [ 11/Jan/13 ]

Yes it works on b70

But I'm not able to resolve the issue





[JSONP-1] JSON not getting deserialized in a WebSocket endpoint Created: 24/Oct/12  Updated: 24/Oct/12

Status: Open
Project: jsonp
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Major
Reporter: arungupta Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

@Override
public MyMessage decode(String string) throws DecodeException

{ System.out.println("decoding: " + string); this.jsonObject = new JsonReader(new StringReader(string)).readObject(); System.out.println(jsonObject); return this; }

is throwing the following exception:

INFO: decoding: { }
SEVERE: javax.json.JsonException: Provider org.glassfish.json.JsonProviderImpl not found
at javax.json.spi.JsonProvider.provider(JsonProvider.java:101)
at javax.json.Json.createParser(Json.java:84)
at org.glassfish.jsonapi.JsonReaderImpl.<init>(JsonReaderImpl.java:58)
at javax.json.JsonReader.<init>(JsonReader.java:77)
at org.sample.MyMessage.decode(MyMessage.java:60)
at org.sample.MyMessage.decode(MyMessage.java:53)
at org.glassfish.tyrus.platform.WebSocketEndpointImpl.decodeMessage(WebSocketEndpointImpl.java:212)
at org.glassfish.tyrus.platform.WebSocketEndpointImpl.processMessage(WebSocketEndpointImpl.java:315)
at org.glassfish.tyrus.platform.WebSocketEndpointImpl.onMessage(WebSocketEndpointImpl.java:300)
at org.glassfish.tyrus.spi.grizzlyprovider.GrizzlyEndpoint.onMessage(GrizzlyEndpoint.java:82)
at org.glassfish.grizzly.websockets.DefaultWebSocket.onMessage(DefaultWebSocket.java:164)
at org.glassfish.grizzly.websockets.frametypes.TextFrameType.respond(TextFrameType.java:70)
at org.glassfish.grizzly.websockets.DataFrame.respond(DataFrame.java:104)
at org.glassfish.grizzly.websockets.WebSocketFilter.handleRead(WebSocketFilter.java:221)
at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:265)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:200)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:134)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:112)
at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:825)
at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:112)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:115)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:55)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:135)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:578)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:558)
at java.lang.Thread.run(Thread.java:722)
Caused by: java.lang.ClassNotFoundException: org.glassfish.json.JsonProviderImpl not found by org.glassfish.main.web.core [246]
at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1460)
at org.apache.felix.framework.BundleWiringImpl.access$400(BundleWiringImpl.java:72)
at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:1843)
at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
at javax.json.spi.JsonProvider.provider(JsonProvider.java:96)
... 27 more

SEVERE: at javax.json.spi.JsonProvider.provider(JsonProvider.java:101)
SEVERE: at javax.json.Json.createParser(Json.java:84)
SEVERE: at org.glassfish.jsonapi.JsonReaderImpl.<init>(JsonReaderImpl.java:58)
SEVERE: at javax.json.JsonReader.<init>(JsonReader.java:77)
SEVERE: at org.sample.MyMessage.decode(MyMessage.java:60)
SEVERE: at org.sample.MyMessage.decode(MyMessage.java:53)
SEVERE: at org.glassfish.tyrus.platform.WebSocketEndpointImpl.decodeMessage(WebSocketEndpointImpl.java:212)
SEVERE: at org.glassfish.tyrus.platform.WebSocketEndpointImpl.processMessage(WebSocketEndpointImpl.java:315)
SEVERE: at org.glassfish.tyrus.platform.WebSocketEndpointImpl.onMessage(WebSocketEndpointImpl.java:300)
SEVERE: at org.glassfish.tyrus.spi.grizzlyprovider.GrizzlyEndpoint.onMessage(GrizzlyEndpoint.java:82)
SEVERE: at org.glassfish.grizzly.websockets.DefaultWebSocket.onMessage(DefaultWebSocket.java:164)
SEVERE: at org.glassfish.grizzly.websockets.frametypes.TextFrameType.respond(TextFrameType.java:70)
SEVERE: at org.glassfish.grizzly.websockets.DataFrame.respond(DataFrame.java:104)
SEVERE: at org.glassfish.grizzly.websockets.WebSocketFilter.handleRead(WebSocketFilter.java:221)
SEVERE: at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
SEVERE: at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:265)
SEVERE: at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:200)
SEVERE: at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:134)
SEVERE: at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:112)
SEVERE: at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
SEVERE: at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:825)
SEVERE: at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:112)
SEVERE: at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:115)
SEVERE: at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:55)
SEVERE: at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:135)
SEVERE: at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:578)
SEVERE: at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:558)
SEVERE: at java.lang.Thread.run(Thread.java:722)
SEVERE: Caused by: java.lang.ClassNotFoundException: org.glassfish.json.JsonProviderImpl not found by org.glassfish.main.web.core [246]
SEVERE: at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1460)
SEVERE: at org.apache.felix.framework.BundleWiringImpl.access$400(BundleWiringImpl.java:72)
SEVERE: at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:1843)
SEVERE: at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
SEVERE: at javax.json.spi.JsonProvider.provider(JsonProvider.java:96)
SEVERE: ... 27 more






Generated at Sun Sep 25 01:26:20 UTC 2016 using JIRA 6.2.3#6260-sha1:63ef1d6dac3f4f4d7db4c1effd405ba38ccdc558.