java:支持更多日期格式的fastjson日期解析器(ObjectDeserializer)实现

19 篇文章 1 订阅

Fastjson内置的日期类型解析器(com.alibaba.fastjson.serializer.DateCodec)只支持ISO8601以及SQL标准日期格式(yyyy-MM-dd HH:mm:ss),但日期格式的常用种类也不少:比如 Date.toString()输出的Tuesday February 27 10:43:27 CST 2024这样的格式。除非在使用注解方式指定日期格式。否则Fastjson不能解析这样的格式。

FastjsonDateDeserializer

如果要实现自适应的各种日期解析,就要自己实现日期解析器,
以下为参照com.alibaba.fastjson.parser.deserializer.AbstractDateDeserializer.deserialze方法实现的自适应日期解析器代码

import java.lang.reflect.Type;
import java.util.Calendar;
import java.util.Date;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.parser.DefaultJSONParser;
import com.alibaba.fastjson.parser.JSONLexer;
import com.alibaba.fastjson.parser.JSONScanner;
import com.alibaba.fastjson.parser.JSONToken;
import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer;
import static net.gdface.utils.DateSupport.parseAsDate;
import static net.gdface.utils.DateSupport.castToDate;

/**
 * 日期类型FASTJSON反序列化实现,
 * 相比默认的反序列化器 {@link com.alibaba.fastjson.serializer.DateCodec}  支持更多日期格式
 * @author guyadong
 */
public class FastjsonDateDeserializer implements ObjectDeserializer {

    @Override
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
        JSONLexer lexer = parser.lexer;
        if(!(type instanceof Class) || !(Date.class.isAssignableFrom((Class)type) || Calendar.class.isAssignableFrom((Class)type))) {
        	throw new IllegalArgumentException("type required Date or Calendar");
        }
        switch(lexer.token()) {
        case JSONToken.LITERAL_INT:{
            long millis = lexer.longValue();
            lexer.nextToken(JSONToken.COMMA);
            try {
            	return (T) castToDate(millis,(Class)type);
			} catch (Exception e) {
				throw new JSONException(e.getMessage(),e);
			}
        }
        case JSONToken.LITERAL_STRING:{
            String strVal = lexer.stringVal();
            lexer.nextToken(JSONToken.COMMA);

            try(JSONScanner iso8601Lexer = new JSONScanner(strVal)){
            	if (iso8601Lexer.scanISO8601DateIfMatch(false)) {
            		Calendar calendar = iso8601Lexer.getCalendar();
            		return (T) castToDate(calendar,(Class)type);
            	}else {
					Object parsed = parseAsDate(strVal, (Class)type,0,1,2,3,4);
					if(parsed != null) {
						return (T) parsed;
					}
					throw new JSONException("FAIL parse date: "+strVal);
				}
            }
        }
        case JSONToken.NULL:
        	lexer.nextToken();
            return null;
        default:
        	throw new JSONException("parse error");
        }
    }
    public int getFastMatchToken() {
        return JSONToken.LITERAL_INT;
    }
}

DateSupport

上面的代码中调用的parseAsDate,castToDate来自DateSupport,它在PATTERNS数组中定义常用的日期格式。对于日期字符串会顺序尝试使用这些格式来解析直到能够成功解析为止。
代码如下:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Set;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicReference;

import com.google.common.collect.Sets;
import com.google.common.primitives.Ints;

/**
 * 日期工具类<br>
 * copy from sql2java-base gu.sql2java.utils.DateSupport
 * @author guyadong
 * @since 2.8.8
 */
public class DateSupport {
	/**
	 * pattern for received date processing.
	 */
	private static final String[] PATTERNS = new String[]
			{
					"yyyy-MM-dd'T'HH:mm:ss.SSSZ",    	 /** ISO8601时间格式 */
					"yyyy-MM-dd HH:mm:ss",                  /** 用于SQL语句的时间戳格式转换格式 */
					"yyyy-MM-dd",                                  /** 日期转换格式 */
					"yyyy-MM-d HH:mm:ss",
					"yyyy-MM-dd HH:mm:ss Z",
					"yyyy-MM-dd HH:mm:ss z",
					"HH:mm:ss",
					"EEE MMM dd HH:mm:ss z yyyy",	/** Tue Feb 27 10:43:27 CST 2024 */
					"EEE, dd MMM yyyy HH:mm:ss '-'S '('z')'",
					"EEE, dd MMM yyyy HH:mm:ss '+'S '('z')'",
					"EEE, dd MMM yyyy HH:mm:ss '-'S",
					"EEE, dd MMM yyyy HH:mm:ss '+'S",
					"EEE, dd MMM yyyy HH:mm:ss z",
					"EEE, dd MMM yyyy HH:mm:ss Z",
					"EEE, dd MMM yyyy HH:mm:ss",
					"EEE, d MMM yyyy HH:mm:ss '-'S '('z')'",
					"EEE, d MMM yyyy HH:mm:ss '+'S '('z')'",
					"EEE, d MMM yyyy HH:mm:ss '-'S",
					"EEE, d MMM yyyy HH:mm:ss '+'S",
					"EEE, d MMM yyyy HH:mm:ss z",
					"EEE, d MMM yyyy HH:mm:ss Z",
					"EEE, d MMM yyyy HH:mm:ss",

					"EEE, dd MMM yy HH:mm:ss '-'S '('z')'",
					"EEE, dd MMM yy HH:mm:ss '+'S '('z')'",
					"EEE, dd MMM yy HH:mm:ss '-'S",
					"EEE, dd MMM yy HH:mm:ss '+'S",
					"EEE, dd MMM yy HH:mm:ss z",
					"EEE, dd MMM yy HH:mm:ss Z",
					"EEE, dd MMM yy HH:mm:ss",
					"EEE, d MMM yy HH:mm:ss '-'S '('z')'",
					"EEE, d MMM yy HH:mm:ss '+'S '('z')'",
					"EEE, d MMM yy HH:mm:ss '-'S",
					"EEE, d MMM yy HH:mm:ss '+'S",
					"EEE, d MMM yy HH:mm:ss z",
					"EEE, d MMM yy HH:mm:ss Z",
					"EEE, d MMM yy HH:mm:ss",

					"dd MMM yyyy HH:mm:ss '-'S",
					"dd MMM yyyy HH:mm:ss '+'S",
					"dd MMM yyyy HH:mm:ss '-'S '('z')'",
					"dd MMM yyyy HH:mm:ss '+'S '('z')'",
					"dd MMM yyyy HH:mm:ss z",
					"dd MMM yyyy HH:mm:ss Z",
					"dd MMM yyyy HH:mm:ss",

					"dd MMM yyy HH:mm:ss '-'S",
					"dd MMM yyy HH:mm:ss '+'S",
					"dd MMM yyy HH:mm:ss '-'S '('z')'",
					"dd MMM yyy HH:mm:ss '+'S '('z')'",
					"dd MMM yyy HH:mm:ss z",
					"dd MMM yyy HH:mm:ss Z",
					"dd MMM yyy HH:mm:ss",

					"yyyy.MM.dd HH:mm:ss z",
					"yyyy.MM.dd HH:mm:ss Z",
					"yyyy.MM.d HH:mm:ss z",
					"yyyy.MM.d HH:mm:ss Z",
					"yyyy.MM.dd HH:mm:ss",
					"yyyy.MM.d HH:mm:ss",

					"yy.MM.dd HH:mm:ss z",
					"yy.MM.dd HH:mm:ss Z",
					"yy.MM.d HH:mm:ss z",
					"yy.MM.d HH:mm:ss Z",
					"yy.MM.dd HH:mm:ss",
					"yy.MM.d HH:mm:ss",

					"yyyy MM dd HH:mm:ss",
					"yyyy MM d HH:mm:ss",
					"yyyy MM dd HH:mm:ss z",
					"yyyy MM dd HH:mm:ss Z",
					"yyyy MM d HH:mm:ss z",
					"yyyy MM d HH:mm:ss Z",

					"yy MM dd HH:mm:ss",
					"yy MM d HH:mm:ss",
					"yy MM dd HH:mm:ss z",
					"yy MM dd HH:mm:ss Z",
					"yy MM d HH:mm:ss z",
					"yy MM d HH:mm:ss Z",

					"yy-MM-dd HH:mm:ss z",
					"yy-MM-dd HH:mm:ss Z",
					"yy-MM-d HH:mm:ss z",
					"yy-MM-d HH:mm:ss Z",
					"yy-MM-dd HH:mm:ss",
					"yy-MM-d HH:mm:ss",

					"dd MMM yyyy",
					"d MMM yyyy",

					"dd.MMM.yyyy",
					"d.MMM.yyyy",

					"dd-MMM-yyyy",
					"d-MMM-yyyy",

					"dd MM yyyy",
					"d MM yyyy",

					"dd.MM.yyyy",
					"d.MM.yyyy",

					"dd-MM-yyyy",
					"d-MM-yyyy",

					"yyyy MM dd",
					"yyyy MM d",

					"yyyy.MM.dd",
					"yyyy.MM.d",

					"yyyy-MM-d",

					"dd MMM yy",
					"d MMM yy",

					"dd.MMM.yy",
					"d.MMM.yy",

					"dd-MMM-yy",
					"d-MMM-yy",

					"dd MM yy",
					"d MM yy",

					"dd.MM.yy",
					"d.MM.yy",

					"dd-MM-yy",
					"d-MM-yy",

					"yy MMM dd",
					"yy MMM d",

					"yy.MMM.d",

					"yy-MMM-dd",
					"yy-MMM-d",

					"yy.MMM.dd",

					// ex: Wed 19, Feb 2003
					"EEE dd, MMM yyyy", 
					// ex: Wed 19, Feb 03
					"EEE dd, MMM yy" 
			};

	/** ISO8601 date time pattern */
	static final String ISO8601_FORMATTER_STR = PATTERNS[0];
    /** 用于SQL语句的时间戳格式转换格式 */
    public static final String TIMESTAMP_FORMATTER_STR = PATTERNS[1];
    /** 日期转换格式 */
    static final String DATE_FORMATTER_STR = PATTERNS[2];
	/**
	 * get a date from a date string representation in one of the registered formats
	 * @param strDate the date as string. 
	 * @param pattern [out] if not null, return pattern string or null if (null or empty) or correct pattern was not found
	 * @param excludeIndexs excluded pattern index 
	 * @return Date object ,otherwise null If (null or empty) or correct pattern was not found
	 */
	public static java.util.Date getDateFromString(String strDate,AtomicReference<String>pattern,int...excludeIndexs)
	{
		java.util.Date dReceivedDate = null;
		if (strDate == null || strDate.trim().equals("null")) {
			return dReceivedDate;
		} else {
			strDate = strDate.trim();
		}
		
		Set<Integer> exidx = 
			Sets.newHashSet(Ints.asList(null == excludeIndexs ? new int[0]: excludeIndexs));
		SimpleDateFormat pSimpleDateFormat = new SimpleDateFormat("",Locale.ENGLISH);
		if (!strDate.isEmpty())
		{
			for (int i=0; i<PATTERNS.length; i++)
			{
				if(exidx.contains(i)) {
					continue;
				}
				try
				{
					pSimpleDateFormat.applyPattern(PATTERNS[i]);
					dReceivedDate = pSimpleDateFormat.parse(strDate);
					if (dReceivedDate == null)
					{
						continue;
					}
					if( null !=pattern) {
						pattern.set(PATTERNS[i]);
					}
					return dReceivedDate;
				}
				catch (ParseException pe)
				{
					; // ignore this format try the next one
				}
			}
		}
		return dReceivedDate;
	}
	/**
	 * get a date from a date string representation in one of the registered formats
	 * @param strDate the date as string. 
	 * @return Date object ,otherwise null If (null or empty) or correct pattern was not found
	 */
	public static java.util.Date getDateFromString(String strDate)
	{
		return getDateFromString(strDate,null);
	}
	/**
	 * get a date from a date string representation in one of the registered formats
	 * @param dateStr the date as string. 
	 * @param targetClass
	 * @return Date object ,otherwise null If (null or empty) or correct pattern was not found
	 */
	public static <D extends Date> D parseDateString(String dateStr, Class<D> targetClass)   {
		if(null != dateStr && null != targetClass)
		{
			Date date = null;
			try {
				date = new SimpleDateFormat(ISO8601_FORMATTER_STR).parse(dateStr);
			} catch (ParseException e3) {
				try {
					date = java.sql.Timestamp.valueOf(dateStr);
				} catch (IllegalArgumentException e) {
					try {
						date =java.sql.Date.valueOf(dateStr);
					} catch (IllegalArgumentException e1) {
						try {
							date =java.sql.Time.valueOf(dateStr);
						} catch (IllegalArgumentException e2) {
							date = getDateFromString(dateStr);
						}
					}
				}
			}
			return castToDate(date,targetClass);
		}
		return null;
	}
	/**
	 * get a date from a date string representation in one of the registered formats
	 * @param input the date as string. 
	 * @param targetClass Date or Calendar or subclass required
	 * @param excludeIndexs excluded pattern index 
	 * @return Date object ,otherwise null If (null or empty) or correct pattern was not found
	 */
	public static <D> D parseAsDate(String input, Class<D> targetClass,int...excludeIndexs)   {
		if(null != input && null != targetClass){
			Date date = getDateFromString(input,null,excludeIndexs);
			return castToDate(date,targetClass);
		}
		return null;
	}
	/**
	 * convert {@link Date} to ISO8601 date time format string
	 * @param date
	 * @return ISO8601 date time format string or null if date is null
	 */
	public static String toISO8601String(Date date){

		return null == date ? null : new SimpleDateFormat(ISO8601_FORMATTER_STR).format(date);
	}
	/**
	 * format {@link Datec} to  string
	 * @param date
	 * @param format date time format string,use ISO8601 format if null
	 * @return ISO8601 date time format string or null if date is null
	 */
	public static String formatDate(Date date, String format){
		return null == date ? null : new SimpleDateFormat(null == format ? ISO8601_FORMATTER_STR : format ).format(date);
	}
	/**
	 * Verify that the string represantes the date with one of the registered formats
	 * @param strDate the date as string.
	 * @return boolean "true" if the string represantes the date in one of the registed formats.
	 */
	public static boolean isDate(String strDate)
	{
		return null != getDateFromString(strDate);
	}
	/**
	 * Verify that the string represantes the date with one of the registered formats
	 * @param strDate the date as string.
	 * @return boolean "true" if the string represantes the date in one of the registed formats.
	 * @since 3.25.0
	 */
	public static String patternOf(String strDate)
	{
		AtomicReference<String> p = new AtomicReference<>();
		getDateFromString(strDate,p);
		return p.get();
	}

	/**
	 * 将对象转为指定的日期类型
	 * @param <F> 原类型  String,Number,java.util.Date or Calendar or subclass
	 * @param <T> 目标类型  java.util.Date or Calendar or subclass
	 * @param from 
	 * @param targetClass 
	 */
	@SuppressWarnings("unchecked")
	public static <F,T>T castToDate(F from,Class<T>targetClass) {
		if(null != from && null != targetClass){
			if(targetClass.isInstance(from)){
				return targetClass.cast(from);
			}else if(from instanceof Date) {
				Date date = (Date)from;
				if(Date.class.isAssignableFrom(targetClass)) {
					try {
						return targetClass.getConstructor(long.class).newInstance(date.getTime());
					} catch (Exception e) {
						throw new IllegalArgumentException("UNSUPPORTED Date type:"+targetClass.getName(),e);
					}
				}else if (targetClass == Calendar.class) {
					Calendar calendar = Calendar.getInstance();
					calendar.setTime(date);
					return (T) calendar;
				}else if(Calendar.class.isAssignableFrom(targetClass)) {
					try {
						Calendar calendar = (Calendar) targetClass.newInstance();
						calendar.setTime(date);
						return (T) calendar;
					} catch (Exception e) {
						throw new IllegalArgumentException("UNSUPPORTED Date type:"+targetClass.getName(),e);
					}
				}else {
					throw new IllegalArgumentException("UNSUPPORTED Date type:"+targetClass.getName());
				}
			}else if(from instanceof Calendar){
				return castToDate(((Calendar)from).getTime(),targetClass);
			}else if(from instanceof Number){
				return castToDate((new Date(((Number)from).longValue())),targetClass);
			}else if(from instanceof String){
				return castToDate(getDateFromString((String)from,null),targetClass);
			}else {
				throw new IllegalArgumentException("UNSUPPORTED Date type:"+from.getClass().getName());
			}
		}
		return null;
	}
}

示例代码:

	@Test
	public void test6FastjsonDateDeserializer() {
		try {
			String input="\"Tuesday February 27 10:43:27 CST 2024\"";
//			String input="\"2024-02-27 15:01:31+0800\"";
//			String input="\"2024-02-27\"";
//			ParserConfig.global.putDeserializer(Date.class, new FastjsonDateDeserializer());
			ParserConfig.global.putDeserializer(java.sql.Date.class, new FastjsonDateDeserializer());
			Date parsed = JSON.parseObject(input, java.sql.Date.class);
			log("parsed {}",parsed);
		} catch (Throwable e) {
			e.printStackTrace();
			fail(e.getMessage());
		}
	}

以上实现的完整代码参见:
https://gitee.com/l0km/common-java/blob/master/common-base2/src/main/java/net/gdface/json/FastjsonDateDeserializer.java
测试代码参见 :
https://gitee.com/l0km/common-java/blob/master/common-base2/src/test/java/net/gdface/json/FastjsonTest.java

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 将实体类转换为FastJson是在Java中使用FastJson库来实现实体类对象与Json字符串之间的相互转换。下面是一个示例: 首先,首先需要引入FastJson的依赖,以及相关的Jackson库: ```xml <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.62</version> </dependency> ``` 接下来,假设我们有一个实体类Person: ```java public class Person { private String name; private int age; // 省略getter和setter方法 } ``` 我们可以使用FastJson库将Person对象转换为Json字符串: ```java import com.alibaba.fastjson.JSON; public class Main { public static void main(String[] args) { Person person = new Person(); person.setName("Alice"); person.setAge(20); String jsonString = JSON.toJSONString(person); System.out.println(jsonString); } } ``` 上述代码中,我们使用`JSON.toJSONString()`方法将Person对象转换为Json字符串。输出的结果为`{"age":20,"name":"Alice"}`。 同样地,我们也可以将Json字符串转换为Person对象: ```java import com.alibaba.fastjson.JSON; public class Main { public static void main(String[] args) { String jsonString = "{\"age\":20,\"name\":\"Alice\"}"; Person person = JSON.parseObject(jsonString, Person.class); System.out.println(person.getName()); System.out.println(person.getAge()); } } ``` 上述代码中,我们使用`JSON.parseObject()`方法将Json字符串转换为Person对象。输出的结果为: ``` Alice 20 ``` 总结:通过上述示例,我们可以看到使用FastJson可以很方便地实现实体类对象与Json字符串之间的转换。只需要引入FastJson的依赖以及Jackson库,就可以进行转换操作。 ### 回答2: 在Java中,我们可以使用Fastjson库将实体类转换为JSON字符串。Fastjson是一个高性能的Java JSON处理器,可以快速将Java对象转换为JSON字符串。 要将实体类转换为Fastjson,我们需要按照以下步骤进行操作: 1. 导入Fastjson库。在项目中,我们需要先将Fastjson库添加到项目的依赖中。可以在Maven或Gradle配置文件中添加相关依赖项。 2. 创建一个实体类。假设我们的实体类名为Person,它具有一些属性,如姓名、年龄等。 3. 在代码中创建Person对象,并设置相应的属性值。 4. 使用Fastjson将Person对象转换为JSON字符串。可以通过调用Fastjson库提供的相关API,如toJSONString()方法,将Person对象转换为JSON字符串。例如,String jsonString = JSON.toJSONString(person); 5. 打印或处理生成的JSON字符串。可以将生成的JSON字符串打印出来,或者根据需要进行其他处理,如存储到文件中。 通过以上步骤,我们可以将实体类转换为JSON字符串,然后可以根据需要进行后续的操作,如传递给其他系统、存储到数据库等。 需要注意的是,Fastjson默认情况下按照实体类的属性顺序来生成JSON字符串,如果需要按照自定义的顺序生成JSON字符串,可以在实体类中使用注解或配置指定属性的顺序。此外,Fastjson支持将JSON字符串转换回Java对象的功能,可以方便地在Java程序中进行JSON数据的读取和解析操作。 ### 回答3: 将实体类转换为Fastjson可以通过以下步骤实现: 首先,确保已经引入Fastjson库。可以通过在pom.xml文件中添加以下依赖项来引入Fastjson: ```xml <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>x.x.x</version> </dependency> ``` 其中,x.x.x是Fastjson库的版本号。 接下来,需要将实体类的属性和对应的值转换为Fastjson的JSONObject对象。可以通过创建一个新的JSONObject对象,并使用put方法将属性和值添加到JSONObject中: ```java import com.alibaba.fastjson.JSONObject; public class Entity { private String name; private int age; // getter and setter methods public JSONObject toJSON() { JSONObject json = new JSONObject(); json.put("name", this.name); json.put("age", this.age); return json; } } ``` 上述代码中,toJSON方法将实体类的属性和对应的值添加到JSONObject对象中,并返回该JSONObject对象。 最后,可以通过调用toJSON方法,将实体类转换为Fastjson的JSON对象: ```java public class Main { public static void main(String[] args) { Entity entity = new Entity(); entity.setName("John"); entity.setAge(25); JSONObject json = entity.toJSON(); System.out.println(json.toJSONString()); } } ``` 上述代码中,首先创建一个实体类的实例entity,并设置其属性值。然后,调用entity的toJSON方法,将实体类转换为Fastjson的JSONObject对象。最后,通过调用JSON对象的toJSONString方法,将JSON对象转换为字符串,并打印输出。 以上就是将实体类转换为Fastjson的一个简单示例。实际使用中,根据实体类的属性情况,可以灵活地使用Fastjson提供的方法来实现转换。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

10km

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值