How do I access EJB bean when inside a custom Converter [duplicate] - java

This question already has answers here:
How to inject #EJB, #PersistenceContext, #Inject, #Autowired, etc in #FacesConverter?
(5 answers)
Closed 8 years ago.
This converter is called from my JSF. I already register it inside faces-config.xml
public class ProjectConverter implements Converter{
#EJB
DocumentSBean sBean;
#ManagedProperty(value="#{logging}")
private Logging log;
public ProjectConverter(){
}
public Object getAsObject(FacesContext context, UIComponent component, String value)
{
if(value.trim().equals("")){
return null;
}
return sBean.getProjectById(value);
}
public String getAsString(FacesContext context, UIComponent component, Object value)
{
if(value == null){
return null;
}
return String.valueOf(((Project) value).getId());
}
}
I ran into java.lang.NullPointerException, when I am in getAsObject(), the primary reason is because my Session Bean sBean is null. I dont know how to fix this, I need to access to my Session bean so that I can query from my database

As BalusC said, injection only works in managed beans. You can however declare your converter as a managed bean in your faces-config
<managed-bean>
<managed-bean-name>myConverter</managed-bean-name>
<managed-bean-class>com.example.MyConverter</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
And later reference it in a jsf component with an el expression:
<h:outputText value="#{myBean.value}" converter="#{myConverter}" />

Related

Is it safe to use a Spring BeanPostProcessor with reflection to change private field values in the bean

I am using Springs BeanPostProcessor to loop through all the declared fields for the passed in bean, and if any of them has a particular annotation, then I want to modify that fields value in some way.
The code to do this (omitting the annotation declaration) looks roughly like the below, and seems work correctly (so far):
#Component
public class AnnotationProcessingBeanPostProcessor implements BeanPostProcessor {
#Override
public final Object postProcessAfterInitialization(final Object bean, final String beanName) {
return bean;
}
#Override
public final Object postProcessBeforeInitialization(Object bean, final String beanName) {
Field[] fields = bean.getClass().getDeclaredFields();
List<Field> fieldsWithAnno = new ArrayList<>();
for (Field field : fields) {
if (field.isAnnotationPresent(SomeAnno.class)) {
try {
field.setAccessible(true);
field.set(bean, "HELLO WORLD!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
return bean;
}
}
My concern is, I believe the beans themselves are wrapped in some sort of proxy object, so the actual instance of the bean here is not a DIRECT instance of my particular bean.
So could doing this sort of thing cause some unforseen issue?
What I am ACTUALLY trying to achieve
I want to annotate fields with something like:
#GetStringFromFile(fileName = "whatever.txt")
private String somePrivField;
Then when I find a field with that annotation, I will read the file in, and inject it's String value, and if the file doesn't exist or can't be read properly, throw an exception, and stop my spring app from starting up.

Use Spring dependency injection on a custom Hibernate validator

I want to create my own Hibernate custom Validator and what I would like to do is to add custom logic based on some information gathered from a different context (a different Spring bean)
On my custom implementation, I have tried to both add a constructor and define the validator in a spring bean, or to use the Autowire annotation and none of them worked
Autowire example:
public class MyCustomValidator implements ConstraintValidator<CustomConstraint, String> {
#Autowired
private MyCustomChecker customChecker;
#Override
public void initialize(CustomConstraint constraintAnnotation) {
}
#Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (null == value) {
return true;
}
//get user authenticated properties to perform validation based on the user
AuthenticatedIdentity identity = Context.getAuthenticatedIdentity();
return customChecker.isWhitelisted(identity);
}
}
Constructor example:
public class MyCustomValidator implements ConstraintValidator<CustomConstraint, String> {
private MyCustomChecker customChecker;
public MetricDataSizeValidator(MyCustomChecker customChecker) {
this.customChecker = customChecker;
}
#Override
public void initialize(CustomConstraint constraintAnnotation) {
}
#Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (null == value) {
return true;
}
//get user authenticated properties to perform validation based on the user
AuthenticatedIdentity identity = Context.getAuthenticatedIdentity();
return customChecker.isWhitelisted(identity);
}
}
I've read around on the official Hibernate doc but that doesn't quite answer my question.
I am pretty sure this is a common issue when you want to validate based on some information based from a different context, however I didn't find around an answer for this.
My app is using Spring DI, where my bean is already initialized like this
<bean id="customChecker" class="com.mycomp.CustomChecker">
<constructor-arg>
<value>arg</value>
</constructor-arg>
</bean>
Is there any example around of how to achieve this?
Update
If I configure my Validator to be:
<bean id="validatorFactory" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
<bean id="validator" factory-bean="validatorFactory"
factory-method="getValidator" />
Now I can see the validation is wired up correctly using spring beans. However, now I'm doubtful whether I'm using HibernateValidator (I think I'm not). Is there any way to achieve the same but configure HibernateValidator factory to use Spring beans?
I assume your MyCustomValidator is not recognized as a managed spring bean, so no autowiring will occur.
The easiest way to make your MyCustomValidator a spring bean is to add the #Component annotation at the class level.
You can use InitBinder in case of Spring MVC where your custom validator will automatically called by the RequestMappingHandlerAdapter.
Simply annotate your method in the controller with #InitBinder and inside the method provide your validator and provide the your validator class to WebDataBinder by calling webDataBinder.setValidator()

How to pass a value from a #ApplicationScoped to a #ViewScoped?

When trying to pass the value I receive this error:
javax.servlet.ServletException: javax.servlet.ServletException: Unable to >create managed bean createController. The following problems were found:
Property configMB for managed bean createController does not exist. Check that appropriate getter and/or setter methods exist.
The scope of the object referenced by expression #{configMB}, request, is shorter than the referring managed beans (createController) scope of view at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:138)
Is it possible to pass a value from #ApplicationScoped to #ViewScoped?
You can inject long-life beans into short-life beans. (Not vice versa)
#ApplicationScoped
public class AppBean {
private Object someValue;
//getters
}
#ViewScoped
public class ViewBean {
#Inject
private AppBean appBean;
public void sendForm() {
Object value = appBean.getSomeValue();
// do things...
}
}

JSF Bean property not updated [duplicate]

This question already has an answer here:
JSF does not populate #Named #RequestScoped bean with submitted input values
(1 answer)
Closed 5 years ago.
I have a bean with a field called 'name', and a JSF form that has an inputText mapped with this field. The initial value of the field is well displayed on the form.
The problem is when I submit the form, the value is not updated with the content of the inputText. In the savePlayer() method below, the value of name is always 'name', not what I typed inside the form input.
The bean :
#Named
#RequestScoped
public class PlayerForm {
#Inject
private PlayerRepository playerRepository;
private String name = "name";
public String savePlayer(){
Player player = new Player();
player.setName(name);
playerRepository.savePlayer(player);
return "saveUserOk";
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
The form :
<h:form>
<h:inputText value="#{playerForm.name}" />
<h:commandButton value="Submit" action="#{playerForm.savePlayer}" />
</h:form>
Thanks very much for any help!
This can happen if you imported #RequestScoped from the package javax.faces.bean (JSF) instead of from javax.enterprise.context (CDI). Every single EL expression #{} would then create a brand new and completely separate instance of the bean. The given form example would then end up in two instances of the bean, one where the name is set and another where the action is invoked.
The javax.faces.bean.RequestScoped annotation can only be used in conjunction with JSF's own #ManagedBean annotation not with CDI's #Named annotation.

How to get the set of beans that are to be created in Spring?

So here's the scenario:
I have a Spring XML configuration with some lazy-beans, some not lazy-beans and some beans that depend on other beans. Eventually Spring will resolve all this so that only the beans that are meant to be created are created.
The question: how can I programmatically tell what this set is?
When I use context.getBean(name) that initializes the bean. BeanDefinition.isLazyInit() will only tell me how I defined the bean.
Any other ideas?
ETA:
In DefaultListableBeanFactory:
public void preInstantiateSingletons() throws BeansException {
if (this.logger.isInfoEnabled()) {
this.logger.info("Pre-instantiating singletons in " + this);
}
synchronized (this.beanDefinitionMap) {
for (Iterator it = this.beanDefinitionNames.iterator(); it.hasNext();) {
String beanName = (String) it.next();
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
FactoryBean factory = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName);
if (factory instanceof SmartFactoryBean && ((SmartFactoryBean) factory).isEagerInit()) {
getBean(beanName);
}
}
else {
getBean(beanName);
}
}
}
}
}
The set of instantiable beans is initialized. When initializing this set any beans not in this set referenced by this set will also be created. From looking through the source it does not look like there's going to be any easy way to answer my question.
Perhaps
ApplicationContext.getBeanDefinitionNames()
Note that there is no (decent) way to determine which beans will be instantiated and which won't. If you are using ApplicationContextAware, you get access to all the beans at runtime, which makes this unpredictable.
So far my solution is:
Create ExtendedApplicationContext implementing ApplicationContextAware
Have the beans call initialized(this) on a static instance of ExtendedApplicationContext
Use this set plus the set of all bean definitions that are not singletons, abstract or lazy-initialized to create the set of intialized beans in ExtendedApplicationContext
Any better suggestions are welcome.
This is probably the best way, using a BeanPostProcessor:
public class IsIntializedBeanPostProcessor implements BeanPostProcessor {
private Set<String> initializedBeanNames = new HashSet<String>();
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
initializedBeanNames.add(beanName);
return bean;
}
public Set<String> getInitializedBeanNames() {
return initializedBeanNames;
}
}
Then all you have to do is include this as a bean somewhere in the Spring config in order for it to work.

Categories