Skip to content

JacksonUtil

java
import com.fasterxml.jackson.*;
import org.springframework.stereotype.Component;

import java.util.*;

@Component
public class JacksonUtil {
    private static ObjectMapper objectMapper;

    public JacksonUtil(ObjectMapper objectMapper) {
        JacksonUtil.objectMapper = objectMapper;
        JacksonUtil.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);//忽略反序列化的未知属性,等同于注解 @JsonIgnoreProperties(true)

    }

    // 序列化为 String
    public static String toStr(Object o) {
        return objectMapper.writeValueAsString(o);
    }

    // 反序列化为 java bean,也可以是 map等集合
    public static <T> T toBean(String json, Class<T> beanClass) {
        return objectMapper.readValue(json, beanClass);
    }

    // 反序列化为 List<Bean>,也可以是List<Map>
    public static <T> List<T> toListBean(String json, Class<T> tClass) {
        return objectMapper.readValue(json, new TypeReference<ArrayList<T>>() {
        });
    }

    // 反序列化为 Map<String,Bean>
    public static <T> HashMap<String, T> toMapBean(String json, Class<T> tClass) {
        TypeFactory typeFactory = objectMapper.getTypeFactory();
        MapType mapType = typeFactory.constructMapType(HashMap.class, String.class, tClass);
        return map;
    }

    // List<Map> 根据map中的key分组 转换为 Map<List>
    public static Map<String, List<String>> listMapGroupToList(List<HashMap<String, String>> listMap) {
        Map<String, List<Map.Entry<String, String>>> collect = listMap.stream()
                .flatMap(m -> m.entrySet().stream())
                .collect(Collectors.groupingBy(a -> a.getKey()));
        Map<String, List<String>> map = new HashMap<>();
        collect.forEach((k, v) -> map.put(k, v.stream().map(Map.Entry::getValue).collect(Collectors.toList())));
        return map;
    }


    // 特殊转换 (此处对objectMapper 最好使用新的实例,避免污染bean)
    public static <T> T toBean(String json, Class<T> tClass, PropertyNamingStrategy strategy) {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setPropertyNamingStrategy(strategy);
        return t;
    }

}
java

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class JsonTests {
    private JacksonUtil jacksonUtil;

    @BeforeAll
    public void before() {
        jacksonUtil = new JacksonUtil(new ObjectMapper());
    }


    @Test
    @SneakyThrows
    public void a1() {

        String s = """
                {
                "name":"Paul"
                }""";
        System.out.println(jacksonUtil.toBean(s, HashMap.class));
    }

    @Test
    @SneakyThrows
    public void a2() {
        String s = """
                [{
                "name":"Paul"
                }]""";
        List list = jacksonUtil.toBean(s, List.class);
        System.out.println(list);
    }

    @Test
    @SneakyThrows
    public void a3() {
        String s = "{\"u1\":{\"name\":\"Paul\"},\"u2\":{\"name\":\"Eve\"}}";
        HashMap<String, User> stringUserHashMap = jacksonUtil.toMapBean(s, User.class);
        System.out.println(stringUserHashMap);
        HashMap<String, HashMap> stringUserHashMap1 = jacksonUtil.toMapBean(s, HashMap.class);
        System.out.println(stringUserHashMap1);
    }

    @Test
    @SneakyThrows
    public void a4() {
        HashMap<String, String> map1 = new HashMap<>();
        map1.put("name", "Paul");
        map1.put("age", "12");

        HashMap<String, String> map2 = new HashMap<>();
        map2.put("name", "Eve");
        map2.put("age", "13");

        Map<String, List<String>> stringListMap = JacksonUtil.listMapGroupToList(new ArrayList<>(Arrays.asList(map1, map2)));
        System.out.println(stringListMap);
    }

    @Test
    @SneakyThrows
    public void a5() {
        String s = "{\"user_name\":\"bee\",\"id_number\":\"123456\"}";
        System.out.println(jacksonUtil.toBean(s, User1.class, PropertyNamingStrategies.SNAKE_CASE));

    }

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class User {
        private String name;
    }

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    static class User1 {
        private String userName;
        private String idNumber;
    }
}

常用注解和配置

//忽略反序列化的未知属性,等同于注解 @JsonIgnoreProperties(true) mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false)

yaml
spring:
  jackson:
    deserialization:
      fail_on_unknown_properties: false

Json 转 JsonLine

java

@Test
@SneakyThrows
public void a5() {
    List all = new ArrayList();
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    try (SequenceWriter seq = new ObjectMapper().writer().withRootValueSeparator("\n")
            .writeValues(byteArrayOutputStream)) {
        all.forEach((Consumer<Object>) s -> {
            try {
                seq.write(s);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        });
    }
    InputStream inputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());

}

Jackson ThreadLocal

每个线程拥有自己的ObjectMapper对象.

java
public class Jackson {
    private static final ThreadLocal<ObjectMapper> om = ThreadLocal.withInitial(() -> {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        return objectMapper;
    });

    public Jackson() {
    }

    public static ObjectMapper getObjectMapper() {
        return om.get();
    }
}

bean被覆盖的问题

springboot 自定义objectMapper bean 导致无法获取 jackson 自动配置的bean

yaml
@Configuration
  public class JacksonConf {

  @Bean
  @Primary
  public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
  return builder.createXmlMapper(false).build();
  }
}

驼峰和下划线

java

@Test
@SneakyThrows
public void test() {
    ObjectMapper objectMapper = new ObjectMapper();
    String json = "{\"user_name\":\"bflee\",\"id_number\":\"123456\"}";
    objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
    AA aa = objectMapper.readValue(json, AA.class);
    String s = objectMapper.writeValueAsString(aa);
    System.out.println(aa);
    System.out.println(s);
}

@Data
@AllArgsConstructor
@NoArgsConstructor
static class AA {
    private String userName;
    private String idNumber;
}

@JsonSubTypes

java

@Data
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME,
        include = JsonTypeInfo.As.EXISTING_PROPERTY,
        property = "type"
)
@JsonSubTypes({
        @JsonSubTypes.Type(value = HiveTarget.class, name = HiveTarget.TYPE),
        @JsonSubTypes.Type(value = HBaseTarget.class, name = HBaseTarget.TYPE)
})
public class AbstractTarget {
    private String type;
}
java

@Data
@EqualsAndHashCode(callSuper = true)
public class HBaseTarget extends AbstractTarget {
    private String namespace;
    private String table;
    private String columnFamily;
    private String column;

    static final String TYPE = "hbase";

    public HBaseTarget() {
        setType(TYPE);
    }
}
java

@Data
@EqualsAndHashCode(callSuper = true)
public class HiveTarget extends AbstractTarget {
    private String schema;
    private String table;
    private String column;

    static final String TYPE = "hive";

    public HiveTarget() {
        setType(TYPE);
    }
}
java

@Test
@SneakyThrows
public void a5() {
    objectMapper.registerSubtypes(new NamedType(clz, s1));//单例对象注册sub type的方式
}