将HttpServletRequest转换为JSON的java.lang.StackOverflowError [英] java.lang.StackOverflowError converting HttpServletRequest to JSON

查看:412
本文介绍了将HttpServletRequest转换为JSON的java.lang.StackOverflowError的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  @Aspect 
@Component

在我的spring rest应用程序中,我记录了每个api端点参数。
public class EndpointsAspect {

@Around(execution(@ org.springframework.web.bind.annotation.RequestMapping * *(..)))
public Object handle (ProceedingJoinPoint joinPoint)抛出Throwable {

Map< String,Object> log = new HashMap<>();


String [] parameterNames = methodSignature.getParameterNames();
Object [] parameterValues = joinPoint.getArgs();

地图< String,Object> arguments = new HashMap<>();

for(int i = 0; i< parameterNames.length; i ++){
arguments.put(parameterNames [i],parameterValues [i]);
}
log.put(Method arguments,arguments);

Gson gson = new GsonBuilder()。setPrettyPrinting()。create();
String json = gson.toJson(log);

...

Object retVal = joinPoint.proceed();
}

}

工作正常, adviced方法的参数具有HttpServletRequest类型的参数

$ $ $ $ $ $ $ $ $ $ $ $ $公共字符串索引(HttpServletRequest请求){
返回信息;

在这种情况下引发java.lang.StackOverflowError。



我知道这与HttpServlterRequest变量(也许是一些不定式循环)有关,但是如何解决这个问题?

Ho来限制gson的深度?



我已经看过一些解决方案(注释应该转换为json的字段或类,并带有一些注释),但它不适合我,这应该是所有类和案例的通用解决方案(例如,我不能用一些注释来注释HttpServletRequest,或者将它包含到排除策略中,因为谁不能将这些类转换为json),我需要将日志数据作为json,但由于序列化问题,记录器不应该是应用程序故障点。



谢谢。

解决方案

我找到了一些解决方案并回答了我的问题。

对于json序列化程序,我使用flexjson库( http://flexjson.sourceforge.net/ )。它支持具有双向关系的类的序列化,而没有任何注释和其他额外的工作。

在HttpServletRequest的情况下,我在try catch块中包装序列化并记录它,例如,参数请求不能被序列化。

  @Around(execution(@ org.springframework.web.bind.annotation.RequestMapping * *(..)) )
public Object handle(ProceedingJoinPoint joinPoint)throws Throwable {

MethodSignature methodSignature =(MethodSignature)joinPoint.getSignature();

地图< String,Object> log = new HashMap<>();
log.put(Method,joinPoint.getSignature()。toString());

String [] parameterNames = methodSignature.getParameterNames();
Object [] parameterValues = joinPoint.getArgs();

地图< String,Object> arguments = new HashMap<>();
for(int i = 0; i< parameterNames.length; i ++){
//检查参数是否可以被序列化并且如果可能的话将参数放到参数列表中。例如,HttpServletRequest无法序列化
尝试{
JSONSerializer serializer = new JSONSerializer();
String json = serializer.prettyPrint(true).deepSerialize(parameterValues [i]);
arguments.put(parameterNames [i],parameterValues [i]);

catch(Exception serializerException){
arguments.put(parameterNames [i],Could not serialize argument。+ serializerException.getMessage());


log.put(Method arguments,arguments);

...

尝试{
JSONSerializer serializer = new JSONSerializer();
String json = serializer.prettyPrint(true).deepSerialize(log);
logger.info(json);

catch(Exception e){
logger.error(无法序列化数据。+ e.getMessage());
}

...
}

日志看起来像这样:

  {
Path:/ v1 / users / 1,
Http状态:200 OK,
方法参数:{
request:无法序列化参数,错误尝试deepSerialize,
id :1
},
Headers:{
accept-language:en-US,en; q = 0.8,
cookie:lbannounce =; ServiceTransactionSuccess = false; ServiceTransactionAmount = false; ServiceTransactionWidgetType = false; ServiceTransactionDomain = false; _ga = GA1.1.1011235846.1448355706,
host:localhost:8080,
connection:保持活着,
accept-encoding:gzip,deflate,sdch,
accept:text / html,application / xhtml + xml,application / xml; q = 0.9, image / webp,* / *; q = 0.8,
user-agent:Mozilla / 5.0(Windows NT 6.2; WOW64)AppleWebKit / 537.36(KHTML,像Gecko)Chrome / 43.0.2357.124 Safar i / 537.36

返回值:{
class:api.domain.User,
email:user@mail.com ,
id:1,
username:user111
},
Ip:0:0:0:0:0:0: 0:1,
Http Method:GET,
Method:User api.web.UserController.user(int,HttpServletRequest)
}


In my spring rest app, I log every api endpoints arguments in aspect.

@Aspect
@Component
public class EndpointsAspect {

   @Around("execution(@org.springframework.web.bind.annotation.RequestMapping * *(..))")
   public Object handle(ProceedingJoinPoint joinPoint) throws Throwable {

      Map<String, Object> log = new HashMap<>();


      String[] parameterNames =  methodSignature.getParameterNames();
      Object[] parameterValues = joinPoint.getArgs();

      Map<String, Object> arguments = new HashMap<>();

        for (int i = 0; i < parameterNames.length; i++) {
            arguments.put(parameterNames[i], parameterValues[i]);
        }
        log.put("Method arguments", arguments);

        Gson gson = new GsonBuilder().setPrettyPrinting().create();
        String json = gson.toJson(log);

        ...

        Object retVal = joinPoint.proceed();
   }

}

It works fine, until one of argument of adviced method has argument of type HttpServletRequest

    @RequestMapping("/info")
    public String index(HttpServletRequest request) {  
        return "Info";
    }

In this case java.lang.StackOverflowError is raised.

I know that this is somehow related to HttpServlterRequest variable (maybe some infinitive loop), but how to solve this problem?

Ho to limit gson depth?

I've looked at some solutions (annotate fields or classes that should be converted to json with some annotations), but it's not suitable for me, this should be universal solutions for all classes and cases (I acn't, for instance, annotate HttpServletRequest with some annotations, or include it to gson exclusion strategy, because who nows wich classes will be converted to json), I need log data as json, but logger shouldn't be application fault point because of serialization issue.

Thank you.

解决方案

I've found some solution and answer my question.

For json serializer I use flexjson library (http://flexjson.sourceforge.net/). It supports serialization of classes which have bidirectional relationship without any annotations and other extra work.

In case of HttpServletRequest, I wrap serialization in try catch block and log that, for example, argument "request" could not be serialized.

@Around("execution(@org.springframework.web.bind.annotation.RequestMapping * *(..))")
public Object handle(ProceedingJoinPoint joinPoint) throws Throwable {

    MethodSignature methodSignature = (MethodSignature)joinPoint.getSignature();

    Map<String, Object> log = new HashMap<>();
    log.put("Method", joinPoint.getSignature().toString());

    String[] parameterNames =  methodSignature.getParameterNames();
    Object[] parameterValues = joinPoint.getArgs();

    Map<String, Object> arguments = new HashMap<>();
    for (int i = 0; i < parameterNames.length; i++) {
      // Check if argument can be serialized and put arguments to argument list if possible. For example, HttpServletRequest cannot be serialized
      try {
         JSONSerializer serializer = new JSONSerializer();
         String json = serializer.prettyPrint(true).deepSerialize(parameterValues[i]);
         arguments.put(parameterNames[i], parameterValues[i]);
      }
      catch (Exception serializerException) {
         arguments.put(parameterNames[i], "Couldn't serialize argument. "+serializerException.getMessage());
      }    
    }
   log.put("Method arguments", arguments);

   ...

   try {
     JSONSerializer serializer = new JSONSerializer();
     String json = serializer.prettyPrint(true).deepSerialize(log);
     logger.info(json);
   }
   catch (Exception e) {
     logger.error("Could not serialize data. "+e.getMessage());
   }       

   ... 
}

And log looks something like this:

{
    "Path": "/v1/users/1",
    "Http Status": "200 OK",
    "Method arguments": {
        "request": "Couldn't serialize argument. Error trying to deepSerialize",
        "id": 1
    },
    "Headers": {
        "accept-language": "en-US,en;q=0.8",
        "cookie": "lbannounce=; ServiceTransactionSuccess=false; ServiceTransactionAmount=false; ServiceTransactionWidgetType=false; ServiceTransactionDomain=false; _ga=GA1.1.1011235846.1448355706",
        "host": "localhost:8080",
        "connection": "keep-alive",
        "accept-encoding": "gzip, deflate, sdch",
        "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
        "user-agent": "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.124 Safari/537.36"
    },
    "Return Value": {
        "class": "api.domain.User",           
        "email": "user@mail.com",
        "id": 1,         
        "username": "user111"
    },
    "Ip": "0:0:0:0:0:0:0:1",
    "Http Method": "GET",
    "Method": "User api.web.UserController.user(int,HttpServletRequest)"
} 

这篇关于将HttpServletRequest转换为JSON的java.lang.StackOverflowError的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆