问题描述
A为中台项目,B为节点项目,B通过client-java-api.jar获取prometheus监控数据,A通过接口调用定时获取节点监控信息,A、B项目均为springboot项目。
开发过程中,A调用B接口失败,查看A项目日志,B接口返回500,查看B项目日志有错误信息如图所示:
问题分析
B返回json数据给A项目需要经过对象序列化成json,springboot接口序列化默认使用Jackson,而k8s client-java-api.jar包返回的对象中有IntOrString类型,值为百分比(例如25%),jackson在序列化成json时会调用该类型的IntOrString.getIntValue方法,导致报错。
问题解决
解决方法一:使用Gson排除Jackson,考虑到B项目功能较多较复杂,不宜采用这种方式。
解决方法二:B接口返回时先使用new Gson().toJson(xxx)转成字符串放入Result对象,A项目使用Gson重新把字符串解析为对象
处理代码
由于Gson处理joda日期时间会出现Failed to invoke public org.joda.time.Chronology() with no args错误,所以还需要在使用Gson时指定datetime处理方式,网上找了很多DateTimeSerializer都报错,下面是本人修改后亲测可用的代码:
import com.google.gson.*;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import java.lang.reflect.Type;
public class DateTimeSerializer implements JsonDeserializer<DateTime>, JsonSerializer<DateTime>
{
private static final String FORMAT_FULL_TIME_NO_ZONE = "yyyy-MM-dd HH:mm:ss";
private static final DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
@Override
public DateTime deserialize(final JsonElement je, final Type type,
final JsonDeserializationContext jdc) throws JsonParseException
{
final String dateAsString = je.getAsString();
if (dateAsString.length() == 0)
{
return null;
}
else
{
return dateTimeFormatter.parseDateTime(dateAsString);
}
}
@Override
public JsonElement serialize(final DateTime src, final Type typeOfSrc,
final JsonSerializationContext context)
{
String retVal;
if (src == null)
{
retVal = "";
}
else
{
retVal = new DateTime(src).toString(FORMAT_FULL_TIME_NO_ZONE);
}
return new JsonPrimitive(retVal);
}
}
A项目Gson处理
final GsonBuilder builder = new GsonBuilder().registerTypeAdapter(DateTime.class, new DateTimeSerializer());
final Gson gson = builder.create();
Map<String, List<V1Deployment>> deploymentMap = gson.fromJson(responseResult.getData(), new TypeToken<Map<String, List<V1Deployment>>>() {}.getType());
B项目Gson处理
final GsonBuilder builder = new GsonBuilder().registerTypeAdapter(DateTime.class, new DateTimeSerializer());
final Gson gson = builder.create();
return ResponseEntity.ok(new Result.Builder<>(true).data(gson.toJson(result)).build());