mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
add moshi
This commit is contained in:
parent
8eff63bc9f
commit
4db6ac1f34
@ -473,6 +473,22 @@ public class TypeUtil {
|
||||
return parameterizedType;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建泛型对象,例如:
|
||||
*
|
||||
* <pre>{@code
|
||||
* List<String> list = TypeUtil.createParameterizedType(List.class, String.class);
|
||||
* }</pre>
|
||||
*
|
||||
* @param rawType 原始类型,例如:List.class
|
||||
* @param actualTypeArguments 实际类型,例如:String.class
|
||||
* @return 泛型对象
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public static Type createParameterizedType(final Type rawType, final Type... actualTypeArguments) {
|
||||
return new ParameterizedTypeImpl(actualTypeArguments, null, rawType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得泛型变量对应的泛型实际类型,如果此变量没有对应的实际类型,返回null
|
||||
*
|
||||
|
@ -38,6 +38,10 @@
|
||||
<bouncycastle.version>1.78.1</bouncycastle.version>
|
||||
<jjwt.version>0.12.6</jjwt.version>
|
||||
<jackson.version>2.17.2</jackson.version>
|
||||
<gson.version>2.11.0</gson.version>
|
||||
<fastjson2.version>2.0.41</fastjson2.version>
|
||||
<moshi.version>1.15.1</moshi.version>
|
||||
<jmh.version>1.37</jmh.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@ -69,13 +73,19 @@
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.11.0</version>
|
||||
<version>${gson.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.fastjson2</groupId>
|
||||
<artifactId>fastjson2</artifactId>
|
||||
<version>2.0.41</version>
|
||||
<version>${fastjson2.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.moshi</groupId>
|
||||
<artifactId>moshi</artifactId>
|
||||
<version>1.15.1</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
@ -98,6 +108,45 @@
|
||||
<version>${jjwt.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- 基准性能测试 -->
|
||||
<dependency>
|
||||
<groupId>org.openjdk.jmh</groupId>
|
||||
<artifactId>jmh-core</artifactId>
|
||||
<version>${jmh.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjdk.jmh</groupId>
|
||||
<artifactId>jmh-generator-annprocess</artifactId>
|
||||
<version>${jmh.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- 添加JMH测试资源 -->
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<version>3.6.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add-jmh-resource</id>
|
||||
<phase>generate-test-sources</phase>
|
||||
<goals>
|
||||
<goal>add-test-resource</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<resources>
|
||||
<directory>src/test/jmh</directory>
|
||||
<targetPath>my-resources</targetPath>
|
||||
</resources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
@ -30,12 +30,12 @@ import java.util.Date;
|
||||
* @author Looly
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public class DateSerDesc implements GsonTypeAdapter<Date> {
|
||||
public class DateGsonTypeAdapter implements GsonTypeAdapter<Date> {
|
||||
|
||||
/**
|
||||
* 默认日期格式化描述,默认为null,表示使用时间戳
|
||||
*/
|
||||
public static final DateSerDesc INSTANCE = new DateSerDesc(null);
|
||||
public static final DateGsonTypeAdapter INSTANCE = new DateGsonTypeAdapter(null);
|
||||
|
||||
private final String dateFormat;
|
||||
|
||||
@ -44,7 +44,7 @@ public class DateSerDesc implements GsonTypeAdapter<Date> {
|
||||
*
|
||||
* @param dateFormat 日期格式
|
||||
*/
|
||||
public DateSerDesc(final String dateFormat) {
|
||||
public DateGsonTypeAdapter(final String dateFormat) {
|
||||
this.dateFormat = dateFormat;
|
||||
}
|
||||
|
@ -115,7 +115,7 @@ public class GsonEngine extends AbstractJSONEngine implements Wrapper<Gson> {
|
||||
*/
|
||||
private void registerDate(final GsonBuilder builder, final String dateFormat){
|
||||
// java date
|
||||
builder.registerTypeHierarchyAdapter(Date.class, new DateSerDesc(dateFormat));
|
||||
builder.registerTypeHierarchyAdapter(Date.class, new DateGsonTypeAdapter(dateFormat));
|
||||
builder.registerTypeHierarchyAdapter(TimeZone.class, TimeZoneGsonTypeAdapter.INSTANCE);
|
||||
|
||||
// java.time
|
||||
|
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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.moshi;
|
||||
|
||||
import com.squareup.moshi.JsonAdapter;
|
||||
import com.squareup.moshi.JsonReader;
|
||||
import com.squareup.moshi.JsonWriter;
|
||||
import org.dromara.hutool.core.date.DateUtil;
|
||||
import org.dromara.hutool.core.reflect.TypeUtil;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 日期格式化适配器,用于moshi序列化与反序列化日期
|
||||
*
|
||||
* @author looly
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public class DateMoshiAdapter extends JsonAdapter<Date> {
|
||||
|
||||
/**
|
||||
* 创建工厂
|
||||
*
|
||||
* @param dateFormat 日期格式
|
||||
* @return 创建工厂
|
||||
*/
|
||||
public static Factory createFactory(final String dateFormat){
|
||||
return (type, set, moshi) -> {
|
||||
if(Date.class.isAssignableFrom(TypeUtil.getClass(type))){
|
||||
return new DateMoshiAdapter(dateFormat);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
private final String dateFormat;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param dateFormat 日期格式
|
||||
*/
|
||||
public DateMoshiAdapter(final String dateFormat) {
|
||||
this.dateFormat = dateFormat;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toJson(final JsonWriter jsonWriter, final Date date) throws IOException {
|
||||
if(null == date){
|
||||
jsonWriter.nullValue();
|
||||
return;
|
||||
}
|
||||
|
||||
if(StrUtil.isEmpty(dateFormat)){
|
||||
jsonWriter.value(date.getTime());
|
||||
}else{
|
||||
jsonWriter.value(DateUtil.format(date, dateFormat));
|
||||
}
|
||||
jsonWriter.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date fromJson(final JsonReader jsonReader) throws IOException {
|
||||
return StrUtil.isEmpty(dateFormat) ?
|
||||
DateUtil.date(jsonReader.nextLong()) :
|
||||
DateUtil.parse(jsonReader.nextString(), dateFormat);
|
||||
}
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* 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.moshi;
|
||||
|
||||
import com.squareup.moshi.JsonAdapter;
|
||||
import com.squareup.moshi.Moshi;
|
||||
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;
|
||||
import org.dromara.hutool.core.util.ObjUtil;
|
||||
import org.dromara.hutool.json.JSONException;
|
||||
import org.dromara.hutool.json.engine.AbstractJSONEngine;
|
||||
import org.dromara.hutool.json.engine.JSONEngineConfig;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.Type;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
|
||||
/**
|
||||
* Moshi引擎实现
|
||||
*
|
||||
* @author looly
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public class MoshiEngine extends AbstractJSONEngine implements Wrapper<Moshi> {
|
||||
|
||||
private Moshi moshi;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*/
|
||||
public MoshiEngine() {
|
||||
// issue#IABWBL JDK8下,在IDEA旗舰版加载Spring boot插件时,启动应用不会检查字段类是否存在
|
||||
// 此处构造时调用下这个类,以便触发类是否存在的检查
|
||||
Assert.notNull(Moshi.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Moshi getRaw() {
|
||||
initEngine();
|
||||
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();
|
||||
}
|
||||
|
||||
try {
|
||||
adapter.toJson(sink, bean);
|
||||
} catch (final IOException e) {
|
||||
throw new JSONException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T> T deserialize(final Reader reader, final Object type) {
|
||||
initEngine();
|
||||
final BufferedSource source = Okio.buffer(Okio.source(new ReaderInputStream(reader, CharsetUtil.UTF_8)));
|
||||
final JsonAdapter<Object> adapter = this.moshi.adapter((Type) type);
|
||||
try {
|
||||
return (T) adapter.fromJson(source);
|
||||
} catch (final IOException e) {
|
||||
throw new JSONException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void reset() {
|
||||
this.moshi = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initEngine() {
|
||||
if (null != this.moshi) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 自定义配置
|
||||
final JSONEngineConfig config = ObjUtil.defaultIfNull(this.config, JSONEngineConfig::of);
|
||||
final Moshi.Builder builder = new Moshi.Builder();
|
||||
|
||||
// 注册日期相关序列化描述
|
||||
final String dateFormat = config.getDateFormat();
|
||||
registerDate(builder, dateFormat);
|
||||
|
||||
this.moshi = builder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册日期相关序列化描述
|
||||
*
|
||||
* @param builder Gson构造器
|
||||
* @param 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));
|
||||
builder.add(LocalTime.class, new TemporalMoshiAdapter(LocalTime.class, dateFormat));
|
||||
builder.add(TimeZoneMoshiAdapter.FACTORY);
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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.moshi;
|
||||
|
||||
import com.squareup.moshi.JsonAdapter;
|
||||
import com.squareup.moshi.JsonReader;
|
||||
import com.squareup.moshi.JsonWriter;
|
||||
import org.dromara.hutool.core.convert.ConvertUtil;
|
||||
import org.dromara.hutool.core.date.TimeUtil;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
|
||||
/**
|
||||
* 时间类型适配器,用于处理时间类型的序列化与反序列化
|
||||
*
|
||||
* @author looly
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public class TemporalMoshiAdapter extends JsonAdapter<TemporalAccessor> {
|
||||
|
||||
private final Class<? extends TemporalAccessor> type;
|
||||
private final String dateFormat;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param type 时间类型
|
||||
* @param dateFormat 日期格式
|
||||
*/
|
||||
public TemporalMoshiAdapter(final Class<? extends TemporalAccessor> type, final String dateFormat) {
|
||||
this.type = type;
|
||||
this.dateFormat = dateFormat;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toJson(final JsonWriter jsonWriter, final TemporalAccessor src) throws IOException {
|
||||
if (null == src){
|
||||
jsonWriter.nullValue();
|
||||
return;
|
||||
}
|
||||
|
||||
if (StrUtil.isEmpty(dateFormat)) {
|
||||
jsonWriter.value(TimeUtil.toEpochMilli(src));
|
||||
} else {
|
||||
jsonWriter.value(TimeUtil.format(src, dateFormat));
|
||||
}
|
||||
jsonWriter.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemporalAccessor fromJson(final JsonReader jsonReader) throws IOException {
|
||||
return StrUtil.isEmpty(dateFormat) ?
|
||||
ConvertUtil.convert(this.type, jsonReader.nextLong()) :
|
||||
ConvertUtil.convert(this.type, TimeUtil.parse(jsonReader.nextString(), dateFormat));
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.moshi;
|
||||
|
||||
import com.squareup.moshi.JsonAdapter;
|
||||
import com.squareup.moshi.JsonReader;
|
||||
import com.squareup.moshi.JsonWriter;
|
||||
import com.squareup.moshi.Moshi;
|
||||
import org.dromara.hutool.core.reflect.TypeUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* TimeZone类型适配器
|
||||
*
|
||||
* @author Looly
|
||||
*/
|
||||
public class TimeZoneMoshiAdapter extends JsonAdapter<TimeZone> {
|
||||
|
||||
/**
|
||||
* 创建工厂
|
||||
*/
|
||||
public static final Factory FACTORY = new Factory() {
|
||||
@Override
|
||||
public JsonAdapter<?> create(final Type type, final Set<? extends Annotation> set, final Moshi moshi) {
|
||||
if(TimeZone.class.isAssignableFrom(TypeUtil.getClass(type))){
|
||||
return INSTANCE;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 单例
|
||||
*/
|
||||
public static final TimeZoneMoshiAdapter INSTANCE = new TimeZoneMoshiAdapter();
|
||||
|
||||
@Override
|
||||
public void toJson(final JsonWriter jsonWriter, final TimeZone timeZone) throws IOException {
|
||||
if(null == timeZone){
|
||||
jsonWriter.nullValue();
|
||||
return;
|
||||
}
|
||||
jsonWriter.value(timeZone.getID());
|
||||
jsonWriter.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimeZone fromJson(final JsonReader jsonReader) throws IOException {
|
||||
return TimeZone.getTimeZone(jsonReader.nextString());
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Moshi引擎实现<br>
|
||||
* https://github.com/square/moshi
|
||||
*
|
||||
* @author Looly
|
||||
* @since 6.0.0
|
||||
*/
|
||||
package org.dromara.hutool.json.engine.moshi;
|
@ -65,7 +65,7 @@ public class JSONXMLSerializer {
|
||||
* @return A string.
|
||||
* @throws JSONException JSON解析异常
|
||||
*/
|
||||
public static String toXml(JSON json, final String tagName, final String... contentKeys) throws JSONException {
|
||||
public static String toXml(final JSON json, final String tagName, final String... contentKeys) throws JSONException {
|
||||
if (null == json) {
|
||||
return null;
|
||||
}
|
||||
|
@ -17,4 +17,5 @@
|
||||
org.dromara.hutool.json.engine.jackson.JacksonEngine
|
||||
org.dromara.hutool.json.engine.gson.GsonEngine
|
||||
org.dromara.hutool.json.engine.fastjson.FastJSON2Engine
|
||||
org.dromara.hutool.json.engine.moshi.MoshiEngine
|
||||
org.dromara.hutool.json.engine.HutoolJSONEngine
|
||||
|
@ -28,7 +28,7 @@ import java.util.TimeZone;
|
||||
|
||||
public class JSONEngineTest {
|
||||
|
||||
private final String[] engineNames = {"jackson", "gson", "fastjson", "hutool"};
|
||||
private final String[] engineNames = {"jackson", "gson", "fastjson", "moshi", "hutool"};
|
||||
|
||||
@Test
|
||||
void writeDateFormatTest() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user