Spring and ThreadLocal

1.3k views Asked by At

I have a spring web app. Whenever in the app, there is an error, I put the error in the error context (code given below). Then, I retrieve the error in the Exception handler and return a message. Now, say for input A, if the error message is "Person is not there" Now, for the first call to the spring web app, I get the right output: "Person is not there" however, for the second call: I get the output : "Person is not there" , "Person is not there" Thus, it is remembers my last request even though I am using a ThreadLocal. Can someone please help

My ErrorContext code:

public class ErrorContext {

private static ThreadLocal<ErrorContext> thisObj = new ThreadLocal<ErrorContext>();

/**
 * List of errors.
 */
private ArrayList<ApplicationError> errorList;

/**
 * Default private constructor.
 */
private ErrorContext() {
    errorList = new ArrayList<ApplicationError>();
}

/**
 * Initialize the ThreadLocal variable.
 */
public static void initialize() {
    if (thisObj.get() == null)
        thisObj.set(new ErrorContext());
    else {
        ErrorContext errorContext = (ErrorContext) thisObj.get();
        if (errorContext.getErrors() != null)
            errorContext.getErrors().clear();

    }
}

/**
 * Returns a new instance of the class.
 *
 * @return {@link ErrorContext}.
 */
public static ErrorContext getInstance() {
    if (thisObj.get() == null) {
        thisObj.set(new ErrorContext());
    }
    return (ErrorContext) thisObj.get();
}

/**
 * Add the error code to the List.
 *
 * @param errorCode
 *            errorCode obtained.
 */
public void addError(final ApplicationError error) {
    errorList.add(error);
}

/**
 * Return the List of errorCodes.
 *
 * @return List of error codes.
 */
public List<ApplicationError> getErrors() {
    return errorList;
}

/**
 * @author anbapri resets the context.
 */
public static void resetContext() {
    thisObj.set(new ErrorContext());
    ErrorContext errorContext = (ErrorContext) thisObj.get();
    if (errorContext.getErrors() != null)
        errorContext.getErrors().clear();
}

/**
 * Returns true if ErrorContext has error, otherwise false.
 *
 * @return
 */
public boolean hasError() {
    return !errorList.isEmpty();
}

}

My Response handler {
package com.db.wscis.core.web.handler;

import java.util.ArrayList; import java.util.List; import java.util.Locale;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.MessageSource; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus;

import com.db.wscis.core.util.exception.ApplicationError; import com.db.wscis.core.util.exception.ApplicationException; import com.db.wscis.core.util.exception.ErrorContext; import com.db.wscis.core.web.model.ApplicationErrorRes; import com.db.wscis.core.web.model.BaseResponse; import com.db.wscis.core.web.model.ResponseObject;

@ControllerAdvice public class RestExceptionProcessor {

private static final Log logger = LogFactory
        .getLog(RestExceptionProcessor.class);

@Autowired
private MessageSource messageSource;

@ExceptionHandler(Exception.class)
@ResponseStatus(value = HttpStatus.NOT_FOUND)
@ResponseBody
public ResponseObject handleException(HttpServletRequest req, Exception excpt) {
    logger.error("",excpt);
//  Locale locale = LocaleContextHolder.getLocale();
    ResponseObject res = new ResponseObject();
//  String errorMessageDesc;
    res.setResultMessage("failure");
    //Business validation exception
    if (excpt instanceof ApplicationException) {
        List<ApplicationError> errorMessages = ErrorContext.getInstance()
                .getErrors();
        List<ApplicationErrorRes> errorMessageRes=new ArrayList<ApplicationErrorRes>();

        for(int i=0;i<errorMessages.size();i++){

        ApplicationErrorRes appErrorRes=    mapApplicationErrorToApplicationErrorRes(errorMessages.get(i));
        errorMessageRes.add(appErrorRes);

        }

        res.setApplicationErrors(errorMessageRes);
    } 
    //Other generic exception
    else {
        ArrayList<Exception> exceptionList=new ArrayList<Exception>();
        exceptionList.add(excpt);
        res.setExceptionList(exceptionList);
    }
    return res;
}

private ApplicationErrorRes mapApplicationErrorToApplicationErrorRes(ApplicationError appError){


    ApplicationErrorRes res=new ApplicationErrorRes();
    res.setErrorCode(appError.getErrorCode());
    res.setErrorLevel(appError.getErrorLevel());
    res.setErrorMessage(appError.getErrorMessage());

    return res;



}

} }

1

There are 1 answers

0
TimeToCodeTheRoad On

The way to fix this is to do ErrorContext.resetContext() after the end of the exception handler.