EL Expression in JSF 2.2 - jsf-2.2

I am using JSF 2.2 and I need to get an instance of the managed bean using EL Expression. I am using the below code which creates an instance of the managed bean if its not already created. If the bean is already created and is in memory (any scoped variable be it in session, request, ..), it returns that instance of the managed bean with out creating a new one.
My requirement is, if the bean is not already created, then it should return null and not create a new instance. If it's is already created , then it should return that instance. But the below code, ends up creating one if it doesn't exists.
Hope I am clear.
public static MyManagedBean getMyManagedBean () {
MyManagedBean bean = (MyManagedBean ) getFacesContext().getApplication().getExpressionFactory().createValueExpression(getELContext(),
"#{MyManagedBean}",
MyManagedBean .class).getValue(FacesContext.getCurrentInstance().getELContext());
return bean;
}

This is the simple (but verbose) version:
public static <T> T resolveBean(String name)
{
FacesContext context = FacesContext.getCurrentInstance();
ExternalContext externalContext = context.getExternalContext();
Map<String, Object> requestMap = externalContext.getRequestMap();
Object requestObject = requestMap.get(name);
if(requestObject != null)
{
return (T) requestObject;
}
Map<String, Object> viewMap = context.getViewRoot().getViewMap();
Object viewObject = viewMap.get(name);
if(viewObject != null)
{
return (T) viewObject;
}
Map<String, Object> sessionMap = externalContext.getSessionMap();
Object sessionObject = sessionMap.get(name);
if(sessionObject != null)
{
return (T) sessionObject;
}
Map<String, Object> applicationMap = externalContext.getApplicationMap();
Object applicationObject = applicationMap.get(name);
if(applicationObject != null)
{
return (T) applicationObject;
}
BeanManager beanManager = CDI.current().getBeanManager();
Bean<T> bean = (Bean<T>) beanManager.resolve(beanManager.getBeans(name));
if(bean != null)
{
Context cdiContext = beanManager.getContext(bean.getScope());
T instance = cdiContext.get(bean);
if(instance != null)
{
return instance;
}
}
return null;
}

Related

Spring Boot custom annotation design not working

I am following a tutorial by PacktPublishing where some annotations are used in an example,
but the code is from 2018 and there have probably been some changes.
Spring does not recognize the Annotation when creating a bean.
Specifically, here is an annotation design that just does not work for me locally:
link
Some important code snippets are:
#Target({ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Component
public #interface ChannelHandler {
/**
* Channel patter, alias of value()
*/
String pattern() default "";
/**
* The channel pattern that the handler will be mapped to by {#link WebSocketRequestDispatcher}
* using Spring's {#link org.springframework.util.AntPathMatcher}
*/
String value() default "";
}
#ChannelHandler("/board/*")
public class BoardChannelHandler {
private static final Logger log = LoggerFactory.getLogger(BoardChannelHandler.class);
#Action("subscribe")
public void subscribe(RealTimeSession session, #ChannelValue String channel) {
log.debug("RealTimeSession[{}] Subscribe to channel `{}`", session.id(), channel);
SubscriptionHub.subscribe(session, channel);
}
#Action("unsubscribe")
public void unsubscribe(RealTimeSession session, #ChannelValue String channel) {
log.debug("RealTimeSession[{}] Unsubscribe from channel `{}`", session.id(), channel);
SubscriptionHub.unsubscribe(session, channel);
}
}
#Target({ElementType.METHOD})
#Retention(RetentionPolicy.RUNTIME)
#Documented
public #interface Action {
/**
* The action pattern. It needs to be an exact match.
* <p>For example, "subscribe"
*/
String value() default "";
}
Can you see what the issue is here? Is there some other annotation missing for newer versions
of Spring?
UPDATE - adding other necessary code.
public class ChannelHandlerInvoker {
private static final Logger log = LoggerFactory.getLogger(ChannelHandlerInvoker.class);
private static final AntPathMatcher antPathMatcher = new AntPathMatcher();
private String channelPattern;
private Object handler;
// Key is the action, value is the method to handle that action
private final Map<String, Method> actionMethods = new HashMap<>();
public ChannelHandlerInvoker(Object handler) {
Assert.notNull(handler, "Parameter `handler` must not be null");
Class<?> handlerClass = handler.getClass();
ChannelHandler handlerAnnotation = handlerClass.getAnnotation(ChannelHandler.class);
Assert.notNull(handlerAnnotation, "Parameter `handler` must have annotation #ChannelHandler");
Method[] methods = handlerClass.getMethods();
for (Method method : methods) {
Action actionAnnotation = method.getAnnotation(Action.class);
if (actionAnnotation == null) {
continue;
}
String action = actionAnnotation.value();
actionMethods.put(action, method);
log.debug("Mapped action `{}` in channel handler `{}#{}`", action, handlerClass.getName(), method);
}
this.channelPattern = ChannelHandlers.getPattern(handlerAnnotation);
this.handler = handler;
}
public boolean supports(String action) {
return actionMethods.containsKey(action);
}
public void handle(IncomingMessage incomingMessage, RealTimeSession session) {
Assert.isTrue(antPathMatcher.match(channelPattern, incomingMessage.getChannel()), "Channel of the handler must match");
Method actionMethod = actionMethods.get(incomingMessage.getAction());
Assert.notNull(actionMethod, "Action method for `" + incomingMessage.getAction() + "` must exist");
// Find all required parameters
Class<?>[] parameterTypes = actionMethod.getParameterTypes();
// All the annotations for each parameter
Annotation[][] allParameterAnnotations = actionMethod.getParameterAnnotations();
// The arguments that will be passed to the action method
Object[] args = new Object[parameterTypes.length];
try {
// Populate arguments
for (int i = 0; i < parameterTypes.length; i++) {
Class<?> parameterType = parameterTypes[i];
Annotation[] parameterAnnotations = allParameterAnnotations[i];
// No annotation applied on this parameter
if (parameterAnnotations.length == 0) {
if (parameterType.isInstance(session)) {
args[i] = session;
} else {
args[i] = null;
}
continue;
}
// Only use the first annotation applied on the parameter
Annotation parameterAnnotation = parameterAnnotations[0];
if (parameterAnnotation instanceof Payload) {
Object arg = JsonUtils.toObject(incomingMessage.getPayload(), parameterType);
if (arg == null) {
throw new IllegalArgumentException("Unable to instantiate parameter of type `" +
parameterType.getName() + "`.");
}
args[i] = arg;
} else if (parameterAnnotation instanceof ChannelValue) {
args[i] = incomingMessage.getChannel();
}
}
actionMethod.invoke(handler, args);
} catch (Exception e) {
String error = "Failed to invoker action method `" + incomingMessage.getAction() +
"` at channel `" + incomingMessage.getChannel() + "` ";
log.error(error, e);
session.error(error);
}
}
}
#Component
public class ChannelHandlerResolver {
private static final Logger log = LoggerFactory.getLogger(ChannelHandlerResolver.class);
private static final AntPathMatcher antPathMatcher = new AntPathMatcher();
// The key is the channel ant-like path pattern, value is the corresponding invoker
private final Map<String, ChannelHandlerInvoker> invokers = new HashMap<>();
private ApplicationContext applicationContext;
public ChannelHandlerResolver(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
this.bootstrap();
}
public ChannelHandlerInvoker findInvoker(IncomingMessage incomingMessage) {
ChannelHandlerInvoker invoker = null;
Set<String> pathPatterns = invokers.keySet();
for (String pathPattern : pathPatterns) {
if (antPathMatcher.match(pathPattern, incomingMessage.getChannel())) {
invoker = invokers.get(pathPattern);
}
}
if (invoker == null) {
return null;
}
return invoker.supports(incomingMessage.getAction()) ? invoker : null;
}
private void bootstrap() {
log.info("Bootstrapping channel handler resolver");
Map<String, Object> handlers = applicationContext.getBeansWithAnnotation(ChannelHandler.class);
for (String handlerName : handlers.keySet()) {
Object handler = handlers.get(handlerName);
Class<?> handlerClass = handler.getClass();
ChannelHandler handlerAnnotation = handlerClass.getAnnotation(ChannelHandler.class);
String channelPattern = ChannelHandlers.getPattern(handlerAnnotation);
if (invokers.containsKey(channelPattern)) {
throw new IllegalStateException("Duplicated handlers found for chanel pattern `" + channelPattern + "`.");
}
invokers.put(channelPattern, new ChannelHandlerInvoker(handler));
log.debug("Mapped channel `{}` to channel handler `{}`", channelPattern, handlerClass.getName());
}
}
}
<!-- begin snippet: js hide: false console: true babel: false -->
UPDATE 2
I have managed to make ChannelHandler and Action annotations work by adding #Inherited annotation and using AnnotationUtils.findAnnotation() which traverses its super methods if the annotation is not directly present on the given method itself.
However, I haven't managed to access custom annotation value of type parameter (ChannelValue)
Here, Annotation[][] allParameterAnnotations = actionMethod.getParameterAnnotations();
returns null value.
UPDATE 3 -> SOLVED
Just add #Aspect annotation to your ChannelHandler implementation (e.g.
"BoardChannelHandler").
Looks like bootstrap() method, that goes through all the #ChannelHandler annotated beans is executed too early - try to debug it to check if it detects any beans at this stage.
If not try calling bootstrap() after Spring context is ready (for example listen for ContextRefreshedEvent.

Replace OAuth2AccessTokenJackson2Deserializer with my own custom deserializer

This class is deserializing an oauth2 token and I would like to tweak it. I created my own class extending StdDeserializer<OAuth2AccessToken> which at the moment is the same as the original class.
Here is the class:
public class MyCustomDeserializer extends StdDeserializer<OAuth2AccessToken> {
public MyCustomDeserializer() {
super(OAuth2AccessToken.class);
}
#Override
public OAuth2AccessToken deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException,
JsonProcessingException {
String tokenValue = null;
String tokenType = null;
String refreshToken = null;
Long expiresIn = null;
Set<String> scope = null;
Map<String, Object> additionalInformation = new LinkedHashMap<String, Object>();
// TODO What should occur if a parameter exists twice
while (jp.nextToken() != JsonToken.END_OBJECT) {
String name = jp.getCurrentName();
jp.nextToken();
if (OAuth2AccessToken.ACCESS_TOKEN.equals(name)) {
tokenValue = jp.getText();
}
else if (OAuth2AccessToken.TOKEN_TYPE.equals(name)) {
tokenType = jp.getText();
}
else if (OAuth2AccessToken.REFRESH_TOKEN.equals(name)) {
refreshToken = jp.getText();
}
else if (OAuth2AccessToken.EXPIRES_IN.equals(name)) {
try {
expiresIn = jp.getLongValue();
} catch (JsonParseException e) {
expiresIn = Long.valueOf(jp.getText());
}
}
else if (OAuth2AccessToken.SCOPE.equals(name)) {
scope = parseScope(jp);
} else {
additionalInformation.put(name, jp.readValueAs(Object.class));
}
}
// TODO What should occur if a required parameter (tokenValue or tokenType) is missing?
DefaultOAuth2AccessToken accessToken = new DefaultOAuth2AccessToken(tokenValue);
accessToken.setTokenType(tokenType);
if (expiresIn != null) {
accessToken.setExpiration(new Date(System.currentTimeMillis() + (expiresIn * 1000)));
}
if (refreshToken != null) {
accessToken.setRefreshToken(new DefaultOAuth2RefreshToken(refreshToken));
}
accessToken.setScope(scope);
accessToken.setAdditionalInformation(additionalInformation);
return accessToken;
}
private Set<String> parseScope(JsonParser jp) throws JsonParseException, IOException {
Set<String> scope;
if (jp.getCurrentToken() == JsonToken.START_ARRAY) {
scope = new TreeSet<String>();
while (jp.nextToken() != JsonToken.END_ARRAY) {
scope.add(jp.getValueAsString());
}
} else {
String text = jp.getText();
scope = OAuth2Utils.parseParameterList(text);
}
return scope;
}
}
Here I am registering the bean:
#Bean
public ObjectMapper configObjectMapper() {
final ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
final SimpleModule module = new SimpleModule("configModule", com.fasterxml.jackson.core.Version.unknownVersion());
module.addDeserializer(OAuth2AccessToken.class, new MyCustomDeserializer());
objectMapper.registerModule(module);
return objectMapper;
}
Testing the above code the flow doesn't reach my class but the original. I am using spring boot 2.1.4

JSF HtmlCommandButton programmatically - Bean method not called if ajax turned off

I'm trying to create an HtmlCommandButton programmatically, following the example here
http://javaevangelist.blogspot.ch/2013/01/jsf-21-tip-of-day-programmatically.html
Everything works fine (i.e., the actionListener is called) if I add the ajax behavior, it doesn't work if ajax is turned off.
Backing bean:
#Named
#RequestScoped
public class CommandBean implements Serializable {
public String generateUUID() {
return java.util.UUID.randomUUID().toString();
}
}
Solution 1 (with ajax)
private HtmlCommandButton createCommandButtonWithAjax(final FacesContext context,
final String methodExpression, final String value) {
Application application = context.getApplication();
Class<?>[] clazz = new Class<?>[]{};
HtmlCommandButton htmlCommandButton =
(HtmlCommandButton) application.createComponent(HtmlCommandButton.COMPONENT_TYPE);
htmlCommandButton.setValue(value);
AjaxBehavior ajaxBehavior = (AjaxBehavior) FacesContext.getCurrentInstance().getApplication().createBehavior(AjaxBehavior.BEHAVIOR_ID);
((UIComponentBase)htmlCommandButton).addClientBehavior("click", ajaxBehavior);
MethodExpression actionListener = application.getExpressionFactory().createMethodExpression(FacesContext.getCurrentInstance().getELContext(), action, String.class, clazz);
button.addActionListener(new MethodExpressionActionListener(actionListener));
return htmlCommandButton;
}
Solution 2 (no ajax)
private HtmlCommandButton createCommandButton(final FacesContext context,
final String methodExpression, final String value) {
Application application = context.getApplication();
Class<?>[] clazz = new Class<?>[]{};
HtmlCommandButton htmlCommandButton =
(HtmlCommandButton) application.createComponent(HtmlCommandButton.COMPONENT_TYPE);
htmlCommandButton.setValue(value);
htmlCommandButton.setActionExpression(JSFUtils.createMethodExpression(methodExpression, String.class, clazz));
return htmlCommandButton;
}
Calling code:
createCommandButton(FacesContext.getCurrentInstance(),
"#{commandBean.generateUUID()}", "Generate UUID");
JSFUtils:
public static MethodExpression createMethodExpression(String methodExpression,Class<?> expectedReturnType,Class<?>[] expectedParamTypes) {
FacesContext context = FacesContext.getCurrentInstance();
return context.getApplication().getExpressionFactory()
.createMethodExpression(context.getELContext(), methodExpression, expectedReturnType, expectedParamTypes);
}
Solution 1 is working, solution 2 not: the bean method generateUUID() is not called. I have tried also with htmlCommandButton.setImmediate(true) to exclude validation errors.
Apparently we need a Custom AjaxBehavior, as suggested here:
https://forum.primefaces.org/viewtopic.php?f=3&t=5344 and here
How to programmatically add an AjaxBehavior to a UIComponent with primefaces
Custom Ajax:
import java.util.HashMap;
import javax.el.ELContext;
import javax.el.MethodExpression;
import javax.faces.component.UIComponentBase;
import javax.faces.context.FacesContext;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.BehaviorEvent;
public class MyAjaxBehavior extends AjaxBehavior{
#Override
public Object saveState(FacesContext context) {
HashMap<String, Object> map;
map = new HashMap<String, Object>();
map.put( "update", getUpdate() );
map.put( "process", getProcess() );
map.put( "oncomplete", getOncomplete() );
map.put( "onerror", getOnerror() );
map.put( "onsuccess", getOnsuccess() );
map.put( "onstart", getOnstart() );
map.put( "listener", getListener() );
if (initialStateMarked()) return null;
return UIComponentBase.saveAttachedState(context, map);
}
#SuppressWarnings("unchecked")
#Override
public void restoreState(FacesContext context, Object state) {
if (state != null){
HashMap<String, Object> map;
map = (HashMap<String, Object>) UIComponentBase.restoreAttachedState(context, state);
setUpdate( (String) map.get( "update" ));
setProcess( (String) map.get( "process"));
setOncomplete( (String) map.get( "oncomplete" ));
setOnerror( (String) map.get( "onerror" ));
setOnsuccess( (String) map.get( "onsuccess" ));
setOnstart( (String) map.get( "onstart" ));
setListener( (MethodExpression) map.get( "listener" ));
}
}
#Override
public void broadcast(BehaviorEvent event) throws AbortProcessingException {
ELContext eLContext = FacesContext.getCurrentInstance().getELContext();
//Backward compatible implementation of listener invocation
if(getListener() != null) {
try {
getListener().invoke(eLContext, new Object[]{event});
} catch(IllegalArgumentException exception) {
getListener().invoke(eLContext, new Object[0]);
}
}
}
}
Create Button
private HtmlCommandButton createCommandButtonWithAjax(final FacesContext context,
final String methodExpression, final String value) {
Application application = context.getApplication();
Class<?>[] clazz = new Class<?>[]{};
HtmlCommandButton htmlCommandButton =
(HtmlCommandButton) application.createComponent(HtmlCommandButton.COMPONENT_TYPE);
htmlCommandButton.setValue(value);
addPrimefacesAjaxSupport(htmlCommandButton,"click", methodExpression);
return htmlCommandButton;
}
add AjaxBehavior
private AjaxBehavior addPrimefacesAjaxSupport(UIComponentBase comp, String event, String actionListener){
MyAjaxBehavior ajaxBehavior = new MyAjaxBehavior();
ajaxBehavior.setListener( JSFUtils.createMethodExpression(actionListener, void.class,new Class[]{ ActionEvent.class}) );
ajaxBehavior.setProcess( "#this" );
comp.addClientBehavior( event, ajaxBehavior );
return ajaxBehavior;
}

broadleaf mail sender class using spring framework

what does this mean in java...i saw something new i havn't seen anything like this before...this code sends a mail using spring framework javamailsender class
public MimeMessagePreparator buildMimeMessagePreparator(final HashMap<String,Object> props) {
MimeMessagePreparator preparator = new MimeMessagePreparator() {
public void prepare(MimeMessage mimeMessage) throws Exception {
EmailTarget emailUser = (EmailTarget) props.get(EmailPropertyType.USER.getType());
EmailInfo info = (EmailInfo) props.get(EmailPropertyType.INFO.getType());
MimeMessageHelper message = new MimeMessageHelper(mimeMessage, (info.getAttachments() != null && info.getAttachments().size() > 0));
message.setTo(emailUser.getEmailAddress());
message.setFrom(info.getFromAddress());
message.setSubject(info.getSubject());
if (emailUser.getBCCAddresses() != null && emailUser.getBCCAddresses().length > 0) {
message.setBcc(emailUser.getBCCAddresses());
}
if (emailUser.getCCAddresses() != null && emailUser.getCCAddresses().length > 0) {
message.setCc(emailUser.getCCAddresses());
}
String messageBody = info.getMessageBody();
if (messageBody == null) {
messageBody = buildMessageBody(info, props);
}
message.setText(messageBody, true);
for (Attachment attachment : info.getAttachments()) {
ByteArrayDataSource dataSource = new ByteArrayDataSource(attachment.getData(), attachment.getMimeType());
message.addAttachment(attachment.getFilename(), dataSource);
}
}
}; // why there is a semicolon here
return preparator;
}
If you're confused about the semicolon, the code is creating an anonymous inner class that's a subclass of MimeMessagePreparator. The semicolon is the end of the assignment to the preparator variable.

spring how to pass values from one page to controller?

I am developing a spring mvc application . I just want to do the following ,
When user clicks on a link , I just want to pass some values from that page to the target Controller of that link.
Is AbstractCommandController will be useful for this ?
Is there any way other than using session attributes ?
You can do it in one of the following ways:
1) Submit Form.
2) Send it as parameters in your URL.
3) Create cusom flash scope for your application:
You can read more about it here:http://goo.gl/nQaQh
In spring MVC there is no Flash Bean scope so you can do it as Interceptor:
Here is the simple code how to use
public class FlashScopeInterceptor implements HandlerInterceptor {
public static final String DEFAULT_ATTRIBUTE_NAME = "flashScope";
public static final String DEFAULT_SESSION_ATTRIBUTE_NAME = FlashScopeInterceptor.class.getName();
public static final int DEFAULT_RETENTION_COUNT = 2;
private String sessionAttributeName = DEFAULT_SESSION_ATTRIBUTE_NAME;
private String attributeName = DEFAULT_ATTRIBUTE_NAME;
private int retentionCount = DEFAULT_RETENTION_COUNT;
/**
* Unbinds current flashScope from session. Rolls request's flashScope to
* the next scope. Binds request's flashScope, if not empty, to the session.
*
*/
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
if (request.getSession( false ) != null)
{
request.getSession().removeAttribute( this.sessionAttributeName );
}
Object requestAttribute = request.getAttribute( this.attributeName );
if (requestAttribute instanceof MultiScopeModelMap)
{
MultiScopeModelMap attributes = (MultiScopeModelMap) requestAttribute;
if (!attributes.isEmpty())
{
attributes.next();
if (!attributes.isEmpty())
{
request.getSession( true ).setAttribute( this.sessionAttributeName, attributes );
}
}
}
}
/**
* merge modelAndView.model['flashScope'] to current flashScope
*/
#Override
public void postHandle( HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
if (modelAndView != null)
{
Map<String, Object> modelFlashScopeMap = null;
for (Iterator<Entry<String, Object>> iterator = ((Map<String, Object>) modelAndView.getModel()).entrySet()
.iterator(); iterator.hasNext();)
{
Entry<String, Object> entry = iterator.next();
if (this.attributeName.equals( entry.getKey() ) && entry.getValue() instanceof Map)
{
if (modelFlashScopeMap == null)
{
modelFlashScopeMap = (Map) entry.getValue();
}
else
{
modelFlashScopeMap.putAll( (Map) entry.getValue() );
}
iterator.remove();
}
else if (entry.getKey().startsWith( this.attributeName + "." ))
{
String key = entry.getKey().substring( this.attributeName.length() + 1 );
if (modelFlashScopeMap == null)
{
modelFlashScopeMap = new HashMap<String, Object>();
}
modelFlashScopeMap.put( key, entry.getValue() );
iterator.remove();
}
}
if (modelFlashScopeMap != null)
{
MultiScopeModelMap flashScopeMap;
if (request.getAttribute( this.attributeName ) instanceof MultiScopeModelMap)
{
flashScopeMap = (MultiScopeModelMap) request.getAttribute( this.attributeName );
}
else
{
flashScopeMap = new MultiScopeModelMap( this.retentionCount );
}
flashScopeMap.putAll( modelFlashScopeMap );
request.setAttribute( this.attributeName, flashScopeMap );
}
}
}
/**
* binds session flashScope to current session, if not empty. Otherwise cleans up empty
* flashScope
*/
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession( false );
if (session != null)
{
Object sessionAttribute = session.getAttribute( this.sessionAttributeName );
if (sessionAttribute instanceof MultiScopeModelMap)
{
MultiScopeModelMap flashScope = (MultiScopeModelMap) sessionAttribute;
if (flashScope.isEmpty())
{
session.removeAttribute( this.sessionAttributeName );
}
else
{
request.setAttribute( this.attributeName, flashScope );
}
}
}
return true;
}
}
and then MultiScopeModelMap
public class MultiScopeModelMap extends CompositeMap implements Serializable, MapMutator
{
public MultiScopeModelMap(int num)
{
super();
setMutator( this );
for(int i = 0; i < num; ++i)
{
addComposited( new HashMap() );
}
}
/** Shadows composite map. */
private final LinkedList<Map> maps = new LinkedList<Map>();
#Override
public synchronized void addComposited( Map map ) throws IllegalArgumentException
{
super.addComposited( map );
this.maps.addLast( map );
}
#Override
public synchronized Map removeComposited( Map map )
{
Map removed = super.removeComposited( map );
this.maps.remove( map );
return removed;
}
/**
* Starts a new scope.
* All items added in the session before the previous session are removed.
* All items added in the previous scope are still retrievable and removable.
*/
public void next()
{
removeComposited( this.maps.getFirst() );
addComposited( new HashMap() );
}
public Object put( CompositeMap map, Map[] composited, Object key, Object value )
{
if(composited.length < 1)
{
throw new UnsupportedOperationException("No composites to add elements to");
}
Object result = map.get( key );
if(result != null)
{
map.remove( key );
}
composited[composited.length-1].put( key, value );
return result;
}
public void putAll( CompositeMap map, Map[] composited, Map mapToAdd )
{
for(Entry entry: (Set<Entry>)mapToAdd.entrySet())
{
put(map, composited, entry.getKey(), entry.getValue());
}
}
public void resolveCollision( CompositeMap composite, Map existing, Map added, Collection intersect )
{
existing.keySet().removeAll( intersect );
}
#Override
public String toString()
{
return new HashMap(this).toString();
}
}
Now configure it in xml:
<bean id="flashScopeInterceptor" class="com.vanilla.scopes.FlashScopeInterceptor" />
<bean id="handlerMapping" class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<list><ref bean="flashScopeInterceptor"/></list>
</property>
</bean>
Usage:
#RequestMapping(value="/login.do", method=RequestMethod.POST)
public ModelAndView login(#Valid User user){
ModelAndView mv = new ModelAndView("redirect:result.html");
if (authService.authenticate(user.getUserName(), user.getPassword()))
mv.addObject("flashScope.message", "Success");
//else
mv.addObject("flashScope.message", "Login Failed");
return mv;
}
#RequestMapping(value ="/result.html", method=RequestMethod.GET)
public ModelAndView result(){
ModelAndView mv = new ModelAndView("login/loginAction");
return mv;
}
In JSP the usage is very simple:
${flashScope.message}

Resources