当前位置:首页 > 技术文章 > 正文内容

Json数据格式化问题_json数据格式化问题怎么解决

一 业务背景

需要将已保存的json字符串获取,并提取其中的某个字段按“,”拼接为字符串。

二 代码

2.1 实体

public class LangDataLimitDTO implements Serializable {

    /** 一级限制类别id */
    private Integer typeId;
    /** 一级限制类别名称 */
    private String typeName;

    public LangDataLimitDTO(Integer typeId, String typeName){
        this.typeId = typeId;
        this.typeName = typeName;
    }

2.2 格式转化代码

public String getLangLimitStr(){
        if(StringUtils.isEmpty(languageLimitJson)){
            return null;
        }
        List<LangDataLimitDTO> langDataLimitList = JsonUtils.fromJSON(languageLimitJson, new TypeReference<List<LangDataLimitDTO>>(){});
        if(CollectionUtils.isEmpty(langDataLimitList)){
            return null;
        }
        StringBuilder  sb = new StringBuilder();
        for(LangDataLimitDTO langDataLimitDTO : langDataLimitList){
            sb.append(langDataLimitDTO.getTypeName()).append(",");
        }
        return StringUtils.removeEnd(sb.toString(), ",");
    }

2.3 工具

	/**
	 *	
	 * 描述:将json字符串转成指定T类型的对象
	 * 示例:formJSON(jsonString,new MyTypeReference()<List<Map<String,Object>>>)
	 * @created 2014-4-7 上午10:04:20
	 * @since   v1.0.0 
	 * @param jsonString
	 * @param typeRef
	 * @return  T
	 */
	@SuppressWarnings("unchecked")
	public static final <T> T fromJSON(String jsonString, TypeReference<T> typeRef) {
		if (null == jsonString)
			return null;
		ByteArrayInputStream bais = new ByteArrayInputStream(jsonString.getBytes());
		try {
			ObjectInput in = serialization.deserialize(bais);
			return (T) in.readObject(typeRef);
		} catch (Exception e) {
			throw new RuntimeException("Json deserial error.", e);
		} finally {
			try {
				if (null != bais) {
					bais.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

2.4 序列化方式

private static final Serialization serialization = new JacksonSerialization();

三 问题

当使用getLangLimitStr()转化数据时,传入的合法的json串数据,返回的格式化对象为空的问题。

3.1 TypeReference分析

TypeReference为jackson包提供的用于处理泛型类型信息的工具,主要用于反序列化时明确指定目标类型,确保数据转换的准确性。

3.2 原因

1、反射实例化需求
Jackson默认通过反射调用无参构造器创建对象实例,再通过setter方法或字段注入填充属性。若类中仅存在有参构造器而无无参构造器,反射将无法实例化对象,导致反序列化失败。
2、框架设计约束
Jackson的ObjectMapper在反序列化时遵循标准JavaBean规范,要求目标类具备无参构造器以实现通用化处理。这种设计简化了反序列化流程,使其无需预知具体构造逻辑即可重建对象。
3、兼容性考量
无参构造器是Java序列化机制(如java.io.Serializable)和多数ORM框架(如Hibernate)的共同要求。Jackson保持这一约束可确保与其他技术栈的兼容性。

3.3 默认生成问题

默认无参构造方法的行为规则
1、自动生成条件
当类中未显式定义任何构造方法时,Java编译器会自动生成一个默认的无参构造方法(访问修饰符与类相同)。

public class User {} // 编译器会自动添加 public User() {}

2、手动定义覆盖
若类中已定义任意构造方法(包括有参构造),编译器不再自动生成无参构造方法。此时若需无参构造,必须显式声明

public class User {
    private String name;
    public User(String name) { this.name = name; }
    public User() {} // 必须手动添加
}

四 解决

4.1 添加无参构造

public class LangDataLimitDTO implements Serializable {

    /** 一级限制类别id */
    private Integer typeId;
    /** 一级限制类别名称 */
    private String typeName;

    public LangDataLimitDTO(){
    }
    public LangDataLimitDTO(Integer typeId, String typeName){
        this.typeId = typeId;
        this.typeName = typeName;
    }

4.2 实现反序列化器

public class ResponseDeserializer extends JsonDeserializer<Response> {
    @Override
    public Response deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
        Map<String, Map<String, String>> map = jsonParser.readValueAs(Map.class);
        Map<String, String> headerMap = map.get("headerMap");
        Map<String, String> apiMap = map.get("apiMap");

        return new Response(headerMap, apiMap);
    }
}

将反序列化器注册到 ObjectMapper 中:


public class ObjectMapperUtil {
    private static ObjectMapper objectMapper = new ObjectMapper();

    static {
        SimpleModule simpleModule = new SimpleModule("custom");
        simpleModule.addDeserializer(Response.class, new ResponseDeserializer());
        objectMapper.registerModule(simpleModule);
    }

    public static ObjectMapper getObjectMapper() {
        return objectMapper;
    }

    /**
     *
     * @param object
     * @return
     */
    public static String writeAsPrettyString(Object object) {
        try {
            return getObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(object);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }
}

相关文章

10个实例小练习,快速入门熟练 Vue3 核心新特性(一)

作者:xuying 全栈修炼转发链接:https://mp.weixin.qq.com/s/_n2seDbbiO5hXQfuUGbUCQ前言Vue3.0 发 beta 版都有一段时间了,正式版也不远了...

Vue2的16种传参通信方式(vue传参数)

前言先直入主题列出有哪些传参方式,下面再通过事例一一讲解。props(父传子)$emit与v-on (子传父)EventBus (兄弟传参).sync与update: (父子双向)v-model (父...

git的几种分支模式(git分支的概念)

编写代码,是软件开发交付过程的起点,发布上线,是开发工作完成的终点。代码分支模式贯穿了开发、集成和发布的整个过程,是工程师们最亲切的小伙伴。那如何根据自身的业务特点和团队规模来选择适合的分支模式呢?本...

用IDEA开发如何用Git快速拉取指定分支代码?

1,准备空的文件夹,git init2,关联远程仓库,git remote add origin gitlab地址3,拉取远程分支代码,git pull origin 远程分支名再用IDEA打开项目即...

Jenkins 学习笔记(jenkins要学多久)

本学习笔记参考《Jenkins 2.x实践指南》。1. Jenkins 简介#Jenkins 是一款自动化的任务执行工具。通常用于持续集成/持续交付领域。可以通过界面或Jenkinsfile告诉Jen...

我的VIM配置(如何配置vim编辑环境)

写一篇关于VIM配置的文章,记录下自己的VIM配置,力求简洁实用。VIM的配置保存在文件~/.vimrc中(Windows下是C:\Users\yourname \_vimrc)。VIM除了自身可配置...