Handling Null values in postgres for text array type column in org.hibernate.PropertyAccessException - spring

we got a strange scenario in our Hibernate based web application.
On the Database postgresql,there is a column field of text[] type and some of the values are Null. In my entity class I have mapped it to String[] and When I run a CriteriaBuilder select query I am getting exception saying
Request processing failed; nested exception is javax.persistence.PersistenceException: org.hibernate.PropertyAccessException: could not set a field value by reflection setter
I am using #Type(type = "GenericArrayUserType") annotation on String[] in entity class.

Please use the below custom GenericStringArrayUserType mapping for your String[] attribute.
#Type(type = "ai.test.GenericStringArrayUserType")
private String[] fields;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.usertype.UserType;
public class GenericStringArrayUserType<T extends Serializable> implements UserType {
protected static final int[] SQL_TYPES = {Types.ARRAY};
private Class<T> typeParameterClass;
#Override
public int[] sqlTypes() {
return new int[]{Types.ARRAY};
}
#Override
public Class<T> returnedClass() {
return typeParameterClass;
}
#Override
public boolean equals(Object x, Object y) throws HibernateException {
if (x == null) {
return y == null;
}
return x.equals(y);
}
#Override
public int hashCode(Object x) throws HibernateException {
return x.hashCode();
}
#Override
public Object nullSafeGet(ResultSet resultSet, String[] names, SessionImplementor session, Object owner)
throws HibernateException, SQLException {
/*
if (resultSet.wasNull()) {
return null;
}
*/
if (resultSet.getArray(names[0]) == null) {
return new String[0];
}
Array array = resultSet.getArray(names[0]);
#SuppressWarnings("unchecked")
T javaArray = (T) array.getArray();
return javaArray;
}
#Override
public void nullSafeSet(PreparedStatement statement, Object value, int index, SessionImplementor session)
throws HibernateException, SQLException {
Connection connection = statement.getConnection();
if (value == null) {
statement.setNull(index, SQL_TYPES[0]);
} else {
#SuppressWarnings("unchecked")
T castObject = (T) value;
Array array = connection.createArrayOf("text", (Object[]) castObject);
statement.setArray(index, array);
}
}
#Override
public Object deepCopy(Object value) throws HibernateException {
return value;
}
#Override
public boolean isMutable() {
return true;
}
#SuppressWarnings("unchecked")
#Override
public Serializable disassemble(Object value) throws HibernateException {
return (T) this.deepCopy(value);
}
#Override
public Object assemble(Serializable cached, Object owner) throws HibernateException {
return this.deepCopy(cached);
}
#Override
public Object replace(Object original, Object target, Object owner) throws HibernateException {
return original;
}
}

Related

Replace RequestResponseBodyMethodProcessor with CustomMethodProcessor using BeanPostProcessor

How can I swap RequestResponseBodyMethodProcessor with CustomRequestResponseBodyMethodProcessor in the BeanPostProcessor postProcessAfterInitialization() method?
I have copied entire code from RequestResponseBodyMethodProcessor and made some modification in my CustomRequestResponseBodyMethodProcessor.
Now I want Spring to use my CustomRequestResponseBodyMethodProcessor, not the inbuilt.
So tried overwriting in postProcessAfterInitialization() by implementing BeanPostProcessor.
In the below forum, where it says "create a new list of it, replace the normal RequestResponseBodyMethodProcessor with your custom implementation", how can I get handle to do this?
For Reference:
http://forum.spring.io/forum/spring-projects/web/130803-how-to-extend-requestresponsebodymethodprocessor-and-configure-it-in-webmvc-config-xm
Pseudo Code:
class BaseInsert {
commonattribute1;
commonattribute1;
}
class ChildInsert extends BaseInsert {
childattribute1;
childattribute2;
}
#PostMapping("/abc")
public Resource<?> insert(#RequestBody BaseInsert baseInsert){
...
}
I changed the code in CustomRequestResponseBodyMethodProcessor to assign ChildInsert in BaseInsert.
Solution 1: I will recommend this solution the most
#Configuration
#EnableWebMvc
public class AdapterConfig extends WebMvcConfigurerAdapter {
private final ApplicationContext applicationContext;
#Autowired
public TrackingAdapterConfig(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver>reso) {
super.addArgumentResolvers(reso);
reso.add( new CustomRequestBodyMethodProcessor(); }
}
public class CustomProcessor extends RequestResponseBodyMethodProcessor {
#Override
public boolean supportsParameter(MethodParameter parameter) {
return (parameter.getNestedGenericParameterType().getTypeName()
.equalsIgnoreCase(BaseInsert.class.getName()));
}
#Override protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter,Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
BaseInsert request = childInsert;
return super.readWithMessageConverters(webRequest, parameter, request.getClass());
}
}
Solution 2: This is also good solution but less performant because BeanPostProcessor interface has 2 methods 'postProcessBeforeInitialization()' and 'postProcessAfterInitialization()'.
So when you provide your implementation of this BeanPostProcessor interface with the class annotated as '#Configuration'.
postProcessBeforeInitialization() - This method is called every time before beans are created
postProcessAfterInitialization() - This method is called every time after beans are created.This is the place where CustomResolver can be added to list of resolvers
#Configuration
public class TestBeanPostProcessor implements BeanPostProcessor {
#Override
public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
return o;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equalsIgnoreCase("requestMappingHandlerAdapter")) {
RequestMappingHandlerAdapter requestMappingHandlerAdapter = (RequestMappingHandlerAdapter) bean;
List<HandlerMethodArgumentResolver> argumentResolvers = requestMappingHandlerAdapter.getArgumentResolvers();
List<HandlerMethodArgumentResolver> modifiedArgumentResolvers = new ArrayList<>(argumentResolvers.size());
for(int i =1; i< argumentResolvers.size();i++){
modifiedArgumentResolvers.add(argumentResolvers.get(i));
}
modifiedArgumentResolvers.add(new TestRequestBodyMethodProcessor(requestMappingHandlerAdapter.getMessageConverters(), new ArrayList<Object>()));
((RequestMappingHandlerAdapter) bean).setArgumentResolvers(null);
((RequestMappingHandlerAdapter) bean).setArgumentResolvers(modifiedArgumentResolvers);
}
return bean;
}
}
public class TestRequestBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
public TestRequestBodyMethodProcessor(List<HttpMessageConverter<?>> converters) {
super(converters);
}
public TestRequestBodyMethodProcessor(List<HttpMessageConverter<?>> converters, ContentNegotiationManager manager) {
super(converters, manager);
}
public TestRequestBodyMethodProcessor(List<HttpMessageConverter<?>> converters, List<Object> requestResponseBodyAdvice) {
super(converters, null, requestResponseBodyAdvice);
}
public TestRequestBodyMethodProcessor(List<HttpMessageConverter<?>> converters,
ContentNegotiationManager manager, List<Object> requestResponseBodyAdvice) {
super(converters, manager, requestResponseBodyAdvice);
}
#Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(RequestBody.class);
}
#Override
public boolean supportsReturnType(MethodParameter returnType) {
return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
returnType.hasMethodAnnotation(ResponseBody.class));
}
#Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
parameter = parameter.nestedIfOptional();
BaseInsert trans_type_code = ;
Object arg = readWithMessageConverters(webRequest, parameter,
Test.getModelClassObject().getClass());
String name = Conventions.getVariableNameForParameter(parameter);
WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
if (arg != null) {
validateIfApplicable(binder, parameter);
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
}
}
mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
return adaptArgumentIfNecessary(arg, parameter);
}
#Override
protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter,
Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest);
Object arg = readWithMessageConverters(inputMessage, parameter, paramType);
if (arg == null) {
if (checkRequired(parameter)) {
throw new HttpMessageNotReadableException("Required request body is missing: " +
parameter.getMethod().toGenericString());
}
}
return arg;
}
protected boolean checkRequired(MethodParameter parameter) {
return (parameter.getParameterAnnotation(RequestBody.class).required() && !parameter.isOptional());
}
#Override
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
mavContainer.setRequestHandled(true);
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
// Try even with null return value. ResponseBodyAdvice could get involved.
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
}
I tried the Solution 1 from previous post but also need this:
#Autowired
private RequestMappingHandlerAdapter adapter;
#PostConstruct
public void prioritizeCustomArgumentMethodHandlers () {
List<HandlerMethodArgumentResolver> argumentResolvers = new ArrayList<>(adapter.getArgumentResolvers ());
List<HandlerMethodArgumentResolver> customResolvers = adapter.getCustomArgumentResolvers();
argumentResolvers.removeAll(customResolvers);
argumentResolvers.addAll (0, customResolvers);
adapter.setArgumentResolvers (argumentResolvers);
}
Without this code, program doesn´t stop at my custom RequestResponseBodyMethodProcessor.
You can check my post : Override default message when #ResponseBody is null

Spring Boot escape characters at Request Body for XSS protection

I'm trying to secure my spring boot application using a XSSFilter like this:
public class XSSFilter implements Filter {
#Override
public void init(FilterConfig filterConfig) throws ServletException { }
#Override
public void destroy() { }
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
chain.doFilter(new XSSRequestWrapper((HttpServletRequest) request), response);
}
}
And the wrapper:
public class XSSRequestWrapper extends HttpServletRequestWrapper {
public XSSRequestWrapper(HttpServletRequest servletRequest) {
super(servletRequest);
}
#Override
public String[] getParameterValues(String parameter) {
String[] values = super.getParameterValues(parameter);
if (values == null) {
return null;
}
int count = values.length;
String[] encodedValues = new String[count];
for (int i = 0; i < count; i++) {
encodedValues[i] = replaceXSSCharacters((values[i]));
}
return encodedValues;
}
private String replaceXSSCharacters(String value) {
if (value == null) {
return null;
}
return value
.replace("&","&")
.replace("<", "<")
.replace(">",">")
.replace("\"",""")
.replace("'","'");
}
#Override
public String getParameter(String parameter) {
return replaceXSSCharacters(super.getParameter(parameter));
}
#Override
public String getHeader(String name) {
return replaceXSSCharacters(super.getHeader(name));
}
}
The problem is, that only secures the Request parameters and Headers, not the Request body, and sometimes my Controller receive data using #RequestBody.
So, if i submit to my controller a json like this:
{"name":"<script>alert('hello!')</script>"}
The html chars at the name property doesn't get escaped like i need. How can i escape the RequestBody?
EDIT:
This is different from the "duplicated" question. My question is very Specific. How to escape characters on Request Body.
To remove XSS characters you just override AbstractJackson2HttpMessageConverter - this converter has responsibility to read request.inputStream to RequestBody object
#Component
public class XSSRequestBodyConverter extends AbstractJackson2HttpMessageConverter {
public XSSRequestBodyConverter(ObjectMapper objectMapper) {
super(objectMapper, MediaType.APPLICATION_JSON, new MediaType("application", "*+json"));
}
#Override
public Object read(Type type, Class<?> contextClass, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
Object requestBody = super.read(type, contextClass, inputMessage);
//Remove xss from requestBody here
String requestInStr = objectMapper.writeValueAsString(requestBody);
return objectMapper.readValue(replaceXSSCharacters(requestInStr), Object.class);
}
}
I resolved with a custom class:
#Configuration
public class AntiXSSConfig {
#Autowired()
public void configeJackson(ObjectMapper mapper) {
mapper.getFactory().setCharacterEscapes(new HTMLCharacterEscapes());
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
public static class HTMLCharacterEscapes extends JsonpCharacterEscapes {
#Override
public int[] getEscapeCodesForAscii() {
int[] asciiEscapes = CharacterEscapes.standardAsciiEscapesForJSON();
// and force escaping of a few others:
asciiEscapes['<'] = CharacterEscapes.ESCAPE_CUSTOM;
asciiEscapes['>'] = CharacterEscapes.ESCAPE_CUSTOM;
asciiEscapes['&'] = CharacterEscapes.ESCAPE_CUSTOM;
asciiEscapes['"'] = CharacterEscapes.ESCAPE_CUSTOM;
asciiEscapes['\''] = CharacterEscapes.ESCAPE_CUSTOM;
return asciiEscapes;
}
#Override
public SerializableString getEscapeSequence(int ch) {
switch (ch) {
case '&' : return new SerializedString("&");
case '<' : return new SerializedString("<");
case '>' : return new SerializedString(">");
case '\"' : return new SerializedString(""");
case '\'' : return new SerializedString("'");
default : return super.getEscapeSequence(ch);
}
}
}
}
It covers all the cases.
Have a local String field in XSSRequestWrapper which holds the cleaned-up body (probably not suitable for large bodies).
Populate this field in the constructor by reading request.getInputStream() and cleaning up the body the same way as parameters.
Override getInputStream and getReader methods of HttpServletRequestWrapper, and construct an InputStream (string -> byte array -> ByteArrayInputStream) and Reader (StringReader) from the String field and return them respectively. Maybe cache the constructed InputStream and Reader objects for better performance for when the methods are called repeatedly.
You may also be interested in cleaning up JSON when it is being deserialized into Java object.

How can I moderate #PathVariable?

I have following methods.
public ResponseEntity some(#PathVariable("id") final String id_) {
final Long id = ((Supplier<Long>) () -> {
try {
if (id_ == null || id_.equals("dontcare")) {
return null;
}
return Long.parseLong(id_);
} catch (final NumberFormatException nfe) {
throw new RuntimeException(nfe);
}
}).get();
}
As you can assume I want my parameter value \d+ or dontcare.
How or What can I use for do following?
public ResponseEntity some(
#Dontcare #PathVariable("id") final Long id) {
}
I found WebArgumentHandler, HandlerMethodArgumentResolver, and PathVariableMethodArgumentResolver, but I can't find any good example.
Please help me.
UPDATE
I prepared following class.
public class DontcarePathVariableResolver
extends PathVariableMethodArgumentResolver {
#Override
public boolean supportsParameter(MethodParameter parameter) {
final boolean flag = parameter.getMethodAnnotation(
DontcarePathVariable.class) != null;
logger.info("flag: {}", flag);
return flag;
}
#Override
protected Object resolveName(String name, MethodParameter parameter,
NativeWebRequest request)
throws Exception {
#SuppressWarnings({"unchecked"})
final Map<String, String> templateVariables
= (Map<String, String>) request.getAttribute(
HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE,
RequestAttributes.SCOPE_REQUEST);
final String pathValue = templateVariables.get(name);
return new DontcareConverter().convert(pathValue);
}
}
And added it.
#Configuration
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {
#Override
public void addArgumentResolvers(final List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new DontcarePathVariableMethodArgumentResolver());
logger.info("resolver added");
//super.addArgumentResolvers(resolvers);
}
}
But it did come to play.
I think a default handler for Long type is already in play.

Spring Batch how to regroup/aggregate user datas into a single object

I am trying to transform user operations (like purshases) into a user summary class (expenses by user). A user can have multiple operations but only one summary. I cannot sum purshases in the reader because I need a processor to reject some operation depending to another service.
So some code :
class UserOperation {
String userId;
Integer price;
}
class UserSummary {
String userId;
Long sum;
}
#Bean
public Step retrieveOobClientStep1(StepBuilderFactory stepBuilderFactory, ItemReader<UserOperation> userInformationJdbcCursorItemReader, ItemProcessor<UserOperation, UserSummary> userInformationsProcessor, ItemWriter<UserSummary> flatFileWriter) {
return stepBuilderFactory.get("Step1").<UserOperation, UserSummary>chunk(100) // chunck result that need to be aggregated... not good
.reader(userInformationJdbcCursorItemReader) // read all user operations from DB
.processor(userInformationsProcessor) // I need to reject or not some operations - but here 1 operation = 1 summary that is not good
.writer(flatFileWriter) // write result into flat file
.build();
}
I thing that ItemReader/ItemProcessor/ItemWriter is for single item processing.
But how to regroup multiples records into a single object using Spring Batch ? only Tasklet ?
Possibility but cause problems with small commit interval :
public class UserSummaryAggregatorItemStreamWriter implements ItemStreamWriter<UserSummary>, InitializingBean {
private ItemStreamWriter<UserSummary> delegate;
#Override
public void afterPropertiesSet() throws Exception {
Assert.notNull(delegate, "'delegate' may not be null.");
}
public void setDelegate(ItemStreamWriter<UserSummary> delegate) {
this.delegate = delegate;
}
#Override
public void write(List<? extends UserSummary> items) throws Exception {
Map<String, UserSummary> userSummaryMap = new HashMap<String, UserSummary>();
// Aggregate
for (UserSummary item : items) {
UserSummary savedUserSummary = userSummaryMap.get(item.getUserId());
if (savedUserSummary != null) {
savedUserSummary.incrementSum(item.getSum()); // sum
} else {
savedUserSummary = item;
}
userSummaryMap.put(item.getSubscriptionCode(), savedUserSummary);
}
Collection<UserSummary> values = userSummaryMap.values();
if(values != null) {
delegate.write(new ArrayList<UserSummary>(values));
}
}
#Override
public void open(ExecutionContext executionContext) throws ItemStreamException {
delegate.open(executionContext);
}
#Override
public void update(ExecutionContext executionContext) throws ItemStreamException {
delegate.update(executionContext);
}
#Override
public void close() throws ItemStreamException {
delegate.close();
}
}

window scope in spring?

i was wondering about the spring scope equivalent to window scope ?
according to the documentation here
http://static.springsource.org/spring/docs/3.0.0.M3/spring-framework-reference/html/ch04s04.html
i couldn't find any, so if there's a custom scope equivalent, can anyone please tell me, thanks.
EDIT: example of window scope in JSF
http://icefaces-showcase.icesoft.org/showcase.jsf?grp=compatMenu&exp=popup
One possible approach is having a session scoped bean that holds all the window sessions, and a window custom scope that access to the corresponding bean through that session scoped bean.
The required classes are:
Window Session
public class WindowSession {
private Map<String, Map<String,Object>> scopeMap = new HashMap<String, Map<String,Object>>();
private Map<String, Boolean> validSessions = new HashMap<String, Boolean>();
public WindowSession() {
super();
}
public Map<String, Map<String, Object>> getScopeMap() {
return scopeMap;
}
public void setScopeMap(Map<String, Map<String, Object>> scopeMap) {
this.scopeMap = scopeMap;
}
public Map<String, Boolean> getValidSessions() {
return validSessions;
}
public void setValidSessions(Map<String, Boolean> validSessions) {
this.validSessions = validSessions;
}
}
WindowIdContext
#Service
#Scope(value="request", proxyMode=ScopedProxyMode.TARGET_CLASS)
public class WindowIdContext {
public static final String DEFAULT_SESSION_ID = "";
private String id = DEFAULT_SESSION_ID;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getQueryParamWithSessionId() {
if (DEFAULT_SESSION_ID.equals(id)) {
return "";
}
return "?" + WindowScope.WINDOW_ID_PARAM + "=" + id;
}
}
WindowSessionContext
#Service
#Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
public class WindowSessionContext {
private static SecureRandom random = new SecureRandom();
private WindowSession windowSession = new WindowSession();
#Autowired
private WindowIdContext windowIdContext;
public WindowSessionContext() {
windowSession.getValidSessions().put(WindowIdContext.DEFAULT_SESSION_ID, false);
}
public Object getObject(String name, ObjectFactory<?> objectFactory) {
String sessionId = windowIdContext.getId();
synchronized(this) {
if (!windowSession.getValidSessions().containsKey(sessionId)) {
windowSession.getValidSessions().put(sessionId, false);
}
Map<String,Object> sessionMap = windowSession.getScopeMap().get(sessionId);
if (sessionMap == null) {
sessionMap = new HashMap<String,Object>();
windowSession.getScopeMap().put(sessionId, sessionMap);
}
Object object = sessionMap.get(name);
if (object == null) {
object = objectFactory.getObject();
sessionMap.put(name, object);
}
return object;
}
}
public Object removeObject(String name) {
String sessionId = windowIdContext.getId();
synchronized(this) {
Map<String,Object> sessionMap = windowSession.getScopeMap().get(sessionId);
if (sessionMap == null) {
return null;
}
Object object = sessionMap.remove(name);
return object;
}
}
public String addSession() {
synchronized(this) {
String sessionId;
do {
sessionId = new BigInteger(130, random).toString(32);
} while (windowSession.getValidSessions().containsKey(sessionId));
windowSession.getValidSessions().put(sessionId, false);
return sessionId;
}
}
public void removeSession() {
String sessionId = windowIdContext.getId();
synchronized(this) {
windowSession.getScopeMap().remove(sessionId);
windowSession.getValidSessions().remove(sessionId);
}
}
public boolean isSessionValid(String sessionId) {
Boolean inUse = windowSession.getValidSessions().get(sessionId);
return inUse != null;
}
public boolean isSessionInUse(String sessionId) {
Boolean inUse = windowSession.getValidSessions().get(sessionId);
return inUse == true;
}
public synchronized boolean invalidateSession(String sessionId) {
Boolean valid = windowSession.getValidSessions().get(sessionId);
if (valid == null) {
return false;
}
if (sessionId.equals(WindowIdContext.DEFAULT_SESSION_ID)) {
windowSession.getValidSessions().put(sessionId, false);
} else {
windowSession.getValidSessions().remove(sessionId);
}
windowSession.getScopeMap().remove(sessionId);
for (Entry<String,Boolean> validSession : windowSession.getValidSessions().entrySet()) {
if (validSession.getValue() == true) {
return false;
}
}
return true;
}
public synchronized void setSessionInUse(String sessionId) {
windowSession.getValidSessions().put(sessionId, true);
}
public int getCount() {
return windowSession.getValidSessions().size();
}
}
WindowScope
public class WindowScope implements Scope {
private final int scope;
private static final int WINDOW_SCOPE = 40;
public static final String NAME = "window";
public static final String WINDOW_ID_PARAM = "windowid";
private ServletContext servletContext = null;
public WindowScope(ServletContext sc) {
servletContext = sc;
this.scope = WINDOW_SCOPE;
}
#Override
public Object get(String name, ObjectFactory<?> objectFactory) {
ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
WindowSessionContext windowSessionContext = applicationContext.getBean(WindowSessionContext.class);
return windowSessionContext.getObject(name, objectFactory);
}
#Override
public Object remove(String name) {
ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
WindowSessionContext windowSessionContext = applicationContext.getBean(WindowSessionContext.class);
return windowSessionContext.removeObject(name);
}
#Override
public String getConversationId() {
return RequestContextHolder.currentRequestAttributes().getSessionId();
}
#Override
public void registerDestructionCallback(String arg0, Runnable arg1) {
}
#Override
public Object resolveContextualObject(String key) {
return null;
}
protected int getScope() {
return this.scope;
}
}
WindowScopeFilter
#Component("windowScopeFilter")
public class WindowScopeFilter implements Filter {
#Autowired
private WindowSessionContext windowSessionContext;
#Autowired
private WindowIdContext windowIdContext;
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest)request;
HttpServletResponse httpResponse = (HttpServletResponse)response;
String sessionId = httpRequest.getParameter(WindowScope.WINDOW_ID_PARAM);
if (sessionId != null) {
if (windowSessionContext.isSessionValid(sessionId)) {
windowIdContext.setId(sessionId);
} else {
httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
} else {
windowSessionContext.setSessionInUse(WindowIdContext.DEFAULT_SESSION_ID);
}
chain.doFilter(request, response);
}
public void init(FilterConfig config) throws ServletException {
}
}
WindowScopeListener
#Component
public class WindowScopeListener implements ApplicationListener<ContextRefreshedEvent> {
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
WebApplicationContext applicationContext = (WebApplicationContext)event.getApplicationContext();
Scope windowScope = new WindowScope(applicationContext.getServletContext());
ConfigurableBeanFactory beanFactory = (ConfigurableBeanFactory)applicationContext.getAutowireCapableBeanFactory();
beanFactory.registerScope("window", windowScope);
}
}
Source with complete source code: http://notwithoutmycode.com/post/window/scope/in/spring

Resources