Java嵌套DTO生成可持久化哈希:支持注解排除字段的库推荐
适合嵌套DTO哈希生成的Java库方案
下面推荐几个能满足需求的Java库,支持自定义注解排除字段、处理嵌套对象,生成整数或字符串哈希用于持久化:
1. Apache Commons Lang3(HashCodeBuilder)
这个库是Java开发中的常用工具,结合反射可以轻松实现带注解过滤的嵌套对象哈希生成,返回整数哈希值,也可转成十六进制字符串。
实现步骤
- 定义自定义排除注解(你已经有了,这里再明确下):
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface ExcludeField {}
- 编写哈希生成工具类,递归遍历对象字段,跳过带
@ExcludeField的字段:
import org.apache.commons.lang3.builder.HashCodeBuilder; import java.lang.reflect.Field; import java.lang.reflect.Modifier; public class HashGenerator { public static int generateIntHash(Object obj) throws IllegalAccessException { if (obj == null) return 0; HashCodeBuilder hcb = new HashCodeBuilder(); processNestedObject(obj, hcb); return hcb.toHashCode(); } public static String generateStringHash(Object obj) throws IllegalAccessException { int intHash = generateIntHash(obj); return Integer.toHexString(intHash); } private static void processNestedObject(Object obj, HashCodeBuilder hcb) throws IllegalAccessException { Class<?> clazz = obj.getClass(); for (Field field : clazz.getDeclaredFields()) { // 跳过静态字段和带排除注解的字段 if (Modifier.isStatic(field.getModifiers()) || field.isAnnotationPresent(ExcludeField.class)) { continue; } field.setAccessible(true); Object value = field.get(obj); if (value != null && !isBasicType(value.getClass())) { // 递归处理嵌套对象 processNestedObject(value, hcb); } else { hcb.append(value); } } } // 判断是否是基础类型或其包装类、字符串 private static boolean isBasicType(Class<?> clazz) { return clazz.isPrimitive() || clazz.equals(Integer.class) || clazz.equals(Long.class) || clazz.equals(Float.class) || clazz.equals(Double.class) || clazz.equals(Boolean.class) || clazz.equals(String.class); } }
- 直接使用:
Car car = new Car(); car.setModelYear(2024); car.setColor("red"); TyreClass tyre = new TyreClass(); tyre.setRadius(18.5f); tyre.setColour("black"); tyre.setWidth(225.0); car.setTyre(tyre); // 生成整数哈希 int intHash = HashGenerator.generateIntHash(car); // 生成字符串哈希 String strHash = HashGenerator.generateStringHash(car);
2. Jackson(序列化JSON后哈希)
如果你的项目已经引入Jackson(很多Web项目都会用),可以通过序列化对象为JSON(自动过滤带注解的字段),再对JSON字符串生成哈希,返回字符串类型(如SHA-256)。
实现步骤
- 复用你的
@ExcludeField注解,配置Jackson识别该注解为忽略字段:
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.introspect.AnnotationIntrospector; import com.fasterxml.jackson.databind.introspect.AnnotatedMember; public class JsonHashGenerator { private static final ObjectMapper objectMapper = new ObjectMapper(); static { // 让Jackson识别@ExcludeField为忽略字段 objectMapper.setAnnotationIntrospector(new AnnotationIntrospector() { private final AnnotationIntrospector delegate = objectMapper.getSerializationConfig().getAnnotationIntrospector(); @Override public boolean hasIgnoreMarker(AnnotatedMember member) { return member.hasAnnotation(ExcludeField.class) || delegate.hasIgnoreMarker(member); } }); } // 生成SHA-256字符串哈希 public static String generateSha256Hash(Object obj) throws Exception { String json = objectMapper.writeValueAsString(obj); java.security.MessageDigest digest = java.security.MessageDigest.getInstance("SHA-256"); byte[] hashBytes = digest.digest(json.getBytes()); StringBuilder hexStr = new StringBuilder(); for (byte b : hashBytes) { String hex = Integer.toHexString(0xff & b); if (hex.length() == 1) hexStr.append('0'); hexStr.append(hex); } return hexStr.toString(); } }
- 使用示例:
String sha256Hash = JsonHashGenerator.generateSha256Hash(car);
3. Google Guava(HashCode)
Guava提供了丰富的哈希算法支持,结合反射可以实现类似的嵌套对象哈希生成,返回字符串哈希值。
实现步骤
import com.google.common.hash.HashFunction; import com.google.common.hash.Hashing; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.nio.charset.StandardCharsets; public class GuavaHashGenerator { private static final HashFunction SHA256 = Hashing.sha256(); public static String generateHash(Object obj) throws IllegalAccessException { if (obj == null) return SHA256.hashString("", StandardCharsets.UTF_8).toString(); com.google.common.hash.Hasher hasher = SHA256.newHasher(); processNested(obj, hasher); return hasher.hash().toString(); } private static void processNested(Object obj, com.google.common.hash.Hasher hasher) throws IllegalAccessException { Class<?> clazz = obj.getClass(); for (Field field : clazz.getDeclaredFields()) { if (Modifier.isStatic(field.getModifiers()) || field.isAnnotationPresent(ExcludeField.class)) { continue; } field.setAccessible(true); Object value = field.get(obj); if (value == null) { hasher.putString("null", StandardCharsets.UTF_8); continue; } Class<?> valueClazz = value.getClass(); // 处理基础类型和包装类 if (valueClazz == int.class || valueClazz == Integer.class) { hasher.putInt((Integer) value); } else if (valueClazz == float.class || valueClazz == Float.class) { hasher.putFloat((Float) value); } else if (valueClazz == double.class || valueClazz == Double.class) { hasher.putDouble((Double) value); } else if (valueClazz == String.class) { hasher.putString((String) value, StandardCharsets.UTF_8); } else { // 递归处理嵌套对象 processNested(value, hasher); } } } }
使用示例:
String guavaHash = GuavaHashGenerator.generateHash(car);
各方案对比
- Apache Commons Lang3:轻量依赖,生成整数哈希,适合不需要长哈希的场景,代码直观易维护。
- Jackson:依赖Jackson(多数项目已引入),序列化逻辑成熟,自动处理复杂嵌套,生成的字符串哈希长度固定,适合持久化存储。
- Google Guava:哈希算法丰富,代码风格简洁,适合本身就用Guava的项目。
内容的提问来源于stack exchange,提问作者user1416932
相关产品推荐
相关产品推荐

