I use Hibernate, Spring and JSF (Primefaces) in my project. I want to create a picklist with simple POJO (Entity). Here is what I created:
<p:pickList id="pickList" converter="#{groupConverter}" value="#{adminUsersMB.groups}" var="group"
itemLabel="#{group.name}" itemValue="#{group}" >
<f:facet name="sourceCaption">Available groups</f:facet>
<f:facet name="targetCaption">Users groups</f:facet>
</p:pickList>
My Converter is:
#RequestScoped
#FacesConverter(forClass=Group.class, value="groupConverter")
public class GroupConverter implements Converter {
#ManagedProperty(name="groupService", value="#{groupService}")
#Getter #Setter
GroupService groupService;
#Override
public Object getAsObject(FacesContext arg0, UIComponent arg1, String arg2) {
try {
return groupService.getGroupByName(Integer.parseInt(arg2));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
#Override
public String getAsString(FacesContext arg0, UIComponent arg1, Object arg2) {
return ((Group) arg2).getId().toString();
}
}
of course I added my custom converter to the faces config:
<converter>
<converter-id>groupConverter</converter-id>
<converter-class>pl.proedims.users.component.GroupConverter</converter-class>
</converter>
But when I commit the form, I got exception:
> SEVERE: javax.el.PropertyNotFoundException: /admin/user.xhtml #73,66
> itemLabel="#{group.name}": Property 'name' not found on type java.lang.String
Problem solved. All i needed was to type:
#Component("groupConverter")
public class GroupConverter implements Converter {
#Autowired
GroupService groupService;
(...)
Related
i wanted to ask if there is a way to enable Springs #ExceptionHandler capabilities with Joinfaces/Primefaces.
For now i'm able to handle global #ControllerAdvice beans, but not if the #ExceptionHandler is inside the #Controller class.
Are there any suggestions on how to solve this topic?
Here is the code i wrote so far
#Slf4j
public class SpringJsfExceptionHandler extends ExceptionHandlerWrapper {
public SpringJsfExceptionHandler(ExceptionHandler wrapped) {
super(wrapped);
}
#Override
public void handle() throws FacesException {
final Iterator<ExceptionQueuedEvent> queue = getUnhandledExceptionQueuedEvents().iterator();
while (queue.hasNext()) {
ExceptionQueuedEvent item = queue.next();
ExceptionQueuedEventContext exceptionQueuedEventContext = (ExceptionQueuedEventContext) item.getSource();
try {
Throwable throwable = exceptionQueuedEventContext.getException();
FacesContext context = FacesContext.getCurrentInstance();
handleException(context, (Exception) throwable);
} finally {
queue.remove();
}
}
}
private void handleException(FacesContext context, Exception throwable) {
WebApplicationContext applicationContext = resolveApplicationContext(context);
Collection<HandlerExceptionResolver> exceptionResolvers = listExceptionHandlerResolvers(applicationContext);
for (HandlerExceptionResolver resolver : exceptionResolvers) {
resolver.resolveException(request(context), response(context), null, throwable);
}
}
private Collection<HandlerExceptionResolver> listExceptionHandlerResolvers(WebApplicationContext context) {
return context.getBeansOfType(HandlerExceptionResolver.class).values();
}
private HttpServletRequest request(FacesContext context) {
return (HttpServletRequest) context.getExternalContext().getRequest();
}
private HttpServletResponse response(FacesContext context) {
return (HttpServletResponse) context.getExternalContext().getResponse();
}
private WebApplicationContext resolveApplicationContext(FacesContext context) {
HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
return WebApplicationContextUtils.findWebApplicationContext(request.getServletContext());
}
}
public class SpringJsfExceptionHandlerFactory extends ExceptionHandlerFactory {
public SpringJsfExceptionHandlerFactory() {
}
public SpringJsfExceptionHandlerFactory(ExceptionHandlerFactory wrapped) {
super(wrapped);
}
#Override
public ExceptionHandler getExceptionHandler() {
return new SpringJsfExceptionHandler(getWrapped() != null ? getWrapped().getExceptionHandler() : null);
}
}
This works:
#ControllerAdvice
public class GlobalExceptionHandler {
#ExceptionHandler
public void handleCalculationException(CalculationException e) {
FacesContext.getCurrentInstance().
addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, e.getMessage(), e.getMessage()));
}
}
This does not work:
#Data
#Controller
#ViewScoped
public class CalculatorController implements Serializable {
#ExceptionHandler
public void handleCalculationException(CalculationException e) {
FacesContext.getCurrentInstance().
addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, e.getMessage(), e.getMessage()));
}
[...]
Thanks in advance
TLDR: No
#ExceptionHandler is part of Spring MVC.
Spring MVC and JSF are separate web frameworks.
Joinfaces allows you to use JSF in a Spring Application, and you can also use Spring MVC in the same application. Every request will however either be handled by Spring MVC (i.e. the DispatcherServlet) or JSF (i.e. the FacesServlet).
I am trying to call validator from controller using #Valid annotation, but control is not going to validator and proceeding without validating.
Controller
#Controller
#RequestMapping(value="/event")
public class EventController {
#Autowired
private EventService eventService;
#Autowired
EventValidator eventValidator;
#InitBinder
private void initBinder(WebDataBinder binder) {
binder.setValidator(eventValidator);
}
#RequestMapping(value="/add_event",method = RequestMethod.POST,produces=MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public ResponseEntity<AjaxJSONResponse> postAddEventForm(#Valid #RequestPart("event") Event event, MultipartHttpServletRequest request) {
Boolean inserted = eventService.addEvent(event);
String contextPath = request.getContextPath();
String redirectURL = StringUtils.isEmpty(contextPath)?"/event":contextPath+"/event";
return new ResponseEntity<AjaxJSONResponse>(new AjaxJSONResponse(inserted,"Event Added Successfully",redirectURL), HttpStatus.OK);
}
}
Validator
#Component
public class EventValidator implements Validator {
#Override
public boolean supports(Class<?> clazz) {
return Event.class.isAssignableFrom(clazz);
}
#Override
public void validate(Object target, Errors errors) {
Event event = (Event)target;
if (event.getEventName() == null ||!StringUtils.hasText(event.getEventName())) {
errors.rejectValue("eventName", "", "Event Name is empty");
}
}
}
Please help on this.
Thank in advance
This question already has answers here:
How to inject #EJB, #PersistenceContext, #Inject, #Autowired, etc in #FacesConverter?
(5 answers)
Closed 7 years ago.
I am working on a web application using PrimeFaces, JPA, Hibernate and JSF 2.0.
I have a converter for my JSF p:selectOneMenu. My problem is, when I run my application the Service descriptifService is not autowired, it return NULL !
The converter :
#Component
#FacesConverter(value = "descriptifConverter")
public class DescriptifConverter implements Converter {
#Autowired
#RmiClient
private IDescriptifService descriptifService;
#Override
public Object getAsObject(FacesContext arg0, UIComponent arg1, String arg2) {
if (arg2 == null || arg2.isEmpty()) {
return null;
}
String descriptif = arg2;
Long value = Long.valueOf(descriptif);
DescriptifDto result = new DescriptifDto();
result = descriptifService.findById(value);
return result;
}
#Override
public String getAsString(FacesContext arg0, UIComponent arg1, Object arg2) {
if(arg2 == null || ((DescriptifDto) arg2).getIdDescriptif() == null) return null;
DescriptifDto descriptif = new DescriptifDto();
if(arg2 instanceof DescriptifDto) {
descriptif = (DescriptifDto) arg2;
String idDescriptif = descriptif.getIdDescriptif().toString();
return (idDescriptif != null) ? String.valueOf(idDescriptif) : null;
} else throw new ConverterException("Something wrong!" + arg2.hashCode() + arg2.toString());
}
}
The JSF code :
<p:selectOneMenu value="#{lotController.selectedDescriptif}"
effect="fade">
<f:selectItems value="#{lotController.listDescriptifs}" var="descriptif"
itemLabel="#{descriptif.libelle}" itemValue="#{descriptif}" />
<f:converter binding="#{descriptifConverter}" />
</p:selectOneMenu>
Here you have two options:
1 - Register a context provider bean:
AppContext Class:
import org.springframework.context.ApplicationContext;
public class AppContext {
private static ApplicationContext ctx;
public static void setApplicationContext(
ApplicationContext applicationContext) {
ctx = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return ctx;
}
}
ApplicationContextProvider class:
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class ApplicationContextProvider implements ApplicationContextAware {
#Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
AppContext.setApplicationContext(applicationContext);
}
}
Register the bean:
<bean id="contextApplicationContextProvider" class="com.example.ApplicationContextProvider" />
Now, through the context, you can get a reference to your service bean anyware:
IDescriptifService descriptifService = AppContext.getApplicationContext().getBean(
IDescriptifService.class);
2 - Store the converted values inside the ViewMap (inspired in this post)
I like this solution because it doesn't required database access which improves the performance of the application.
AbstractConverter class
import java.util.HashMap;
import java.util.Map;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
public abstract class AbstractConverter implements Converter {
private static final String KEY = "com.example.converters.AbstractConverter";
protected Map<String, Object> getViewMap(FacesContext context) {
Map<String, Object> viewMap = context.getViewRoot().getViewMap();
#SuppressWarnings({ "unchecked", "rawtypes" })
Map<String, Object> idMap = (Map) viewMap.get(KEY);
if (idMap == null) {
idMap = new HashMap<String, Object>();
viewMap.put(KEY, idMap);
}
return idMap;
}
#Override
public final Object getAsObject(FacesContext context, UIComponent c,
String value) {
if (value == null || value.isEmpty()) {
return null;
}
return getViewMap(context).get(value);
}
#Override
public final String getAsString(FacesContext context, UIComponent c,
Object value) {
if (value != null) {
String id = getConversionId(value);
if (id == null || id.isEmpty()) {
throw new IllegalArgumentException(
"Objeto não pode ser convertido.");
}
getViewMap(context).put(id, value);
return id;
}
return null;
}
//Every concrete class must provide an unique conversionId String
//to every instance of the converted object
public abstract String getConversionId(Object value);
}
Here we create a storage place inside the ViewMap. We can now use it to store any converter object we need.
Here is an example of a concrete converter:
EntityConverter class
import javax.faces.convert.FacesConverter;
import com.example.AbstractEntity;
#FacesConverter("entity")
public class EntityConverter extends AbstractConverter {
#Override
public String getConversionId(Object value) {
if (value instanceof AbstractEntity) {
AbstractEntity entity = (AbstractEntity) value;
StringBuilder sb = new StringBuilder();
sb.append(entity.getClass().getSimpleName());
sb.append("#");
sb.append(entity.getId());
return sb.toString();
}
return null;
}
}
A late response, but I had the same problem of not being able to Autowire Spring beans into a JSF Converter, so I removed the #FacesConverter annotation and declared the converter component as session scoped, then, as you did, using the f:converter tag with binding attribute solved the problem. In your case:
#Component
#Scope(WebApplicationContext.SCOPE_SESSION)
public class DescriptifConverter implements Converter {
...
}
should work...
I'm trying to init property before the JSF #PostConstruvtor is called with respect to MVC.
This is my Java code:
#ManagedBean
public abstract class FooController {
protected <type> prop;
public void setProp(<type> prop) {
this.prop = prop;
}
public <type> getProp() {
return this.prop;
}
}
#ManagedBean
public class Foo1Controller extends FooController {
private <otherType> myProp;
#PostConstructor
public void init {
myProp = prop.getProp().getOtherTypeProp();
}
}
[here I have more FooControllers Foo2Controller, Foo3Controller, Foo4Controller...]
#ManagedBean
public class MainController {
// all props have getters and setters
private FooController fooController;
private int controllerType;
private List<SelectItem> myTypes;
private <type> prop;
#PostConstructor
public void init {
// init myTypes here
// init prop here
}
public static Object getBean(String s) {
FacesContext context = FacesContext.getCurrentInstance();
return context.getApplication().evaluateExpressionGet(context, "#{" + s + "}", Object.class);
}
public void controllerTypeChange (ValueChangeEvent event) {
controllerType = Integer.valueOf(event.getNewValue().toString());
if (controllerType == 1)
fooController = (Foo1Controller) getBean("foo1Controller");
else if (controllerType == 2)
fooController = (Foo2Controller) getBean("foo2Controller");
....
fooController.setProp(this.prop);
}
}
And this is the XHTML:
<o:SelectOneMenu id="fooType"
value = #{"MainController.controllerType"}
valueChangeListener = "#{MainController.controllerTypeChange}"
styleClass = "dropdown">
<o:ajax action = "#{MainController.controllerTypeChange}">
<f:selectItems value = "MainController.myTypes">
</o:selectOneMenu>
<h:panelGroup id="component1" rendered="#{MainController.controllerType == 1}">
<!-- some component here that uses foo1Controller as it's controller -->
</h:panelGroup>
<h:panelGroup id="component2" rendered="#{MainController.controllerType == 2}">
<!-- some component here that uses foo2Controller as it's controller -->
</h:panelGroup>
The thing is that when i'm creating the foo1Controller in the MainController bean, it's already uses the prop attribute in the foo1Controller #postConstructor but this attribute is NULL because it wasn't yet initialized and i have no idea how to do it before the post constructor is called.
The concept behind what i'm tring to do is that MainController can and should have only one child component and they all have a lot in common so it's a must to do here inheritance.
When the user select some value in the drop down the relative component should be displayd while the MainController should have a refrence to the component controller.
Any help will be very appreceated.
Thanks!
define servlet which should GenericServlet in your application do whatever you want. and define it in web.xml set load-on-startup tag.
Sample code for servlet
public class ResourceInitializer extends GenericServlet {
#Override
public void init(final ServletConfig config) throws ServletException {
super.init(config);
// YOUR APPLICATION INIT CODE
}
#Override
public void service(final ServletRequest req, final ServletResponse res)
throws ServletException {
}
#Override
public void destroy() {
// tell the ResourceManager to cleanup and remove the resouces
LibraOfficeService.getInstance().closeConnection();
super.destroy();
}
}
in the web.xml
<servlet>
<description>Initializes Resources</description>
<servlet-name>ResourceInitializer</servlet-name>
<servlet-class>packageNAME.ResourceInitializer</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
Is there any scope like JSF #ViewScoped in Spring 3.0? I have an application using JSF+Spring where backing beans are managed by Spring. I didn't find any scope like JSF wiew scope in Spring. I saw the blog Porting JSF 2.0’s ViewScope to Spring 3.0, but it didn't work for me.
Here's my attempt on the custom Spring scope:
import java.util.Map;
import javax.faces.context.FacesContext;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;
/**
* Implements the JSF View Scope for use by Spring. This class is registered as a Spring bean with the CustomScopeConfigurer.
*/
public class ViewScope implements Scope {
public Object get(String name, ObjectFactory<?> objectFactory) {
System.out.println("**************************************************");
System.out.println("-------------------- Getting objects For View Scope ----------");
System.out.println("**************************************************");
if (FacesContext.getCurrentInstance().getViewRoot() != null) {
Map<String, Object> viewMap = FacesContext.getCurrentInstance().getViewRoot().getViewMap();
if (viewMap.containsKey(name)) {
return viewMap.get(name);
} else {
Object object = objectFactory.getObject();
viewMap.put(name, object);
return object;
}
} else {
return null;
}
}
public Object remove(String name) {
System.out.println("**************************************************");
System.out.println("-------------------- View Scope object Removed ----------");
System.out.println("**************************************************");
if (FacesContext.getCurrentInstance().getViewRoot() != null) {
return FacesContext.getCurrentInstance().getViewRoot().getViewMap().remove(name);
} else {
return null;
}
}
public void registerDestructionCallback(String name, Runnable callback) {
// Do nothing
}
public Object resolveContextualObject(String key) { return null;
}
public String getConversationId() {
return null;
}
}
application-context.xml:
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="view">
<bean class="com.delta.beans.ViewScope"/>
</entry>
</map>
</property>
</bean>
Recently I've created maven artifact which will solve this problem.
See my github javaplugs/spring-jsf repository.
I did something like this without Porting bean to Spring. It's working for me.
#ManagedBean(name="bean")
#ViewScoped // actual jsf viewscoped only with javax.faces.viewscoped import
public class Bean implements
Serializable {
#ManagedProperty(value="#{appService}") // Spring Manged Bean and singleton
private transient AppService appService;
// Getting AppService Object which is singleton in the application during deserialization
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
stream.defaultReadObject();
FacesContext context = FacesContext.getCurrentInstance();
appService = (AppService)context.getApplication()
.evaluateExpressionGet(context, "#{appService}", AppService.class);
}
}
public class ViewScopeCallbackRegistrer implements ViewMapListener {
#SuppressWarnings("unchecked")
#Override
public void processEvent(SystemEvent event) throws AbortProcessingException {
if (event instanceof PostConstructViewMapEvent) {
PostConstructViewMapEvent viewMapEvent = (PostConstructViewMapEvent) event;
UIViewRoot viewRoot = (UIViewRoot) viewMapEvent.getComponent();
viewRoot.getViewMap().put(
ViewScope.VIEW_SCOPE_CALLBACKS,
new HashMap<String, Runnable>()
);
} else if (event instanceof PreDestroyViewMapEvent) {
PreDestroyViewMapEvent viewMapEvent = (PreDestroyViewMapEvent) event;
UIViewRoot viewRoot = (UIViewRoot) viewMapEvent.getComponent();
Map<String, Runnable> callbacks = (Map<String, Runnable>) viewRoot
.getViewMap().get(ViewScope.VIEW_SCOPE_CALLBACKS);
if (callbacks != null) {
for (Runnable c : callbacks.values()) {
c.run();
}
callbacks.clear();
}
}
}
#Override
public boolean isListenerForSource(Object source) {
return source instanceof UIViewRoot;
}
}
public class ViewScope implements Scope {
public static final String VIEW_SCOPE_CALLBACKS = "viewScope.callbacks";
#Override
public synchronized Object get(String name, ObjectFactory<?> objectFactory) {
Object instance = this.getViewMap().get(name);
if(instance == null){
instance = objectFactory.getObject();
this.getViewMap().put(name, instance);
}
return instance;
}
#SuppressWarnings("unchecked")
#Override
public Object remove(String name) {
Object instance = this.getViewMap().remove(name);
if(instance == null){
Map<String, Runnable> callbacks = (Map<String, Runnable>) this.getViewMap().get(VIEW_SCOPE_CALLBACKS);
if(callbacks != null)
callbacks.remove(name);
}
return instance;
}
/**
* Responsável por registrar uma chamada de destruição ao bean
* que será armazenadano [b]viewMap[/b] da [b]ViewRoot[/b](nossa página que será mostrada)
* #see #getViewMap()
* #param name - nome do bean
* #param runnable
*/
#SuppressWarnings("unchecked")
#Override
public void registerDestructionCallback(String name, Runnable runnable) {
Map<String, Runnable> callbacks = (Map<String, Runnable>) this.getViewMap().get(VIEW_SCOPE_CALLBACKS);
if(callbacks != null)
callbacks.put(name, runnable);
}
#Override
public Object resolveContextualObject(String key) {
FacesContext facesContext = FacesContext.getCurrentInstance();
FacesRequestAttributes facesResquestAttributes = new FacesRequestAttributes(facesContext);
return facesResquestAttributes.resolveReference(key);
}
#Override
public String getConversationId() {
FacesContext facesContext = FacesContext.getCurrentInstance();
FacesRequestAttributes facesResquestAttributes = new FacesRequestAttributes(facesContext);
return facesResquestAttributes.getSessionId() + "-" + facesContext.getViewRoot().getViewId();
}
private Map<String, Object> getViewMap(){
return FacesContext.getCurrentInstance().getViewRoot().getViewMap();
}
}
I have tried a work around for the Jsf view bean memory leak issue for both Jsf 2.1 & Jsf 2.2. Try the code in following link Memory leak with ViewScoped bean?. It will clear the view bean in session while navigating to next page.