1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package ch.qos.logback.core.util;
16
17 import java.math.BigDecimal;
18 import java.nio.ByteBuffer;
19 import java.nio.charset.StandardCharsets;
20
21
22
23
24
25
26
27
28 public final class DirectJson {
29 private static final int INITIAL_BUFFER_SIZE = 1024;
30 private static final byte QUOTE = '"';
31 private static final byte ENTRY_SEP = ':';
32 private static final byte KV_SEP = ',';
33 private static final byte DOT = '.';
34 private static final byte OPEN_OBJ = '{';
35 private static final byte CLOSE_OBJ = '}';
36 private static final byte OPEN_ARR = '[';
37 private static final byte CLOSE_ARR = ']';
38
39 private static final byte[] NEWLINE = new byte[] {
40 '\\',
41 'n',
42 };
43 private static final byte[] ESCAPE = new byte[] {
44 '\\',
45 '\\',
46 };
47 private static final byte[] LINEBREAK = new byte[] {
48 '\\',
49 'r',
50 };
51 private static final byte[] TAB = new byte[] {
52 '\\',
53 't',
54 };
55 private static final byte[] TRUE = new byte[] {
56 't',
57 'r',
58 'u',
59 'e'
60 };
61 private static final byte[] FALSE = new byte[] {
62 'f',
63 'a',
64 'l',
65 's',
66 'e'
67 };
68 private static final byte[] NULL = new byte[] {
69 'n',
70 'u',
71 'l',
72 'l'
73 };
74
75 private ByteBuffer buffer;
76
77 public DirectJson() {
78 buffer = ByteBuffer.allocateDirect(INITIAL_BUFFER_SIZE);
79 }
80
81 public void openObject() { buffer.put(OPEN_OBJ); }
82 public void openArray() { buffer.put(OPEN_ARR); }
83
84 public void openObject(String str) {
85 writeString(str);
86 writeEntrySep();
87 buffer.put(OPEN_OBJ);
88 }
89
90 public void openArray(String str) {
91 writeString(str);
92 writeEntrySep();
93 buffer.put(OPEN_ARR);
94 }
95
96 public void closeObject() {
97 var target = buffer.position() - 1;
98 if (',' == buffer.get(target)) {
99 buffer.put(target, CLOSE_OBJ);
100 } else {
101 buffer.put(CLOSE_OBJ);
102 }
103 }
104
105 public void closeArray() {
106 var target = buffer.position() - 1;
107 if (',' == buffer.get(target)) {
108 buffer.put(target, CLOSE_ARR);
109 } else {
110 buffer.put(CLOSE_ARR);
111 }
112 }
113
114 public void writeRaw(String str) {
115 for(int i = 0; i < str.length(); i++ ){
116 var chr = str.codePointAt(i);
117 switch (chr) {
118 case '\\':
119 buffer.put(ESCAPE);
120 break;
121 case '\n':
122 buffer.put(NEWLINE);
123 break;
124 case '\r':
125 buffer.put(LINEBREAK);
126 break;
127 case '\t':
128 buffer.put(TAB);
129 break;
130 default:
131 if (chr >= 0x80 && chr <= 0x10FFFF) {
132 buffer.put(String.valueOf(str.charAt(i)).getBytes());
133 } else if (chr > 0x1F) buffer.put((byte) chr);
134 }
135
136 }
137 }
138
139 public void writeRaw(char chr) { buffer.put((byte) chr); }
140 public void writeRaw(byte[] chr) { buffer.put(chr); }
141
142 public void writeQuote() { buffer.put(QUOTE); }
143 public void writeString(String str) {
144 checkSpace(str.length() + 3);
145 buffer.put(QUOTE);
146 writeRaw(str);
147 buffer.put(QUOTE);
148 buffer.put(KV_SEP);
149 }
150 public void writeSep() { buffer.put(KV_SEP); }
151
152 public void writeNumberRaw(final long data) {
153 final int pos = buffer.position();
154 final int sz = (int) Math.log10(data) + 1;
155 long dataPointer = data;
156
157 for (int i = sz - 1; i >= 0; i--) {
158 byte chr = (byte) (dataPointer % 10);
159 dataPointer = dataPointer / 10;
160 chr += 48;
161 buffer.put(pos + i, chr);
162 }
163
164 buffer.position(pos + sz);
165 }
166
167 public void writeNumber(final long data) {
168 final int pos = buffer.position();
169 final int sz = data == 0 ? 1 : (int) Math.log10(data) + 1;
170 long dataPointer = data;
171
172 for (int i = sz - 1; i >= 0; i--) {
173 byte chr = (byte) (dataPointer % 10);
174 dataPointer = dataPointer / 10;
175 chr += 48;
176 buffer.put(pos + i, chr);
177 }
178
179 buffer.position(pos + sz);
180 buffer.put(KV_SEP);
181 }
182
183 public void writeNumber(final double data) {
184 int pos = buffer.position();
185 long whole = (long) data;
186 final int sz = (int) Math.log10(whole) + 1;
187
188 for (int i = sz - 1; i >= 0; i--) {
189 byte chr = (byte) (whole % 10);
190 whole = whole / 10;
191 chr += 48;
192 buffer.put(pos + i, chr);
193 }
194 buffer.position(pos + sz);
195 buffer.put(DOT);
196 pos = buffer.position();
197 BigDecimal fractional = BigDecimal.valueOf(data).remainder(BigDecimal.ONE);
198 int decs = 0;
199 while (!fractional.equals(BigDecimal.ZERO)) {
200 fractional = fractional.movePointRight(1);
201 byte chr = (byte) (fractional.intValue() + 48);
202 fractional = fractional.remainder(BigDecimal.ONE);
203 decs += 1;
204 buffer.put(chr);
205 }
206
207 buffer.position(pos + decs);
208 buffer.put(KV_SEP);
209 }
210
211 public void writeEntrySep() { buffer.put(buffer.position() - 1, ENTRY_SEP); }
212
213 public void writeStringValue(String key, String value) {
214 writeString(key);
215 writeEntrySep();
216 writeString(value);
217 }
218
219 public void writeNumberValue(String key, long value) {
220 writeString(key);
221 writeEntrySep();
222 writeNumber(value);
223 }
224
225 public void writeNumberValue(String key, double value) {
226 writeString(key);
227 writeEntrySep();
228 writeNumber(value);
229 }
230
231 public void writeBoolean(boolean value) {
232 buffer.put(value ? TRUE : FALSE);
233 buffer.put(KV_SEP);
234 }
235
236 public void writeNull() {
237 buffer.put(NULL);
238 buffer.put(KV_SEP);
239 }
240
241 public void checkSpace(int size) {
242 if (buffer.position() + size >= buffer.capacity()) {
243 var newSize = (buffer.capacity() + size) * 2;
244 ByteBuffer newBuffer = ByteBuffer.allocateDirect(newSize);
245 buffer.flip();
246 newBuffer.put(buffer);
247 buffer = newBuffer;
248 }
249 }
250
251 public byte[] flush() {
252 byte[] result = new byte[buffer.position()];
253 buffer.flip();
254 buffer.get(result);
255 buffer.clear();
256
257 return result;
258 }
259 }