Integrating JSF managed bean annotations with Spring Boot - spring

I use Spring boot with JSF 2.2. My problem is that I can create #ManagedBean from javax.annotation.ManagedBean and it is working in my index.xhtml when I run the app, but when I want to use javax.faces.bean.ManagedBean is not displaying the value. What's the difference between those two? Why I can't use the javax.faces.bean.ManagedBean? ( I don't have web.xml file, all is configured in classes)

The javax.annotation.* annotations are meant to be a move from the classic JSF annotations to a CDI approach. The Spring Framework has the ability to read some CDI annotations, so that could be the reason why this annotation "works". However, the trend in CDI is to use #Named, overall.
In a Spring Boot application, it's Spring the one scanning your annotations, not JSF. So, even you could think that the application works with #ManagedBean, you'll see that the #*Scoped annotations are useless, because all the created beans happen to be singletons, which is Spring's default scope.
In the end the choice I made was to use vanilla Spring annotations and scopes. As Spring lacks the JSF view scope, also a custom scope to emulate it.
MyBean.java:
#Component
#Scope("view")
public class MyBean {
//Here it goes your logic
}
ViewScope.java:
public class ViewScope implements Scope {
#Override
public Object get(String name, ObjectFactory<?> objectFactory) {
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;
}
}
#Override
public String getConversationId() {
return null;
}
#Override
public void registerDestructionCallback(String arg0, Runnable arg1) {
}
#Override
public Object remove(String name) {
return FacesContext.getCurrentInstance().getViewRoot().getViewMap().remove(name);
}
#Override
public Object resolveContextualObject(String arg0) {
return null;
}
}
Register the view scope with a CustomScopeConfigurer:
#Bean
public static CustomScopeConfigurer viewScope() {
CustomScopeConfigurer configurer = new CustomScopeConfigurer();
configurer.setScopes(
new ImmutableMap.Builder<String, Object>().put("view", new ViewScope()).build());
return configurer;
}
Finally, do not forget to add the Spring EL resolver in your faces-config.xml to make the Spring beans available through EL expressions:
<application>
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>
See also:
Why are there different bean management annotations
Backing beans (#ManagedBean) or CDI Beans (#Named)?
Configuring Spring Boot with JSF

Related

Spring Boot configuration for non-beans [duplicate]

This question already has answers here:
Injecting beans into a class outside the Spring managed context
(8 answers)
Closed 3 years ago.
Introduction
I have some business logic properties in the application.yml file.
They are loaded into the application via a #ConfigurationProperties annotated class.
How could I use these properties in a class which is not a Spring Bean? It cannot be a singleton, because many objects of it must be created during run-time.
Example
application.yml
business.foo: 2
BusinessProperties.java
#ConfigurationProperties("business")
#Getter // lombok
#Setter // lombok
public class BusinessProperties {
private int foo;
}
TypicalBean.java
#Component
public class TypicalBean {
private final BusinessProperties properties;
#Autowired
public TypicalBean(BusinessProperties properties) {
this.properties = properties;
}
#PostConstruct
public void printFoo() {
System.out.println("Foo: " + properties.getFoo()); // "Foo: 2"
}
}
NonBean.java
public class NonBean {
public void printFoo() {
System.out.println("Foo: ???"); // How to access the property?
}
}
Is there some way to create a non-singleton class, which can have access to configuration (or even other Spring beans) but otherwise works the same as a regular java class? Meaning that I can control its creation, it is collected by the garbage collector if not used anymore, etc.
You can still define the NonBean.class as a Component with Scope.Prototype
#Component
#Scope(value = BeanDefinition.SCOPE_PROTOTYPE)
public class NonBean {
#Autowired
public TypicalBean(BusinessProperties properties) {
this.properties = properties;
}
public void printFoo() {
System.out.println("Foo: " + properties.getFoo());
}
}
The trick is how you create an instance of NonBean.class. In the code where you'll be creating an instance of NonBean.class, use Spring's ObjectFactory<T>
private final ObjectFactory<NonBean> nonBeanFactory;
...
NonBean nonBean = nonBeanFactory.getObject();
The instantiated nonBean object will have been autowired.
All spring-beans creates by SpringApplicationContext. Bean - it's simple POJO-object, but created by Spring and saved in his container. If you want to get access to bean from outside of container - see this:
Getting Spring Application Context
Spring beans are really meant to be used within the application context but you might be able to achieve what you want by autowiring the properties to a static field in a Spring bean.
#Component
public class BusinessPropertiesUtils {
public static BusinessProperties INSTANCE;
#Autowired
public setBusinessProperties(BusinessProperties properties) {
this.INSTANCE = properties;
}
}
And then:
public class NonBean {
public void printFoo() {
System.out.println("Foo: " + BusinessPropertiesUtils.INSTANCE.getFoo());
}
}
PS: this is very hacky and definitely not the "Spring way".
You can configure beans with the prototype scope, which will give you a new instance of the bean every time it's requested.
From the Spring documentation:
In contrast to the other scopes, Spring does not manage the complete lifecycle of a prototype bean. The container instantiates, configures, and otherwise assembles a prototype object and hands it to the client, with no further record of that prototype instance.
...
In some respects, the Spring container’s role in regard to a prototype-scoped bean is a replacement for the Java new operator. All lifecycle management past that point must be handled by the client.
Example of how you can convert the TypicalBean class to a prototype scoped bean:
#Component
#Scope("prototype")
public class TypicalBean {
...
}
Another alternative is to manually instantiate the bean class (or any POJO) and injecting the dependencies (configuration, spring beans, etc.) through the constructor or setter methods, if you have them available or can get them from the Spring Context.
new TypicalBean(properties);

ClassBridge with DAO class injected

I have a Hibernate Search ClassBridge where I want to use #Inject to inject a Spring 4.1 managed DAO/Service class. I have annotated the ClassBridge with #Configurable. I noticed that Spring 4.2 adds some additional lifecycle methods that might do the trick, but I'm on Spring 4.1
The goal of this is to store a custom field into the index document based on a query result.
However, since the DAO, depends on the SessionFactory getting initialized, it doesn't get injected because it doesn't exist yet when the #Configurable bean gets processed.
Any suggestions on how to achieve this?
You might try to create a custom field bridge provider, which could get hold of the Spring application context through some static method. When provideFieldBridge() is called you may return a Spring-ified instance of that from the application context, assuming the timing is better and the DAO bean is available by then.
Not sure whether it'd fly, but it may be worth trying.
Hibernate Search 5.8.0 includes support for bean injection. You can see the issue https://hibernate.atlassian.net/browse/HSEARCH-1316.
However I couldn't make it work in my application and I had implemented a workaround.
I have created an application context provider to obtain the Spring application context.
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext context;
public static ApplicationContext getApplicationContext() {
return context;
}
#Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
ApplicationContextProvider.context = context;
}
}
I have added it to the configuration class.
#Configuration
public class RootConfig {
#Bean
public ApplicationContextProvider applicationContextProvider() {
return new ApplicationContextProvider();
}
}
Finally I have used it in a bridge to retrieve the spring beans.
public class AttachmentTikaBridge extends TikaBridge {
#Override
public void set(String name, Object value, Document document, LuceneOptions luceneOptions) {
// get service bean from the application context provider (to be replaced when HS bridges support beans injection)
ApplicationContext applicationContext = ApplicationContextProvider.getApplicationContext();
ExampleService exampleService = applicationContext.getBean(ExampleService .class);
// use exampleService ...
super.set(name, content, document, luceneOptions);
}
}
I think this workaround it's quite simple in comparision with other solutions and it doesn't have any big side effect except the bean injection happens in runtime.

How are components managed in Spring MVC and how to inject a customized component in Spring 3.2.5?

I’m considering to replace the DefaultSessionAttributeStore implementation of Spring MVC 3.2.5 with some class of my own, and I’ve known from the source code that in my 3.2.5 spring source, it’s SessionAttributesHandler which possesses a SessionAttributeStore interface reference and invokes the session store function. My question is how to replace that by DI? The SessionAttributesHandler holds a final private sessionAttributeStore reference and can only be set by the constructor:
public class SessionAttributesHandler {
...
private final SessionAttributeStore sessionAttributeStore;
...
public SessionAttributesHandler(Class<?> handlerType, SessionAttributeStore sessionAttributeStore) {
Assert.notNull(sessionAttributeStore, "SessionAttributeStore may not be null.");
this.sessionAttributeStore = sessionAttributeStore;
SessionAttributes annotation = AnnotationUtils.findAnnotation(handlerType, SessionAttributes.class);
if (annotation != null) {
this.attributeNames.addAll(Arrays.asList(annotation.value()));
this.attributeTypes.addAll(Arrays.<Class<?>>asList(annotation.types()));
}
for (String attributeName : this.attributeNames) {
this.knownAttributeNames.put(attributeName, Boolean.TRUE);
}
}
...
}
Are all the components of spring mvc managed in the spring DI container? How to inject my own SessionAttributeStore implementation into SessionAttributesHandler? What does the "Class handlerType" argument mean in the constructor? From source, it seems like it's the "controller" class. Since SessionAttributesHandler is invoked and held by a ModelFactory, and in ModelFactory there is no code instantiating the SessionAttributesHandler, is there any "XML" bean configuration file for the Spring MVC inner components and how to overwrite them?
If you want to provide your own implementation of a SessionAttributeStore you need to manually configure the RequestMappingHandlerAdapter and set your custom implementation on there. That will take care of using it through-out the rest of the infrastructure.
Assuming that you use java config you can do the following
#Configuration
public class MyConfiguration extend WebMvcConfigurationSupport {
#Bean
public SessionAttributeStore sessionAttributeStore() {
return new MyCustomSessionAttributeStore();
}
#Override
#Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
RequestMappingHandlerAdapter rmha = super.requestMappingHandlerAdapter();
rmha.setSessionAttributeStore(sessionAttributeStore());
return rmha;
}
}
If you want to do this in XML you either have to write a BeanPostProcessor which sets it on the default RequestMappingHandlerAdapter instance created by <mvc:annotation-driven /> or configure it manually and drop the namespace support.

Why Spring #Autowired ApplicationContext appContext is null?

I have Spring bean with annotations:
#Named
#Scope("session")
And this bean property:
#Autowired
ApplicationContext appContext;
The Spring configuration file has entry (that works for other anotations/injections):
<context:component-scan base-package="my.package.name" />
Why appContext is null after such code and configuration?
I am trying to get ApplicationContext (to call getBean(...) on it) and this can be quite involved task (judging from other discussions) in previous Spring versions (e.g. one is required to get ServletContext in Spring web application to create ApplicationContext and getting ServletContext can be quite involved task for beans that don't directly access HTTP Request objects). In Spring 3.x, as I understand, simple #Autwired injection can be used. How AppContext can be accessed?
Here the first problem is you are using #Named which is Java EE annotation and as for as I know Spring yet to support Java EE annotations. Hence instead of using #Named try to use Spring annotation #Service, #Component, #Repository etc.
Here is the example for you I have used JSF Managed bean as well to show how to integrate beans.
#ManagedBean(name="myBacking")
#RequestScoped
public class MyBacking {
private String myText;
#ManagedProperty(value="#{mySpring}")
MySpringBean mySpring;
public String getMyText() {
myText = mySpring.getText();
return myText;
}
public void setMyText(String myText) {
this.myText = myText;
}
public MySpringBean getMySpring() {
return mySpring;
}
public void setMySpring(MySpringBean mySpring) {
this.mySpring = mySpring;
}
}
#Service("mySpring")
#Scope("request")
public class MySpringBean {
#Autowired
MySecond mySecond;
public String getText(){
return "Hello KP" + mySecond.appObj();
}
}
#Service
#Scope("request")
public class MySecond {
#Autowired
ApplicationContext applicationContext;
public String appObj(){
MyThrid mythird =(MyThrid)applicationContext.getBean("myThrid");
return "My Second Bean calld "+ mythird.getTxt();
}
}
#Service
public class MyThrid {
public String getTxt(){
return "from thrid Bean";
}
}

Managed beans with custom ViewScope

I'm doing a Web application using Spring 3.1.0.RELEASE, JSF 2.x, JPA 2 with Hibernate Provider. I use PrettyFaces 3.3.2 for friendly URL. The application run on Tomcat 6.35 .
I wanted to use the Jsf ViewScope so I decided to follow the implementation found on the web : http://comdynamics.net/blog/109/spring3-jsf2-view-scope/
public class ViewScope implements Scope {
private static final Logger logger = LoggerFactory.getLogger(ViewScope.class);
#Override
public Object get(String name, ObjectFactory objectFactory) {
final Map<String, Object> viewMap = FacesContext.getCurrentInstance().getViewRoot().getViewMap();
Object instance = viewMap.get(name);
if (instance == null) {
instance = objectFactory.getObject();
viewMap.put(name, instance);
}
return instance;
}
#Override
public Object remove(String name) {
logger.debug("ViewScope::remove {}", name);
return FacesContext.getCurrentInstance().getViewRoot().getViewMap().remove(name);
}
#Override
public String getConversationId() {
return null;
}
#Override
public void registerDestructionCallback(String name, Runnable callback) {
//Not supported
}
#Override
public Object resolveContextualObject(String key) {
return null;
}
}
I notice that #PreDestroy are not called on them like show this question #PreDestroy never called on #ViewScoped.
Does it mean that the Managed beans with ViewScope are never destruct ? Which conduct to memory leak. Should we use this scope so?
It's only happen with custom Viewscope on Spring or also on Mojarra ?
Thanks.
Problem is incorrect implementaiton of view scope. It is creates Spring bean objectFactory.getObject(); but never destroy it.
To solve it - check correct implementation with support for registerDestructionCallback.
BWT, current Mojjara implementation will not call #PreDestory on your bean too.
But it will free bean instance at least.
I tried the work around for Jsf view scope bean memory leaks using spring custom view scope. It works for both Jsf 2.1 & 2.2.Try the code in below link.
Memory leak with ViewScoped bean?

Resources