wtorek, 16 października 2012

Zasięg @ViewScoped w CDI/Weld

Szybki przepis jak w CDI/Weld stworzyć nowy zasięg @ViewScoped, ponieważ niestety nie został on domyślnie uwzględniony w specyfikacji. Weld oferuje nam 4 domyślne zasięgi:
  • @RequestScoped,
  • @ConversationScoped,
  • @SessionScoped,
  • @ApplicationScoped.
Po przejrzeniu tej listy od razu nasuwa się pytanie - gdzie jest @ViewScoped? Co prawda pojawił się nowy zasięg @ConversationScoped, który znany jest wszystkim tym, którzy mieli styczność z Seam'em, ale to chyba jeszcze nie powód, aby usuwać @ViweScoped (w Seam'ie - @Scope(ScopeType.PAGE)). Niestety z jakiś względów tak się właśnie stało. Na szczęście specyfikacja CDI pozwala nam tworzyć nowe zasięgi, co skłoniło mnie do tego, aby trochę poszperać i stworzyć zapomniany zasięg @ViewScoped. Swoją drogą autorzy dokumentacji Weld nie pomagają w tego typu czynnościach.

Potrzebny kod
Potrzebujemy dodać następujące klasy do naszego projektu.
package com.blogspot.mkorwel.context;

import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.enterprise.context.NormalScope;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;

@Target(value = { METHOD, TYPE, FIELD })
@Retention(value = RUNTIME)
@NormalScope
@Inherited
public @interface ViewScoped {

}
package com.blogspot.mkorwel.context.spi;

import javax.enterprise.event.Observes;
import javax.enterprise.inject.spi.AfterBeanDiscovery;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.Extension;

public class ViewContextExtension implements Extension {

 public void afterBeanDiscovery(@Observes AfterBeanDiscovery event,
   BeanManager manager) {
  event.addContext(new ViewContext());
 }
}
package com.blogspot.mkorwel.context.spi;

import java.util.Map;

import javax.enterprise.context.spi.Context;
import javax.enterprise.context.spi.Contextual;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.Bean;
import javax.faces.context.FacesContext;

import com.blogspot.mkorwel.context.ViewScoped;

public class ViewContext implements Context {

 public Class<ViewScoped> getScope() {
  return ViewScoped.class;
 }

 public <T> T get(Contextual<T> contextual,
   CreationalContext<T> creationalContext) {
  Bean<T> bean = (Bean<T>) contextual;
  Map<String, Object> viewMap =FacesContext.getCurrentInstance()
    .getViewRoot().getViewMap(true);
  
  if (viewMap.containsKey(bean.getName())) {
   return (T) viewMap.get(bean.getName());
  } else {
   T t = bean.create(creationalContext);
   viewMap.put(bean.getName(), t);
   return t;
  }
 }

 public <T> T get(Contextual<T> contextual) {
  Bean<T> bean = (Bean<T>) contextual;
  Map<String, Object> viewMap = FacesContext.getCurrentInstance()
    .getViewRoot().getViewMap(true);
  
  if (viewMap.containsKey(bean.getName())) {
   return (T) viewMap.get(bean.getName());
  } else {
   return null;
  }
 }

 public boolean isActive() {
  return true;
 }
}
W META-INF tworzymy plik: services/javax.enterprise.inject.spi.Extension, w którym zadeklarujemy użycie naszego zasięgu
com.blogspot.mkorwel.context.spi.ViewContextExtension
Użycie
Nasza "Managed Bean" o zasięgu @ViewScoped może wyglądać mniej więcej tak:
@ViewScoped
public class SomeControler implements Serializable {

 //some field and method
}

Brak komentarzy:

Prześlij komentarz