fix code and add UTF8OutputStreamWriter

This commit is contained in:
Looly
2024-09-29 01:15:23 +08:00
parent 4db6ac1f34
commit 924357730e
15 changed files with 360 additions and 67 deletions

View File

@@ -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> T deserialize(final Reader reader, final Object type) {
initEngine();

View File

@@ -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 BeanPOJO对象
* @param writer 写出到的Writer
* @param out 写出到的{@link OutputStream}
*/
void serialize(Object bean, Writer writer);
void serialize(Object bean, OutputStream out);
/**
* 解析JSON数据反序列化用于从Reader中读取JSON字符串转换为Bean对象<br>
@@ -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);
}
/**

View File

@@ -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;
}
}

View File

@@ -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<Gson> {
}
@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")

View File

@@ -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<ObjectM
}
@Override
public void serialize(final Object bean, final Writer writer) {
public void serialize(final Object bean, final OutputStream out) {
initEngine();
try {
mapper.writeValue(writer, bean);
mapper.writeValue(out, bean);
} catch (final IOException e) {
throw new IORuntimeException(e);
}
}
@Override
public String toJsonString(final Object bean) {
initEngine();
try {
return mapper.writeValueAsString(bean);
} catch (final IOException e) {
throw new IORuntimeException(e);
}

View File

@@ -73,11 +73,14 @@ public class DateMoshiAdapter extends JsonAdapter<Date> {
}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);

View File

@@ -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<Moshi> {
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<Object> adapter = (JsonAdapter<Object>) 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<Object> adapter = getAdapter(this.moshi, bean.getClass());
return adapter.toJson(bean);
}
@SuppressWarnings("unchecked")
@Override
public <T> T deserialize(final Reader reader, final Object type) {
@@ -120,13 +114,32 @@ public class MoshiEngine extends AbstractJSONEngine implements Wrapper<Moshi> {
this.moshi = builder.build();
}
/**
* 获取并配置{@link JsonAdapter}
*
* @param moshi {@link Moshi}
* @param type Bean类型
* @return this
*/
private JsonAdapter<Object> getAdapter(final Moshi moshi, final Type type) {
initEngine();
JsonAdapter<Object> 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));

View File

@@ -60,11 +60,13 @@ public class TemporalMoshiAdapter extends JsonAdapter<TemporalAccessor> {
} 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));

View File

@@ -60,7 +60,6 @@ public class TimeZoneMoshiAdapter extends JsonAdapter<TimeZone> {
return;
}
jsonWriter.value(timeZone.getID());
jsonWriter.flush();
}
@Override

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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));
}
}

View File

@@ -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;