Skip to content

Commit 103d13b

Browse files
committed
json
1 parent 0e2af07 commit 103d13b

File tree

11 files changed

+246
-33
lines changed

11 files changed

+246
-33
lines changed
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.api.common;
7+
8+
import java.nio.ByteBuffer;
9+
import java.util.Base64;
10+
import java.util.List;
11+
12+
/** Package-private utility for JSON encoding. */
13+
final class JsonUtil {
14+
15+
private static final char[] HEX_DIGITS = {
16+
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
17+
};
18+
19+
@SuppressWarnings("unchecked")
20+
static void appendJsonValue(StringBuilder sb, Value<?> value) {
21+
switch (value.getType()) {
22+
case STRING:
23+
appendJsonString(sb, (String) value.getValue());
24+
break;
25+
case LONG:
26+
sb.append(value.getValue());
27+
break;
28+
case DOUBLE:
29+
appendJsonDouble(sb, (Double) value.getValue());
30+
break;
31+
case BOOLEAN:
32+
sb.append(value.getValue());
33+
break;
34+
case ARRAY:
35+
appendJsonArray(sb, (List<Value<?>>) value.getValue());
36+
break;
37+
case KEY_VALUE_LIST:
38+
appendJsonKeyValueList(sb, (List<KeyValue>) value.getValue());
39+
break;
40+
case BYTES:
41+
appendJsonBytes(sb, (ByteBuffer) value.getValue());
42+
break;
43+
case EMPTY:
44+
sb.append("null");
45+
break;
46+
}
47+
}
48+
49+
static void appendJsonString(StringBuilder sb, String value) {
50+
sb.append('"');
51+
for (int i = 0; i < value.length(); i++) {
52+
char c = value.charAt(i);
53+
switch (c) {
54+
case '"':
55+
sb.append("\\\"");
56+
break;
57+
case '\\':
58+
sb.append("\\\\");
59+
break;
60+
case '\b':
61+
sb.append("\\b");
62+
break;
63+
case '\f':
64+
sb.append("\\f");
65+
break;
66+
case '\n':
67+
sb.append("\\n");
68+
break;
69+
case '\r':
70+
sb.append("\\r");
71+
break;
72+
case '\t':
73+
sb.append("\\t");
74+
break;
75+
default:
76+
if (c < 0x20) {
77+
// Control characters must be escaped as \\uXXXX
78+
sb.append("\\u");
79+
sb.append(HEX_DIGITS[(c >> 12) & 0xF]);
80+
sb.append(HEX_DIGITS[(c >> 8) & 0xF]);
81+
sb.append(HEX_DIGITS[(c >> 4) & 0xF]);
82+
sb.append(HEX_DIGITS[c & 0xF]);
83+
} else {
84+
sb.append(c);
85+
}
86+
}
87+
}
88+
sb.append('"');
89+
}
90+
91+
private static void appendJsonDouble(StringBuilder sb, double value) {
92+
if (Double.isNaN(value)) {
93+
// Encoding as string to match ProtoJSON: https://protobuf.dev/programming-guides/json/
94+
sb.append("\"NaN\"");
95+
} else if (Double.isInfinite(value)) {
96+
// Encoding as string to match ProtoJSON: https://protobuf.dev/programming-guides/json/
97+
sb.append(value > 0 ? "\"Infinity\"" : "\"-Infinity\"");
98+
} else {
99+
sb.append(value);
100+
}
101+
}
102+
103+
private static void appendJsonBytes(StringBuilder sb, ByteBuffer value) {
104+
// Encoding as base64 to match ProtoJSON: https://protobuf.dev/programming-guides/json/
105+
byte[] bytes = new byte[value.remaining()];
106+
value.duplicate().get(bytes);
107+
sb.append('"').append(Base64.getEncoder().encodeToString(bytes)).append('"');
108+
}
109+
110+
private static void appendJsonArray(StringBuilder sb, List<Value<?>> values) {
111+
sb.append('[');
112+
for (int i = 0; i < values.size(); i++) {
113+
if (i > 0) {
114+
sb.append(',');
115+
}
116+
appendJsonValue(sb, values.get(i));
117+
}
118+
sb.append(']');
119+
}
120+
121+
private static void appendJsonKeyValueList(StringBuilder sb, List<KeyValue> values) {
122+
sb.append('{');
123+
for (int i = 0; i < values.size(); i++) {
124+
if (i > 0) {
125+
sb.append(',');
126+
}
127+
KeyValue kv = values.get(i);
128+
appendJsonString(sb, kv.getKey());
129+
sb.append(':');
130+
appendJsonValue(sb, kv.getValue());
131+
}
132+
sb.append('}');
133+
}
134+
135+
private JsonUtil() {}
136+
}

api/all/src/main/java/io/opentelemetry/api/common/KeyValueList.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55

66
package io.opentelemetry.api.common;
77

8-
import static java.util.stream.Collectors.joining;
9-
108
import java.util.ArrayList;
119
import java.util.Arrays;
1210
import java.util.Collections;
@@ -50,9 +48,9 @@ public List<KeyValue> getValue() {
5048

5149
@Override
5250
public String asString() {
53-
return value.stream()
54-
.map(item -> item.getKey() + "=" + item.getValue().asString())
55-
.collect(joining(", ", "[", "]"));
51+
StringBuilder sb = new StringBuilder();
52+
JsonUtil.appendJsonValue(sb, this);
53+
return sb.toString();
5654
}
5755

5856
@Override

api/all/src/main/java/io/opentelemetry/api/common/ValueArray.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55

66
package io.opentelemetry.api.common;
77

8-
import static java.util.stream.Collectors.joining;
9-
108
import java.util.ArrayList;
119
import java.util.Arrays;
1210
import java.util.Collections;
@@ -44,7 +42,9 @@ public List<Value<?>> getValue() {
4442

4543
@Override
4644
public String asString() {
47-
return value.stream().map(Value::asString).collect(joining(", ", "[", "]"));
45+
StringBuilder sb = new StringBuilder();
46+
JsonUtil.appendJsonValue(sb, this);
47+
return sb.toString();
4848
}
4949

5050
@Override

api/all/src/main/java/io/opentelemetry/api/common/ValueBoolean.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ public Boolean getValue() {
3131

3232
@Override
3333
public String asString() {
34-
return String.valueOf(value);
34+
StringBuilder sb = new StringBuilder();
35+
JsonUtil.appendJsonValue(sb, this);
36+
return sb.toString();
3537
}
3638

3739
@Override

api/all/src/main/java/io/opentelemetry/api/common/ValueBytes.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
import java.nio.ByteBuffer;
99
import java.util.Arrays;
10-
import java.util.Base64;
1110
import java.util.Objects;
1211

1312
final class ValueBytes implements Value<ByteBuffer> {
@@ -35,7 +34,9 @@ public ByteBuffer getValue() {
3534

3635
@Override
3736
public String asString() {
38-
return Base64.getEncoder().encodeToString(raw);
37+
StringBuilder sb = new StringBuilder();
38+
JsonUtil.appendJsonValue(sb, this);
39+
return sb.toString();
3940
}
4041

4142
@Override

api/all/src/main/java/io/opentelemetry/api/common/ValueDouble.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ public Double getValue() {
3131

3232
@Override
3333
public String asString() {
34-
return String.valueOf(value);
34+
StringBuilder sb = new StringBuilder();
35+
JsonUtil.appendJsonValue(sb, this);
36+
return sb.toString();
3537
}
3638

3739
@Override

api/all/src/main/java/io/opentelemetry/api/common/ValueEmpty.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public Void getValue() {
2727

2828
@Override
2929
public String asString() {
30-
return "";
30+
return "null";
3131
}
3232

3333
@Override

api/all/src/main/java/io/opentelemetry/api/common/ValueLong.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ public Long getValue() {
3131

3232
@Override
3333
public String asString() {
34-
return String.valueOf(value);
34+
StringBuilder sb = new StringBuilder();
35+
JsonUtil.appendJsonValue(sb, this);
36+
return sb.toString();
3537
}
3638

3739
@Override

api/all/src/main/java/io/opentelemetry/api/common/ValueString.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ public String getValue() {
3232

3333
@Override
3434
public String asString() {
35-
return value;
35+
StringBuilder sb = new StringBuilder();
36+
JsonUtil.appendJsonValue(sb, this);
37+
return sb.toString();
3638
}
3739

3840
@Override

0 commit comments

Comments
 (0)