Skip to content

Commit ef54ae7

Browse files
committed
add PreciseFloat support
1 parent 57e133e commit ef54ae7

8 files changed

Lines changed: 113 additions & 21 deletions

File tree

src/main/java/com/jsoniter/CodegenImplNative.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.jsoniter;
22

33
import com.jsoniter.any.Any;
4+
import com.jsoniter.spi.JsoniterSpi;
45
import com.jsoniter.spi.TypeLiteral;
56

67
import java.lang.reflect.ParameterizedType;

src/main/java/com/jsoniter/datetime/JdkDatetimeSupport.java renamed to src/main/java/com/jsoniter/extra/JdkDatetimeSupport.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.jsoniter.datetime;
1+
package com.jsoniter.extra;
22

33
import com.jsoniter.JsonException;
44
import com.jsoniter.JsonIterator;
@@ -14,7 +14,7 @@
1414
import java.util.Date;
1515

1616
/**
17-
* this is just an example
17+
* there is no official way to encode/decode datetime, this is just an option for you
1818
*/
1919
public class JdkDatetimeSupport {
2020

@@ -26,7 +26,10 @@ protected SimpleDateFormat initialValue() {
2626
}
2727
};
2828

29-
public static void enable(String pattern) {
29+
public static synchronized void enable(String pattern) {
30+
if (JdkDatetimeSupport.pattern != null) {
31+
throw new JsonException("JdkDatetimeSupport.enable can only be called once");
32+
}
3033
JdkDatetimeSupport.pattern = pattern;
3134
JsoniterSpi.registerTypeEncoder(Date.class, new Encoder() {
3235
@Override
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package com.jsoniter.extra;
2+
3+
import com.jsoniter.JsonException;
4+
import com.jsoniter.any.Any;
5+
import com.jsoniter.output.JsonStream;
6+
import com.jsoniter.spi.Encoder;
7+
import com.jsoniter.spi.JsoniterSpi;
8+
9+
import java.io.IOException;
10+
11+
/**
12+
* default float/double encoding will keep 6 decimal places
13+
* enable precise encoding will use JDK toString to be precise
14+
*/
15+
public class PreciseFloatSupport {
16+
private static boolean enabled;
17+
18+
public static synchronized void enable() {
19+
if (enabled) {
20+
throw new JsonException("PreciseFloatSupport.enable can only be called once");
21+
}
22+
enabled = true;
23+
JsoniterSpi.registerTypeEncoder(Double.class, new Encoder() {
24+
@Override
25+
public void encode(Object obj, JsonStream stream) throws IOException {
26+
stream.writeRaw(obj.toString());
27+
}
28+
29+
@Override
30+
public Any wrap(Object obj) {
31+
Double number = (Double) obj;
32+
return Any.wrap(number.doubleValue());
33+
}
34+
});
35+
JsoniterSpi.registerTypeEncoder(double.class, new Encoder.DoubleEncoder() {
36+
@Override
37+
public void encodeDouble(double obj, JsonStream stream) throws IOException {
38+
stream.writeRaw(Double.toString(obj));
39+
}
40+
});
41+
JsoniterSpi.registerTypeEncoder(Float.class, new Encoder() {
42+
@Override
43+
public void encode(Object obj, JsonStream stream) throws IOException {
44+
stream.writeRaw(obj.toString());
45+
}
46+
47+
@Override
48+
public Any wrap(Object obj) {
49+
Float number = (Float) obj;
50+
return Any.wrap(number.floatValue());
51+
}
52+
});
53+
JsoniterSpi.registerTypeEncoder(float.class, new Encoder.FloatEncoder() {
54+
@Override
55+
public void encodeFloat(float obj, JsonStream stream) throws IOException {
56+
stream.writeRaw(Float.toString(obj));
57+
}
58+
});
59+
}
60+
}

src/main/java/com/jsoniter/output/CodegenImplNative.java

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -269,18 +269,20 @@ public static void genWriteOp(CodegenResult ctx, String code, Type valueType, bo
269269
}
270270

271271
public static void genWriteOp(CodegenResult ctx, String code, Type valueType, boolean isNullable, boolean isCollectionValueNullable) {
272-
if (!isNullable && String.class == valueType) {
273-
ctx.buffer('"');
274-
ctx.append(String.format("com.jsoniter.output.CodegenAccess.writeStringWithoutQuote((java.lang.String)%s, stream);", code));
275-
ctx.buffer('"');
276-
return;
277-
}
278-
if (NATIVE_ENCODERS.containsKey(valueType)) {
279-
ctx.append(String.format("stream.writeVal((%s)%s);", getTypeName(valueType), code));
280-
return;
272+
String cacheKey = TypeLiteral.create(valueType).getEncoderCacheKey();
273+
if (JsoniterSpi.getEncoder(cacheKey) == null) {
274+
if (!isNullable && String.class == valueType) {
275+
ctx.buffer('"');
276+
ctx.append(String.format("com.jsoniter.output.CodegenAccess.writeStringWithoutQuote((java.lang.String)%s, stream);", code));
277+
ctx.buffer('"');
278+
return;
279+
}
280+
if (NATIVE_ENCODERS.containsKey(valueType)) {
281+
ctx.append(String.format("stream.writeVal((%s)%s);", getTypeName(valueType), code));
282+
return;
283+
}
281284
}
282285

283-
String cacheKey = TypeLiteral.create(valueType).getEncoderCacheKey();
284286
if (!isCollectionValueNullable) {
285287
cacheKey = cacheKey + "__value_not_nullable";
286288
}
@@ -324,9 +326,4 @@ public static CodegenResult genEnum(Class clazz) {
324326
ctx.append("}");
325327
return ctx;
326328
}
327-
328-
private static void append(StringBuilder lines, String str) {
329-
lines.append(str);
330-
lines.append("\n");
331-
}
332329
}

src/main/java/com/jsoniter/output/CodegenImplObject.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ private static int appendComma(CodegenResult ctx, int notFirst) {
104104
if (notFirst == 1) { // definitely not first
105105
ctx.buffer(',');
106106
} else if (notFirst == 2) { // maybe not first, previous field is omitNull
107-
ctx.append("if (notFirst) { stream.write(','); notFirst = true; }");
107+
ctx.append("if (notFirst) { stream.write(','); } else { notFirst = true; }");
108108
} else { // this is the first, do not write comma
109109
notFirst = 1;
110110
}

src/main/java/com/jsoniter/output/DynamicCodegen.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ public static Encoder gen(Class clazz, String cacheKey, CodegenResult source) th
3030
append(lines, CodegenResult.bufferToWriteOp(source.epilogue));
3131
}
3232
append(lines, "}");
33-
System.out.println(lines.toString());
3433
CtMethod interfaceMethod = CtNewMethod.make(lines.toString(), ctClass);
3534
ctClass.addMethod(interfaceMethod);
3635
return (Encoder) ctClass.toClass().newInstance();

src/test/java/com/jsoniter/datetime/TestJdkDatetime.java renamed to src/test/java/com/jsoniter/extra/TestJdkDatetime.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
package com.jsoniter.datetime;
1+
package com.jsoniter.extra;
22

33
import com.jsoniter.JsonIterator;
4+
import com.jsoniter.extra.JdkDatetimeSupport;
45
import com.jsoniter.output.JsonStream;
56
import junit.framework.TestCase;
67

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.jsoniter.extra;
2+
3+
import com.jsoniter.output.JsonStream;
4+
import junit.framework.TestCase;
5+
6+
public class TestPreciseFloat extends TestCase {
7+
static {
8+
PreciseFloatSupport.enable();
9+
}
10+
11+
public void test_direct_encode() {
12+
assertEquals("0.123456789", JsonStream.serialize(0.123456789d));
13+
assertEquals("0.12345678", JsonStream.serialize(0.12345678f));
14+
}
15+
16+
public static class TestObject1 {
17+
public Double field1;
18+
public double field2;
19+
public Float field3;
20+
public float field4;
21+
}
22+
23+
public void test_indirect_encode() {
24+
TestObject1 obj = new TestObject1();
25+
obj.field1 = 0.12345678d;
26+
obj.field2 = 0.12345678d;
27+
obj.field3 = 0.12345678f;
28+
obj.field4 = 0.12345678f;
29+
assertEquals("{\"field1\":0.12345678,\"field2\":0.12345678,\"field3\":0.12345678,\"field4\":0.12345678}", JsonStream.serialize(obj));
30+
}
31+
}

0 commit comments

Comments
 (0)