外汇自动跟单网站开发,中国建设银行网站企业,爱网云主机,深圳最新政策说是解决#xff0c;其实不是很完美的解决的#xff0c;写出来只是想记录一下这个问题或者看一下有没有哪位仁兄会的#xff0c;能否知道一二。 下面说说出现问题#xff1a; 问题是这样的#xff0c;当我查询一个一对多的实体的时候#xff0c;工具直接就爆了#xff0…说是解决其实不是很完美的解决的写出来只是想记录一下这个问题或者看一下有没有哪位仁兄会的能否知道一二。 下面说说出现问题 问题是这样的当我查询一个一对多的实体的时候工具直接就爆了差不多我就猜到是哪里死循环了最后等了好久查看原因果然是堆溢出再然后是jsckson的错误。那么必然是序列化的问题了。 这是jackson的错误 at java.security.AccessController.doPrivileged(Native Method)at java.net.URLClassLoader.findClass(URLClassLoader.java:354)at java.lang.ClassLoader.loadClass(ClassLoader.java:425)at java.lang.ClassLoader.loadClass(ClassLoader.java:412)at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)at java.lang.ClassLoader.loadClass(ClassLoader.java:358)at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1617)at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1547)at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:691)at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:157)at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:656)at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:675)at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:157) 这是循环引用的错误 严重: Servlet.service() for servlet [springDispatcherServlet] in context with path [/Shop] threw exception [Request processing failed; nested exception is org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Infinite recursion (StackOverflowError) (through reference chain: com.web.module.index.model.entity.Account[user]-com.web.module.index.model.entity.User[accounts]-org.hibernate.collection.internal.PersistentSet[0]-com.web.module.index.model.entity.Account[user]-com.web.module.index.model.entity.User[accounts]-org.hibernate.collection.internal.PersistentSet[0]-com.web.module.index.model.entity.Account[user]-com.web.module.index.model.entity.User[accounts]-org.hibernate.collection.internal.PersistentSet[0]-com.web.module.index.model.entity.Account[user]-com.web.module.index.model.entity.User[accounts]-org.hibernate.collection.internal.PersistentSet[0]-com.web.module.index.model.entity.Account[user]-com.web.module.index.model.entity.User[accounts]-org.hibernate.collection.internal.PersistentSet[0]-com.web.module.index.model.entity.Account[user]-com.web.module.index.model.entity.User[accounts]-org.hibernate.collection.internal.PersistentSet[0]-com.web.module.index.model.entity.Account[user]-com.web.module.index.model.entity.User[accounts]-org.hibernate.collection.internal.PersistentSet[0]-
j。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。还有很多的相同的错误 下面是两个实体 User.java: package com.web.module.index.model.entity;import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;import org.hibernate.validator.constraints.NotEmpty;import com.fasterxml.jackson.annotation.JsonIgnore;XmlAccessorType(XmlAccessType.FIELD)
XmlRootElement(nameuser)
Entity
public class User implements Serializable{/*** */private static final long serialVersionUID 1L;XmlElementIdprivate String id;/*** validate适用于springmvc*/XmlElement//NotEmptyprivate String name;JsonIgnoreOneToMany(mappedByuser,targetEntityAccount.class,fetchFetchType.EAGER)private SetAccount accountsnew HashSetAccount();public String getName() {return name;}public void setName(String name) {this.name name;}public String getId() {return id;}public void setId(String id) {this.id id;}public SetAccount getAccounts() {return accounts;}public void setAccounts(SetAccount accounts) {this.accounts accounts;}Overridepublic String toString() {return User [id id , name name , accounts accounts ];}} Account.java: package com.web.module.index.model.entity;import java.io.Serializable;import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;import com.fasterxml.jackson.annotation.JsonIgnore;Entity
public class Account implements Serializable{/*** */private static final long serialVersionUID 1L;Idprivate String id;private String code;private String password;JsonIgnoreJoinColumn(nameuser_id)ManyToOne(targetEntityUser.class,fetchFetchType.EAGER)private User user;public String getId() {return id;}public void setId(String id) {this.id id;}public String getCode() {return code;}public void setCode(String code) {this.code code;}public String getPassword() {return password;}public void setPassword(String password) {this.password password;}public User getUser() {return user;}public void setUser(User user) {this.user user;}Overridepublic String toString() {return Account [id id , code code , password password , user user ];}} 后来去网上看了一下这个问题很多人遇到。解决方案也有很多. 1.在关联的实体上面设置JsonIgnore,这个注解的意思是表示在序列化的时候忽略这个属性.但是我现在的逻辑是在页面中必须使用到这个关联实体中的属性所以就不能这么做了不然在页面中是取不出这个数据的。 Uncaught TypeError: Cannot read property name of undefined1,2都会出现 2.采用单向多对一的形式这样就不会出现循环的问题这个确实是个方案但是如果在一的那边需要使用到多的这边的话就不好搞了。所以感觉还是不是很满意。 3.后来想了想既然是这样要不我在一的那边使用JsonIgnore吧。目前在页面中没使用。其实这个是第二个是差不多的有点不同的是除了页面展示的时候不能够显示多的那面的数据在其他的业务中还是能够使用的。这也是我在前面说不是很满意的解决办法。 4.第四种解决就是前面的3差不多当我们使用多的一边的时候可以正确的显示但是在我们使用一的那一端的时候我们可以使用List自己拼装有点像下面的代码 RequestMapping(valueresult/{id},methodRequestMethod.GET)public ResponseBody List? result(PathVariable(id) String id){System.out.println(id);ListMapString,Object listLists.newArrayList();//MapString,Object mapnew HashMapString,Object();MapString,Object mapnull;Random rnew Random();DecimalFormat dfmtnew DecimalFormat(#,###.00);for(int i0;i4;i){int pricer.nextInt(10)1;int numberr.nextInt(100000)10000;mapnew HashMapString,Object();map.put(tradegoods, 煤i);map.put(units, 顿);map.put(consumer, XX物流id);map.put(unitPrice, dfmt.format(price));map.put(number, dfmt.format(number));map.put(count, dfmt.format(price*number));list.add(map);}//设置日期格式 return list;} 这样jackson序列化的时候就不会出错了而且使用起来就不用像A.B.name这样了而且使用起来也更加的简单。我们在JS里面就可以这样使用 if(id!id){$.ajax({type: GET,url: $ctx /example/demo/result/id,dataType: json,success: function(data) {for(var i0;idata.length;i){data[i].numi1;}//alert(JSON.stringify(data));viewModel.result(data);$(.notice-hide).show();$(.notice-show).hide();},error: function(req, textStatus, errorThrown){}}); html: tbody data-bindforeach: resulttrtd data-bindtext:num/tdtd data-bindtext:tradegoods/tdtd data-bindtext:units/tdtd data-bindtext:consumer/tdtd data-bindtext:unitPrice classformat_/tdtd data-bindtext:number classformat_/tdtd data-bindtext:count classformat_/td/tr/tbody 这样就完美的解决了这个问题。 5添加Filter的方式进行动态的过滤属性 上面的解决方法还是或多或少的影响到我们正常的使用类下面说的方法是不会影响放到原有的类的。 jsckson的ObjectMapper有一个 public final void addMixInAnnotations(Class? target, Class? mixinSource){_mixInAnnotations.put(new ClassKey(target), mixinSource);}public final Class? findMixInClassFor(Class? cls) {return (_mixInAnnotations null) ? null : _mixInAnnotations.get(new ClassKey(cls));}public final int mixInCount() {return (_mixInAnnotations null) ? 0 : _mixInAnnotations.size();} 这样的方法这个方法的使用就要结合JsonIgnoreProperties注解一起来进行使用。我们需要定义一个接口这个接口的作用是用来专门的过滤属性的。 还是针对上面的例子我们要解决问题的话 我们需要在定义一个接口: package com.hotusm.jackson;import com.fasterxml.jackson.annotation.JsonIgnoreProperties;JsonIgnoreProperties(ignoreUnknowntrue,value{user})
public interface AccountFilter {
} 这个接口非常简单就是一个注解注解其中的value就是表示的是我们需要将那些属性给忽略掉增加了这么一个接口后我们就可以使用上面提到的方法。 objectMapper.addMixInAnnotations(Account.class, AccountFilter.class); 之后再使用这个objectmapper的时候在account类上面的user就不会被忽略掉了通过这种方式我们不用修改原来类的任何地方。但是这种方式需要我们重新创建一个接口所以下面一种就是解决这种每次都要创建的痛苦了。 6.利用自定义注解的方式来进行过滤这种方式也是看到其他人使用感觉非常好也就做一个简单的总结。 大概的讲一下思路 1.还是使用addMixInAnnotations方法但是不需要我们每次都创建一个接口而是采用全注解的形式来。也许会很奇怪前面的方法命名 是传入两个class啊 我们不手动创建的话那该怎样的去调用呢。这里我们使用字节码技术Javassist来动态的创建class。 2.大概的思路就是我们自定义方法级别注解注解上面可以指定某些类上的哪些属性需要忽略。然后对这些方法进行增强增强逻辑中获取到这些注解中的类以及这个类上面忽略的 下面是上面理论的一个简单的实践: 第一步:自定义注解: package com.hotusm.jackson.annotation;import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;Target(ElementType.METHOD)
Documented
Retention(RetentionPolicy.RUNTIME)
Inherited
public interface IgnoreProperty {/*** 指定类*/Class? pojo();/***指定上面的类那些属性需要过滤的 */String[] value();
} 上面这个注解就是我们后面要使用到的动态的在方法上面直接指定类需要忽略的属性。 第二步:对ObjectMapper进行装饰写的例子不是很优雅 package com.hotusm.jackson.annotation;import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashSet;import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.bytecode.AnnotationsAttribute;
import javassist.bytecode.ClassFile;
import javassist.bytecode.ConstPool;
import javassist.bytecode.annotation.Annotation;
import javassist.bytecode.annotation.ArrayMemberValue;
import javassist.bytecode.annotation.BooleanMemberValue;
import javassist.bytecode.annotation.MemberValue;
import javassist.bytecode.annotation.StringMemberValue;import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.ObjectMapper;public class ObjectMapperBuilder {public ObjectMapper build(Method method) throws CannotCompileException{IgnoreProperty ignoreProperty method.getAnnotation(IgnoreProperty.class);String[] value ignoreProperty.value();Class? pojo ignoreProperty.pojo();checkParamter(method,value,pojo);Class? clazzdoBuild(value);ObjectMapper objectMappernew ObjectMapper();objectMapper.addMixInAnnotations(pojo, clazz);return objectMapper;}/*** 根据传入的参数构造一个class* throws CannotCompileException */public Class? doBuild(String[] values) throws CannotCompileException{ClassPool pool ClassPool.getDefault();CtClass cc pool.makeInterface(ProxyMixInAnnotation System.currentTimeMillis());ClassFile classFile cc.getClassFile();ConstPool cp classFile.getConstPool();AnnotationsAttribute attr new AnnotationsAttribute(cp,AnnotationsAttribute.visibleTag);Annotation jsonIgnorePropertiesAnnotation new Annotation(JsonIgnoreProperties.class.getName(), cp);BooleanMemberValue ignoreUnknownMemberValue new BooleanMemberValue(false, cp);//ArrayMemberValue arrayMemberValue new ArrayMemberValue(cp);CollectionMemberValue memberValues new HashSetMemberValue();for(int i0;ivalues.length;i){StringMemberValue memberValue new StringMemberValue(cp);// 将name值设入注解内memberValue.setValue(values[i]);memberValues.add(memberValue);}arrayMemberValue.setValue(memberValues.toArray(new MemberValue[]{}));jsonIgnorePropertiesAnnotation.addMemberValue(value, arrayMemberValue);jsonIgnorePropertiesAnnotation.addMemberValue(ignoreUnknown, ignoreUnknownMemberValue);attr.addAnnotation(jsonIgnorePropertiesAnnotation);classFile.addAttribute(attr); Class clazz cc.toClass();return clazz;}protected void checkParamter(Object... objs){boolean isTruetrue;if(objsnull||objs.length0){isTruefalse;}for(Object obj:objs){if(objnull){isTruefalse;}}if(!isTrue){throw new RuntimeException(参数出现错误);}}
} 上面这一步我们已经看到了熟悉的addMixInAnnotations。后面的参数就是我们使用javassist根据value数组创建的动态类这个动态类增加了一个很重要的注解就是JsonIgnoreProperties这个注解就是我们6中讲的过滤属性的现在通过build方法返回的ObjectMapper已经满足了动态的过滤属性的。 下面是一个测试: TestIgnoreProperty(pojoArticle.class,value{user})public void testJacksonAnnotation(){User usernew User();user.setName(hotusm);Article a1new Article();a1.setTitle(t1);a1.setUser(user);Article a2new Article();a2.setTitle(t2);a2.setUser(user);Article a3new Article();a3.setTitle(t3);a3.setUser(user);ListArticle asnew ArrayListArticle();as.add(a1);as.add(a2);as.add(a3);user.setArticles(as);ObjectMapper objectMapper;try {objectMapper new ObjectMapperBuilder().build(Main.class.getMethod(testJacksonAnnotation));String str objectMapper.writeValueAsString(user);System.out.println(str);} catch (Exception e) {e.printStackTrace();}} 在打印出来的json数据我们就可以明显的看出来已经把Article中的user属性给过滤掉了。注意user和article是一对多的关系 总结:因为上面写的一个例子只是为了显示出问题并没有进行代码的优化以及功能的完善如果是要在生产过程中使用的话我们完全可以这样做:1.注解可以在类或者是方法上面2.所有多出来的操作都应该是对客户端程序员来说是透明的我们可以通过方法的增强以及对ObjectMapper进行装饰。3.将方法或者类上面的注解信息放入到缓存中去而不用发每次都要提取一次转载于:https://www.cnblogs.com/zr520/p/5357459.html