• HibernateProxy异常处理 java.lang.UnsupportedOperationException: Attempted to serialize java.lang.Class: org.hibernate.proxy.HibernateProxy. Forgot to register a type adapter?


    这里使用google的Gson包做JSON转换,因为较早的1.4版本的FieldAttributes类中没有getDeclaringClass()这个方法,这个方法是获取field所属的类,在我的排除策略中会用到。

    排除策略 
      最简单的gson转换可以是这样的,但却没有多少实际的作用。切面日志时,一个实体和其他实体存在关联,这时候就需要通过自定义排除策略决定如何转换关联对象,否则可能出现“爆炸式”的json字符串。 

    Gson gson = new Gson();
    int[] ints = {1, 2, 3, 4, 5};
    String[] strings = {"abc", "def", "ghi"};
    
    // Serialization
    gson.toJson(ints);     ==> prints [1,2,3,4,5]
    gson.toJson(strings);  ==> prints ["abc", "def", "ghi"]

    下面是我定义的一个排除策略的类,能基本满足需求,从内网搬过来的,未测试 

    package com.lingceng.magic.logutil;
    
    import org.apache.commons.lang.ArrayUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import com.google.gson.ExclusionStrategy;
    import com.google.gson.FieldAttributes;
    
    public class TargetStrategy implements ExclusionStrategy {
        private static Logger log = LoggerFactory.getLogger(TargetStrategy.class);
        private Class<?> target;
        private String[] fields;
        private Class<?>[] clazz;
        private boolean reverse;
    
        public TargetStrategy(Class<?> target) {
            super();
            this.target = target;
        }
    
        @Override
        public boolean shouldSkipClass(Class<?> class1) {
            return false;
        }
    
        @Override
        public boolean shouldSkipField(FieldAttributes fieldattributes) {
            Class<?> owner = fieldattributes.getDeclaringClass();
            Class<?> c = fieldattributes.getDeclaredClass();
            String f = fieldattributes.getName();
            boolean isSkip = false;
            
            if (owner == target) {
                if (ArrayUtils.contains(fields, f)) {
                    log.debug("fitler field:{} for class:{}", f, owner);
                    isSkip = true;
                }
                if (ArrayUtils.contains(clazz, c)) {
                    log.debug("fitler class:{} for class:{}", c, owner);
                    isSkip = true;
                }
                if (reverse) {
                    isSkip = !isSkip;
                }
            }
    
            return isSkip;
        }
    
        public void setFields(String[] fields) {
            this.fields = fields;
        }
    
        public void setClazz(Class<?>[] clazz) {
            this.clazz = clazz;
        }
    
        public void setReverse(boolean reverse) {
            this.reverse = reverse;
        }
    }

    使用的时候是这样的 

    TargetStrategy ts = new TargetStrategy(Student.class);
    //这里表示仅转换Student中的id和name属性
    ts.setFields(new String[] {"id", "name"});
    ts.setReverse(true);
    
    Gson gson = new GsonBuilder().setExcludeStrategy(ts).create();
    gson.toJson(teacher);



    HibernateProxy异常处理 
      在使用Hibernate时,那么很可能遇到这样的错误: 
    java.lang.UnsupportedOperationException: Attempted to serialize java.lang.Class: org.hibernate.proxy.HibernateProxy. Forgot to register a type adapter? 
      因为gson在转换时是使用的反射机制,当获取的实体对象还在hibernate代理的时候,例如刚通过Id获取到,这时候获取到的便是代理对象HibernateProxy。这和直接调用实体对象的get方法不同,获取对象的属性就不能起作用。 
      解决的方法便是将代理对象实例化,见下面的代码 

    /**
     * This TypeAdapter unproxies Hibernate proxied objects, and serializes them
     * through the registered (or default) TypeAdapter of the base class.
     */
    public class HibernateProxyTypeAdapter extends TypeAdapter<HibernateProxy> {
    
        public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {
            @Override
            @SuppressWarnings("unchecked")
            public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
                return (HibernateProxy.class.isAssignableFrom(type.getRawType()) ? (TypeAdapter<T>) new HibernateProxyTypeAdapter(gson) : null);
            }
        };
        private final Gson context;
    
        private HibernateProxyTypeAdapter(Gson context) {
            this.context = context;
        }
    
        @Override
        public HibernateProxy read(JsonReader in) throws IOException {
            throw new UnsupportedOperationException("Not supported");
        }
    
        @SuppressWarnings({"rawtypes", "unchecked"})
        @Override
        public void write(JsonWriter out, HibernateProxy value) throws IOException {
            if (value == null) {
                out.nullValue();
                return;
            }
            // Retrieve the original (not proxy) class
            Class<?> baseType = Hibernate.getClass(value);
            // Get the TypeAdapter of the original class, to delegate the serialization
            TypeAdapter delegate = context.getAdapter(TypeToken.get(baseType));
            // Get a filled instance of the original class
            Object unproxiedValue = ((HibernateProxy) value).getHibernateLazyInitializer()
                    .getImplementation();
            // Serialize the value
            delegate.write(out, unproxiedValue);
        }
    }

    使用的时候将该TypeAdapter的Factory注册到GsonBuilder,上面的代码变为 

    Gson gson = new GsonBuilder().setExcludeStrategy(ts)
    .registerTypeAdapterFactory(HibernateProxyTypeAdapter.FACTORY)
    .create();
    gson.toJson(teacher);
  • 相关阅读:
    C语言字符编码处理
    Linux gperf命令
    C语言命令行处理
    深入分析Java ClassLoader原理
    微软Build2016:Xamarin杂记
    Ubuntu下配置Tomcat以指定(非root)身份执行
    Android之弹出多级菜单
    OC基础:Date
    Linux IO 多路复用是什么意思?
    c语言实现输出一个数的每一位
  • 原文地址:https://www.cnblogs.com/beyang/p/5383160.html
Copyright © 2020-2023  润新知