From 924357730eb6a097990f97dfb5c37c73b0630696 Mon Sep 17 00:00:00 2001 From: Looly Date: Sun, 29 Sep 2024 01:15:23 +0800 Subject: [PATCH] fix code and add UTF8OutputStreamWriter --- .../io/stream/UTF8OutputStreamWriter.java | 160 ++++++++++++++++++ hutool-json/pom.xml | 1 - .../hutool/json/engine/HutoolJSONEngine.java | 15 +- .../hutool/json/engine/JSONEngine.java | 18 +- .../json/engine/fastjson/FastJSON2Engine.java | 58 +++++-- .../hutool/json/engine/gson/GsonEngine.java | 13 +- .../json/engine/jackson/JacksonEngine.java | 16 +- .../json/engine/moshi/DateMoshiAdapter.java | 5 +- .../hutool/json/engine/moshi/MoshiEngine.java | 49 ++++-- .../engine/moshi/TemporalMoshiAdapter.java | 4 +- .../engine/moshi/TimeZoneMoshiAdapter.java | 1 - .../json/engine/BeanWithLocalDateTime.java | 28 +++ .../json/engine/JSONEngineFactoryTest.java | 13 +- .../dromara/hutool/json/engine/MoshiTest.java | 39 +++++ .../{ => serializer}/CustomSerializeTest.java | 7 +- 15 files changed, 360 insertions(+), 67 deletions(-) create mode 100644 hutool-core/src/main/java/org/dromara/hutool/core/io/stream/UTF8OutputStreamWriter.java create mode 100644 hutool-json/src/test/java/org/dromara/hutool/json/engine/BeanWithLocalDateTime.java create mode 100644 hutool-json/src/test/java/org/dromara/hutool/json/engine/MoshiTest.java rename hutool-json/src/test/java/org/dromara/hutool/json/{ => serializer}/CustomSerializeTest.java (91%) diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/io/stream/UTF8OutputStreamWriter.java b/hutool-core/src/main/java/org/dromara/hutool/core/io/stream/UTF8OutputStreamWriter.java new file mode 100644 index 000000000..ae53435f4 --- /dev/null +++ b/hutool-core/src/main/java/org/dromara/hutool/core/io/stream/UTF8OutputStreamWriter.java @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2024 Hutool Team and hutool.cn + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.dromara.hutool.core.io.stream; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.Writer; + +/** + *

This class is used to write a stream of chars as a stream of + * bytes using the UTF8 encoding. It assumes that the underlying + * output stream is buffered or does not need additional buffering.

+ * + *

It is more efficient than using a {@link java.io.OutputStreamWriter} + * because it does not need to be wrapped in a + * {@link java.io.BufferedWriter}. Creating multiple instances + * of {@link java.io.BufferedWriter} has been shown to be very expensive.

+ * + *

copy from: {@code com.sun.xml.internal.stream.writers.UTF8OutputStreamWriter}

+ * + * @author Santiago.PericasGeertsen@sun.com + */ +public class UTF8OutputStreamWriter extends Writer { + + /** + * Undelying output stream. This class assumes that this + * output stream does not need buffering. + */ + private final OutputStream out; + + /** + * Java represents chars that are not in the Basic Multilingual + * Plane (BMP) in UTF-16. This int stores the first code unit + * for a code point encoded in two UTF-16 code units. + */ + int lastUTF16CodePoint = 0; + + /** + * Creates a new UTF8OutputStreamWriter. + * + * @param out The underlying output stream. + */ + public UTF8OutputStreamWriter(final OutputStream out) { + this.out = out; + } + + @Override + public void write(final int c) throws IOException { + // Check in we are encoding at high and low surrogates + if (lastUTF16CodePoint != 0) { + final int uc = + (((lastUTF16CodePoint & 0x3ff) << 10) | (c & 0x3ff)) + 0x10000; + + out.write(0xF0 | (uc >> 18)); + out.write(0x80 | ((uc >> 12) & 0x3F)); + out.write(0x80 | ((uc >> 6) & 0x3F)); + out.write(0x80 | (uc & 0x3F)); + + lastUTF16CodePoint = 0; + return; + } + + // Otherwise, encode char as defined in UTF-8 + if (c < 0x80) { + // 1 byte, 7 bits + out.write((int) c); + } else if (c < 0x800) { + // 2 bytes, 11 bits + out.write(0xC0 | (c >> 6)); // first 5 + out.write(0x80 | (c & 0x3F)); // second 6 + } else if (c <= '\uFFFF') { + if (!isHighSurrogate(c) && !isLowSurrogate(c)) { + // 3 bytes, 16 bits + out.write(0xE0 | (c >> 12)); // first 4 + out.write(0x80 | ((c >> 6) & 0x3F)); // second 6 + out.write(0x80 | (c & 0x3F)); // third 6 + } else { + lastUTF16CodePoint = c; + } + } + } + + @SuppressWarnings("ForLoopReplaceableByForEach") + @Override + public void write(final char[] cbuf) throws IOException { + for (int i = 0; i < cbuf.length; i++) { + write(cbuf[i]); + } + } + + @Override + public void write(final char[] cbuf, final int off, final int len) throws IOException { + for (int i = 0; i < len; i++) { + write(cbuf[off + i]); + } + } + + @Override + public void write(final String str) throws IOException { + final int len = str.length(); + for (int i = 0; i < len; i++) { + write(str.charAt(i)); + } + } + + @Override + public void write(final String str, final int off, final int len) throws IOException { + for (int i = 0; i < len; i++) { + write(str.charAt(off + i)); + } + } + + @Override + public void flush() throws IOException { + out.flush(); + } + + @Override + public void close() throws IOException { + if (lastUTF16CodePoint != 0) { + throw new IllegalStateException("Attempting to close a UTF8OutputStreamWriter" + + " while awaiting for a UTF-16 code unit"); + } + out.close(); + } + + /** + * Returns whether the given character is a high surrogate + * + * @param c The character to check. + * @return true if the character is a high surrogate. + */ + private static boolean isHighSurrogate(final int c) { + return (0xD800 <= c && c <= 0xDBFF); + } + + /** + * Returns whether the given character is a low surrogate + * + * @param c The character to check. + * @return true if the character is a low surrogate. + */ + private static boolean isLowSurrogate(final int c) { + return (0xDC00 <= c && c <= 0xDFFF); + } +} diff --git a/hutool-json/pom.xml b/hutool-json/pom.xml index e0aa29f23..cf24ecc3c 100755 --- a/hutool-json/pom.xml +++ b/hutool-json/pom.xml @@ -140,7 +140,6 @@ src/test/jmh - my-resources diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/engine/HutoolJSONEngine.java b/hutool-json/src/main/java/org/dromara/hutool/json/engine/HutoolJSONEngine.java index 4ccff81d1..b9def36f0 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/engine/HutoolJSONEngine.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/engine/HutoolJSONEngine.java @@ -16,13 +16,14 @@ package org.dromara.hutool.json.engine; +import org.dromara.hutool.core.io.stream.UTF8OutputStreamWriter; import org.dromara.hutool.core.util.ObjUtil; import org.dromara.hutool.json.JSON; import org.dromara.hutool.json.JSONConfig; import org.dromara.hutool.json.JSONFactory; +import java.io.OutputStream; import java.io.Reader; -import java.io.Writer; import java.lang.reflect.Type; /** @@ -36,13 +37,21 @@ public class HutoolJSONEngine extends AbstractJSONEngine { private JSONFactory jsonFactory; @Override - public void serialize(final Object bean, final Writer writer) { + public void serialize(final Object bean, final OutputStream out) { initEngine(); final JSON json = jsonFactory.parse(bean); - json.write(jsonFactory.ofWriter(writer, + json.write(jsonFactory.ofWriter(new UTF8OutputStreamWriter(out), ObjUtil.defaultIfNull(this.config, JSONEngineConfig::isPrettyPrint, false))); } + @Override + public String toJsonString(final Object bean) { + initEngine(); + final JSON json = jsonFactory.parse(bean); + final boolean isPrettyPrint = ObjUtil.defaultIfNull(this.config, JSONEngineConfig::isPrettyPrint, false); + return isPrettyPrint ? json.toStringPretty() : json.toString(); + } + @Override public T deserialize(final Reader reader, final Object type) { initEngine(); diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/engine/JSONEngine.java b/hutool-json/src/main/java/org/dromara/hutool/json/engine/JSONEngine.java index 6398c3a64..3da51ae5b 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/engine/JSONEngine.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/engine/JSONEngine.java @@ -16,10 +16,10 @@ package org.dromara.hutool.json.engine; -import java.io.Reader; -import java.io.StringReader; -import java.io.StringWriter; -import java.io.Writer; +import org.dromara.hutool.core.io.stream.FastByteArrayOutputStream; +import org.dromara.hutool.core.util.CharsetUtil; + +import java.io.*; /** * JSON引擎实现 @@ -43,9 +43,9 @@ public interface JSONEngine { * 生成JSON数据(序列化),用于将指定的Bean对象通过Writer写出为JSON字符串 * * @param bean Java Bean(POJO)对象 - * @param writer 写出到的Writer + * @param out 写出到的{@link OutputStream} */ - void serialize(Object bean, Writer writer); + void serialize(Object bean, OutputStream out); /** * 解析JSON数据(反序列化),用于从Reader中读取JSON字符串,转换为Bean对象
@@ -65,9 +65,9 @@ public interface JSONEngine { * @return JSON字符串 */ default String toJsonString(final Object bean) { - final StringWriter stringWriter = new StringWriter(); - serialize(bean, stringWriter); - return stringWriter.toString(); + final FastByteArrayOutputStream out = new FastByteArrayOutputStream(); + serialize(bean, out); + return out.toString(CharsetUtil.UTF_8); } /** diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/engine/fastjson/FastJSON2Engine.java b/hutool-json/src/main/java/org/dromara/hutool/json/engine/fastjson/FastJSON2Engine.java index 1e2b80cce..67426272b 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/engine/fastjson/FastJSON2Engine.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/engine/fastjson/FastJSON2Engine.java @@ -22,13 +22,16 @@ import com.alibaba.fastjson2.JSONWriter; import com.alibaba.fastjson2.reader.ObjectReader; import com.alibaba.fastjson2.writer.ObjectWriter; import org.dromara.hutool.core.collection.ListUtil; +import org.dromara.hutool.core.io.IORuntimeException; +import org.dromara.hutool.core.io.IoUtil; import org.dromara.hutool.core.lang.Assert; import org.dromara.hutool.core.util.ObjUtil; import org.dromara.hutool.json.engine.AbstractJSONEngine; import org.dromara.hutool.json.engine.JSONEngineConfig; +import java.io.IOException; +import java.io.OutputStream; import java.io.Reader; -import java.io.Writer; import java.lang.reflect.Type; import java.util.List; @@ -53,19 +56,26 @@ public class FastJSON2Engine extends AbstractJSONEngine { } @Override - public void serialize(final Object bean, final Writer writer) { - initEngine(); - try (final JSONWriter jsonWriter = JSONWriter.of(this.writerContext)) { - if (bean == null) { - jsonWriter.writeNull(); - } else { - jsonWriter.setRootObject(bean); - final Class valueClass = bean.getClass(); - final ObjectWriter objectWriter = this.writerContext.getObjectWriter(valueClass, valueClass); - objectWriter.write(jsonWriter, bean, null, null, 0); - } + public void serialize(final Object bean, final OutputStream out) { + JSONWriter jsonWriter = null; + try{ + jsonWriter = toJsonWriter(bean); + jsonWriter.flushTo(out); + } catch (final IOException e){ + throw new IORuntimeException(e); + } finally { + IoUtil.closeQuietly(jsonWriter); + } + } - jsonWriter.flushTo(writer); + @Override + public String toJsonString(final Object bean) { + JSONWriter jsonWriter = null; + try{ + jsonWriter = toJsonWriter(bean); + return jsonWriter.toString(); + } finally { + IoUtil.closeQuietly(jsonWriter); } } @@ -116,4 +126,26 @@ public class FastJSON2Engine extends AbstractJSONEngine { this.writerContext.setDateFormat(ObjUtil.defaultIfNull(config.getDateFormat(), "millis")); } } + + /** + * 将对象转为JSONWriter + * + * @param bean 对象 + * @return JSONWriter + */ + private JSONWriter toJsonWriter(final Object bean) { + initEngine(); + + final JSONWriter jsonWriter = JSONWriter.of(this.writerContext); + if (bean == null) { + jsonWriter.writeNull(); + } else { + jsonWriter.setRootObject(bean); + final Class valueClass = bean.getClass(); + final ObjectWriter objectWriter = this.writerContext.getObjectWriter(valueClass, valueClass); + objectWriter.write(jsonWriter, bean, null, null, 0); + } + + return jsonWriter; + } } diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/engine/gson/GsonEngine.java b/hutool-json/src/main/java/org/dromara/hutool/json/engine/gson/GsonEngine.java index f0adab467..f6d6de0d1 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/engine/gson/GsonEngine.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/engine/gson/GsonEngine.java @@ -18,6 +18,7 @@ package org.dromara.hutool.json.engine.gson; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import org.dromara.hutool.core.io.stream.UTF8OutputStreamWriter; import org.dromara.hutool.core.lang.Assert; import org.dromara.hutool.core.lang.wrapper.Wrapper; import org.dromara.hutool.core.util.ObjUtil; @@ -25,8 +26,8 @@ import org.dromara.hutool.json.JSONException; import org.dromara.hutool.json.engine.AbstractJSONEngine; import org.dromara.hutool.json.engine.JSONEngineConfig; +import java.io.OutputStream; import java.io.Reader; -import java.io.Writer; import java.lang.reflect.Type; import java.time.LocalDate; import java.time.LocalDateTime; @@ -60,9 +61,15 @@ public class GsonEngine extends AbstractJSONEngine implements Wrapper { } @Override - public void serialize(final Object bean, final Writer writer) { + public void serialize(final Object bean, final OutputStream out) { initEngine(); - gson.toJson(bean, writer); + gson.toJson(bean, new UTF8OutputStreamWriter(out)); + } + + @Override + public String toJsonString(final Object bean) { + initEngine(); + return gson.toJson(bean); } @SuppressWarnings("unchecked") diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/engine/jackson/JacksonEngine.java b/hutool-json/src/main/java/org/dromara/hutool/json/engine/jackson/JacksonEngine.java index e1f2c9506..50aee205c 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/engine/jackson/JacksonEngine.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/engine/jackson/JacksonEngine.java @@ -35,8 +35,8 @@ import org.dromara.hutool.json.engine.AbstractJSONEngine; import org.dromara.hutool.json.engine.JSONEngineConfig; import java.io.IOException; +import java.io.OutputStream; import java.io.Reader; -import java.io.Writer; /** * Jackson引擎 @@ -68,10 +68,20 @@ public class JacksonEngine extends AbstractJSONEngine implements Wrapper { }else{ jsonWriter.value(DateUtil.format(date, dateFormat)); } - jsonWriter.flush(); } @Override public Date fromJson(final JsonReader jsonReader) throws IOException { + if(jsonReader.peek() == JsonReader.Token.NULL){ + return jsonReader.nextNull(); + } + return StrUtil.isEmpty(dateFormat) ? DateUtil.date(jsonReader.nextLong()) : DateUtil.parse(jsonReader.nextString(), dateFormat); diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/engine/moshi/MoshiEngine.java b/hutool-json/src/main/java/org/dromara/hutool/json/engine/moshi/MoshiEngine.java index a26b81630..04ede274a 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/engine/moshi/MoshiEngine.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/engine/moshi/MoshiEngine.java @@ -22,7 +22,6 @@ import okio.BufferedSink; import okio.BufferedSource; import okio.Okio; import org.dromara.hutool.core.io.stream.ReaderInputStream; -import org.dromara.hutool.core.io.stream.WriterOutputStream; import org.dromara.hutool.core.lang.Assert; import org.dromara.hutool.core.lang.wrapper.Wrapper; import org.dromara.hutool.core.util.CharsetUtil; @@ -32,8 +31,8 @@ import org.dromara.hutool.json.engine.AbstractJSONEngine; import org.dromara.hutool.json.engine.JSONEngineConfig; import java.io.IOException; +import java.io.OutputStream; import java.io.Reader; -import java.io.Writer; import java.lang.reflect.Type; import java.time.LocalDate; import java.time.LocalDateTime; @@ -64,27 +63,22 @@ public class MoshiEngine extends AbstractJSONEngine implements Wrapper { return this.moshi; } - @SuppressWarnings("unchecked") @Override - public void serialize(final Object bean, final Writer writer) { - initEngine(); - final BufferedSink sink = Okio.buffer(Okio.sink(new WriterOutputStream(writer, CharsetUtil.UTF_8))); - JsonAdapter adapter = (JsonAdapter) this.moshi.adapter(bean.getClass()); - - if(ObjUtil.defaultIfNull(this.config, JSONEngineConfig::isPrettyPrint, false)){ - adapter = adapter.indent(" "); - } - if(!ObjUtil.defaultIfNull(this.config, JSONEngineConfig::isIgnoreNullValue, true)){ - adapter = adapter.serializeNulls(); - } - + public void serialize(final Object bean, final OutputStream out) { + final BufferedSink sink = Okio.buffer(Okio.sink(out)); try { - adapter.toJson(sink, bean); + getAdapter(this.moshi, bean.getClass()).toJson(sink, bean); } catch (final IOException e) { throw new JSONException(e); } } + @Override + public String toJsonString(final Object bean) { + final JsonAdapter adapter = getAdapter(this.moshi, bean.getClass()); + return adapter.toJson(bean); + } + @SuppressWarnings("unchecked") @Override public T deserialize(final Reader reader, final Object type) { @@ -120,13 +114,32 @@ public class MoshiEngine extends AbstractJSONEngine implements Wrapper { this.moshi = builder.build(); } + /** + * 获取并配置{@link JsonAdapter} + * + * @param moshi {@link Moshi} + * @param type Bean类型 + * @return this + */ + private JsonAdapter getAdapter(final Moshi moshi, final Type type) { + initEngine(); + JsonAdapter adapter = this.moshi.adapter(type); + if (ObjUtil.defaultIfNull(this.config, JSONEngineConfig::isPrettyPrint, false)) { + adapter = adapter.indent(" "); + } + if (!ObjUtil.defaultIfNull(this.config, JSONEngineConfig::isIgnoreNullValue, true)) { + adapter = adapter.serializeNulls(); + } + return adapter; + } + /** * 注册日期相关序列化描述 * - * @param builder Gson构造器 + * @param builder Gson构造器 * @param dateFormat 日期格式 */ - private void registerDate(final Moshi.Builder builder, final String dateFormat){ + private void registerDate(final Moshi.Builder builder, final String dateFormat) { builder.add(DateMoshiAdapter.createFactory(dateFormat)); builder.add(LocalDateTime.class, new TemporalMoshiAdapter(LocalDateTime.class, dateFormat)); builder.add(LocalDate.class, new TemporalMoshiAdapter(LocalDate.class, dateFormat)); diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/engine/moshi/TemporalMoshiAdapter.java b/hutool-json/src/main/java/org/dromara/hutool/json/engine/moshi/TemporalMoshiAdapter.java index 96f5ee0db..6f121d4b8 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/engine/moshi/TemporalMoshiAdapter.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/engine/moshi/TemporalMoshiAdapter.java @@ -60,11 +60,13 @@ public class TemporalMoshiAdapter extends JsonAdapter { } else { jsonWriter.value(TimeUtil.format(src, dateFormat)); } - jsonWriter.flush(); } @Override public TemporalAccessor fromJson(final JsonReader jsonReader) throws IOException { + if(jsonReader.peek() == JsonReader.Token.NULL){ + return jsonReader.nextNull(); + } return StrUtil.isEmpty(dateFormat) ? ConvertUtil.convert(this.type, jsonReader.nextLong()) : ConvertUtil.convert(this.type, TimeUtil.parse(jsonReader.nextString(), dateFormat)); diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/engine/moshi/TimeZoneMoshiAdapter.java b/hutool-json/src/main/java/org/dromara/hutool/json/engine/moshi/TimeZoneMoshiAdapter.java index c1dd268db..176cff3b3 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/engine/moshi/TimeZoneMoshiAdapter.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/engine/moshi/TimeZoneMoshiAdapter.java @@ -60,7 +60,6 @@ public class TimeZoneMoshiAdapter extends JsonAdapter { return; } jsonWriter.value(timeZone.getID()); - jsonWriter.flush(); } @Override diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/engine/BeanWithLocalDateTime.java b/hutool-json/src/test/java/org/dromara/hutool/json/engine/BeanWithLocalDateTime.java new file mode 100644 index 000000000..15812acc8 --- /dev/null +++ b/hutool-json/src/test/java/org/dromara/hutool/json/engine/BeanWithLocalDateTime.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024 Hutool Team and hutool.cn + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.dromara.hutool.json.engine; + +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +@AllArgsConstructor +public class BeanWithLocalDateTime { + private LocalDateTime date; +} diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/engine/JSONEngineFactoryTest.java b/hutool-json/src/test/java/org/dromara/hutool/json/engine/JSONEngineFactoryTest.java index fe033025e..4a87441be 100644 --- a/hutool-json/src/test/java/org/dromara/hutool/json/engine/JSONEngineFactoryTest.java +++ b/hutool-json/src/test/java/org/dromara/hutool/json/engine/JSONEngineFactoryTest.java @@ -26,7 +26,6 @@ import org.dromara.hutool.json.engine.jackson.JacksonEngine; import org.junit.jupiter.api.Test; import java.io.StringReader; -import java.io.StringWriter; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -72,12 +71,10 @@ public class JSONEngineFactoryTest { final JSONEngine engine = JSONEngineFactory.createEngine("gson"); assertEquals(GsonEngine.class, engine.getClass()); - final StringWriter stringWriter = new StringWriter(); final TestBean testBean = new TestBean("张三", 18, true); - engine.serialize(testBean, stringWriter); final String jsonStr = "{\"name\":\"张三\",\"age\":18,\"gender\":true}"; - assertEquals(jsonStr, stringWriter.toString()); + assertEquals(jsonStr, engine.toJsonString(testBean)); final TestBean testBean1 = engine.deserialize(new StringReader(jsonStr), TestBean.class); assertEquals(testBean, testBean1); @@ -88,12 +85,10 @@ public class JSONEngineFactoryTest { final JSONEngine engine = JSONEngineFactory.createEngine("fastjson"); assertEquals(FastJSON2Engine.class, engine.getClass()); - final StringWriter stringWriter = new StringWriter(); final TestBean testBean = new TestBean("张三", 18, true); - engine.serialize(testBean, stringWriter); final String jsonStr = "{\"name\":\"张三\",\"age\":18,\"gender\":true}"; - assertEquals(jsonStr, stringWriter.toString()); + assertEquals(jsonStr, engine.toJsonString(testBean)); final TestBean testBean1 = engine.deserialize(new StringReader(jsonStr), TestBean.class); assertEquals(testBean, testBean1); @@ -104,12 +99,10 @@ public class JSONEngineFactoryTest { final JSONEngine engine = JSONEngineFactory.createEngine("hutoolJSON"); assertEquals(HutoolJSONEngine.class, engine.getClass()); - final StringWriter stringWriter = new StringWriter(); final TestBean testBean = new TestBean("张三", 18, true); - engine.serialize(testBean, stringWriter); final String jsonStr = "{\"name\":\"张三\",\"age\":18,\"gender\":true}"; - assertEquals(jsonStr, stringWriter.toString()); + assertEquals(jsonStr, engine.toJsonString(testBean)); final TestBean testBean1 = engine.deserialize(new StringReader(jsonStr), TestBean.class); assertEquals(testBean, testBean1); diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/engine/MoshiTest.java b/hutool-json/src/test/java/org/dromara/hutool/json/engine/MoshiTest.java new file mode 100644 index 000000000..0eed36469 --- /dev/null +++ b/hutool-json/src/test/java/org/dromara/hutool/json/engine/MoshiTest.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2024 Hutool Team and hutool.cn + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.dromara.hutool.json.engine; + +import org.dromara.hutool.core.date.DateTime; +import org.dromara.hutool.core.date.DateUtil; +import org.dromara.hutool.core.date.TimeUtil; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class MoshiTest { + + @Test + void writeLocalDateFormatTest() { + final DateTime date = DateUtil.parse("2024-01-01 01:12:21"); + final BeanWithLocalDateTime bean = new BeanWithLocalDateTime(TimeUtil.of(date)); + final JSONEngine engine = JSONEngineFactory.createEngine("moshi"); + + final String jsonString = engine.toJsonString(bean); + Assertions.assertEquals("{\"date\":1704042741000}", jsonString); + + engine.init(JSONEngineConfig.of().setDateFormat("yyyy-MM-dd HH:mm:ss")); + Assertions.assertEquals("{\"date\":\"2024-01-01 01:12:21\"}", engine.toJsonString(bean)); + } +} diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/CustomSerializeTest.java b/hutool-json/src/test/java/org/dromara/hutool/json/serializer/CustomSerializeTest.java similarity index 91% rename from hutool-json/src/test/java/org/dromara/hutool/json/CustomSerializeTest.java rename to hutool-json/src/test/java/org/dromara/hutool/json/serializer/CustomSerializeTest.java index 7e7f20813..170519978 100644 --- a/hutool-json/src/test/java/org/dromara/hutool/json/CustomSerializeTest.java +++ b/hutool-json/src/test/java/org/dromara/hutool/json/serializer/CustomSerializeTest.java @@ -14,12 +14,11 @@ * limitations under the License. */ -package org.dromara.hutool.json; +package org.dromara.hutool.json.serializer; import lombok.ToString; -import org.dromara.hutool.json.serializer.JSONDeserializer; -import org.dromara.hutool.json.serializer.JSONSerializer; -import org.dromara.hutool.json.serializer.TypeAdapterManager; +import org.dromara.hutool.json.JSONObject; +import org.dromara.hutool.json.JSONUtil; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test;