Writing a simple JSF application I've some across the following Problem:
My entities.controller.EntityNameManager class contains a method getEntityNameSelectList() which I can use to populate a ComboBox with. This works and shows all Entities, since the Method to retrieve the Entities does not have a where clause.
This Method was automatically created.
Now I want to have a second similar Method, that filters the options based on a variable in the sessionscope. To do this I copied the original Method, renamed it to getEntityNameSelectListByUser(User theUser) and changed the Method that queries the database to one that does indeed filter by UserId.
However, when trying to load the page in the browser, I get an error stating that the controller class does not have a "EntityNameSelectListByUser" property. I assume that since my new method expects a parameter it can't be found. Is there a way I can make it aware of the Parameter or the Sessionscope userid?
Support for parameters in EL is slated for the next maintenance release of JSR 245 (announcement here; implementation here).
Assuming you don't want to wait for JEE6, you have several ways to overcome this limitation. These approached are defined in terms of POJO managed beans, so adapt them to your EJBs as appropriate.
1.
Do the session lookup and function call in a backing bean:
public String getFoo() {
FacesContext context = FacesContext
.getCurrentInstance();
ExternalContext ext = context.getExternalContext();
String bar = (String) ext.getSessionMap().get("bar");
return getFoo(bar);
}
Example binding:
#{paramBean.foo}
2.
Use an EL function (defined in a TLD, mapped to a public static method):
public static String getFoo(ParamBean bean, String bar) {
return bean.getFoo(bar);
}
Example binding:
#{baz:getFoo(paramBean, bar)}
3.
Subvert the Map class to call the function (a bit of a hack and limited to one parameter):
public Map<String, String> getFooMap() {
return new HashMap<String, String>() {
#Override
public String get(Object key) {
return getFoo((String) key);
}
};
}
Example binding:
#{paramBean.fooMap[bar]}
Related
I want to avoid boiler plate code for creating a list of SelectItems to map my entities/dtos between view and model, so I used this snippet of a generic object converter:
#FacesConverter(value = "objectConverter")
public class ObjectConverter implements Converter {
private static Map<Object, String> entities = new WeakHashMap<Object, String>();
#Override
public String getAsString(FacesContext context, UIComponent component, Object entity) {
synchronized (entities) {
if (!entities.containsKey(entity)) {
String uuid = UUID.randomUUID().toString();
entities.put(entity, uuid);
return uuid;
} else {
return entities.get(entity);
}
}
}
#Override
public Object getAsObject(FacesContext context, UIComponent component, String uuid) {
for (Entry<Object, String> entry : entities.entrySet()) {
if (entry.getValue().equals(uuid)) {
return entry.getKey();
}
}
return null;
}
}
There are already many answers to similliar questions, but I want a vanilla solution (without *faces). The following points still leave me uncertain about the quality of my snippet:
If it was that easy, why isn't there a generic object converter build into JSF?
Why are so many people still using SelectItems? Isn't there more flexibility by using the generic approach? E.g. #{dto.label} can be quickly changed into #{dto.otherLabel}.
Given the scope is just to map between view and model, is there any major downside of the generic approach?
This approach is hacky and memory inefficient.
It's "okay" in a small application, but definitely not in a large application with tens or hundreds of thousands of potential entities around which could be referenced in a f:selectItems. Moreover, such a large application has generally a second level entity cache. The WeakHashMap becomes then useless and is only effective when an entity is physically removed from the underlying datastore (and thus also from second level entity cache).
It has certainly a "fun" factor, but I'd really not recommend using it in "heavy production".
If you don't want to use an existing solution from an utility library like OmniFaces SelectItemsConverter as you already found, which is basically completely stateless and doesn't use any DAO/Service call, then your best bet is to abstract all your entities with a common base interface/class and hook the converter on that instead. This only still requires a DAO/Service call. This has been fleshed out in detail in this Q&A: Implement converters for entities with Java Generics.
I am working on a project with jsf 2.2 on the web side and spring 4 on the business side. I have a web filter which receives a parameter from the request url. From this parameter I have to connect to a database. There are cases where there are different databases possible, so depending on the parameter I have to initiate a different database connection. The web filter looks like this:
#Component
public final class SecurityFilter implements Filter
{
#Autowired
private CommonEao commonEao;
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException
{
HttpServletRequest req = (HttpServletRequest)request;
String instance = req.getParameter("instance");
//I would like to have something here like:
// springContext.addParameter("instance", instance);
String company = req.getParameter("company");
commonEao.getConfiguration(company);
... Do stuff
}
}
How does it works? The commonEao contains methods to make queries to the database (JPA/Eclipselink...). At initialization, no entityManager is present in commonEao since it is injected in SecurityFilter before the doFilter is executed when an url is requested. After the url is requested, the instance of the database to use is known through the 'instance' request parameter.
When the method commonEao.getConfiguration(company) is invoked, the first thing that should happen is to create an entity Manager:
#Repository
public final class CommonEao extends AbstractEao
{
public final void getConfiguration(final String company)
{
if (entityManager == null)
{
//I would like to have something here like:
// String instance = springContext.getParameter("instance");
createEntityManager(instance);
}
else ...
}
}
As you can see, when the first time the url is requested, no entityManager exists and it needs to be created based on the instance name provided by the request. Based on the instance name the properties files containing database connection parameters will be used the call the Persistence.createEntityManagerFactory functionality... etc etc... :)
What is the idea? The idea that I had, as you can see in my comments, is to put a parameter in some global context/container that is available for all Spring beans. This idea comes from the JSF world, where you can create a managed bean, annotate it with applicationscope, define a variable in it, and access this variable from any jsf managed bean through injecting the application scoped bean with the managedproperty annotation:
#ManagedBean
public final class SomeJsfBean
{
#ManagedProperty(value = "#{applicationBean}")
private ApplicationBean applicationBean;
private void method()
{
applicationBean.setInstanceName("instance");
}
}
#ManagedBean
public final class AnotherJsfBean
{
#ManagedProperty(value = "#{applicationBean}")
private ApplicationBean applicationBean;
private void method()
{
String instance = applicationBean.getInstanceName();
}
}
I have some restrictions though. I want to use a global object of Spring. I don't have any XML config in my project. Spring is configured like this and nothing more:
#Configuration
#ComponentScan(value = { "megan.fox.is.hot", "as.is.lindsay.lohan" })
public class SpringConfiguration
{
}
I have looked in many places, something I found was fetching a property from PropertyPlaceholderConfigurer and stuff like that, but I didn't understand how it works and mainly it looks way too complex for what i need: just sharing one variable.
There must be an easy solution like in the JSF world, but i suspect i am looking for the wrong name in the Spring world! :)
Any help is greatly appreciated, this is the last thing I need to fix in my project!
In my XPages application, I use a managed Java bean (scope = application) for translating strings:
public class Translator extends HashMap<String,String> implements Serializable {
private static final long serialVersionUID = 1L;
public String language = "en";
public Translator() { super(); this.init(null); }
public Translator(String language) { super(); this.init(language); }
public boolean init(String language) {
try {
FacesContext context = FacesContext.getCurrentInstance();
if (language!=null) this.language=language;
Properties data = new Properties();
// load translation strings from properties file in WEB-INF
data.load(new InputStreamReader(context.getExternalContext().getResourceAsStream("WEB-INF/translations_"+this.language+".properties"),"UTF-8"));
super.putAll(new HashMap<String,String>((Map) data));
// serializing the bean to a file on disk > this part of the code is just here to easily test how often the bean is initialized
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("C:\\dump\\Translator_"+this.language+"_"+new Date().getTime()+".ser"));
out.writeObject(this);
out.close();
return true;
}
catch (Exception e) { return false; }
}
public String getLanguage() { return this.language; }
public boolean setLanguage(String language) { return this.init(language); }
// special get function which is more tolerant than HashMap.get
public String get(Object key) {
String s = (String) key;
if (super.containsKey(s)) return super.get(s);
if (super.containsKey(s.toLowerCase())) return super.get(s.toLowerCase());
String s1 = s.substring(0,1);
if (s1.toLowerCase().equals(s1)) {
s1=super.get(s1.toUpperCase()+s.substring(1));
if (s1!=null) return s1.substring(0,1).toLowerCase()+s1.substring(1);
} else {
s1=super.get(s1.toLowerCase()+s.substring(1));
if (s1!=null) return s1.substring(0,1).toUpperCase()+s1.substring(1);
}
return s;
}
}
I use "extends HashMap" because in this way i only have to write "${myTranslatorBean['someText']}" (expression language) to get the translations into my XPage. The problem is that the bean is re-initialized at EVERY complete refresh or page reload. I tested this by serializing the bean to a unique file on the disk at the end of every initialisiation. In my other managed Java beans (which do not use "extends HashMap") this problem does not occur. Can anybody tell me what's wrong with my code? Thanks in advance.
EDIT: The entry for the managed Java bean in the faces-config.xml looks like this:
<managed-bean>
<managed-bean-name>myTranslatorBean</managed-bean-name>
<managed-bean-class>com.ic.Translator</managed-bean-class>
<managed-bean-scope>application</managed-bean-scope>
</managed-bean>
I concur with David about the faces-config entry - if you could post it, that could shine some light on it.
In its absence, I'll take a stab at it: are you using a managed property to set the "language" value for the app. If you are, I suspect that there's a high chance that the runtime calls the setLanguage(...) method excessively. Since you call this.init(...) in that method, that would re-run that method repeatedly as well.
As a point of code style you are free to ignore, over time I (in part due to reading others' opinions) have moved away from extending collection classes directly for this kind of use. What I do instead in this situation is create an object that implements the DataObject interface and then uses a HashMap internally to store cached values. That's part of a larger industry preference called "Composition over inheritance": http://en.wikipedia.org/wiki/Composition_over_inheritance
Just to make sure nothings weird - I suggest you post your faces-config. I use beans all the time but haven't extended HashMap in any of them. You can add a map and still use EL.
Assuming you have a map getter like "getMyMap()" then EL might be:
AppBean.myMap["myKey"]
Truth be told I don't typically use that syntax but I BELIEVE that works. I gave it a quick test and it didn't work as I expected so I'm missing something. I tried something like:
imageData.size["Large"].url
I THINK it didn't work for me because my bean doesn't IMPLEMENT Map. I notice you're EXTENDING HashMap. You might want to try implementing it. I found an interesting post here: http://blog.defrog.nl/2012/04/settings-bean-parameterized-method-call.html
Usually I do still use SSJS to pass Parameters in. It's really not the end of the would using SSJS for that. And I use EL for everything else.
This is an example of passing an object to a custom control and return a TreeSet with EL.
value="#{compositeData.imageSet.allImages}">
Regarding the bigger issue of the bean re-initializing.. That is odd.. I don't do a ton with ApplicationScope. But I suggest you play with the constructor. I'm not sure what you get by calling super() there. I would suggest use a boolean to only run any init code of the boolean wasn't already set. Obviously you then set it in the init code. See what that does.
I am using Guice's RequestScoped and Provider in order to get instances of some classes during a user request. This works fine currently. Now I want to do some job in a background thread, using the same instances created during request.
However, when I call Provider.get(), guice returns an error:
Error in custom provider, com.google.inject.OutOfScopeException: Cannot
access scoped object. Either we are not currently inside an HTTP Servlet
request, or you may have forgotten to apply
com.google.inject.servlet.GuiceFilter as a servlet
filter for this request.
afaik, this is due to the fact that Guice uses thread local variables in order to keep track of the current request instances, so it is not possible to call Provider.get() from a thread different from the thread that is handling the request.
How can I get the same instances inside new threads using Provider? It is possible to achieve this writing a custom scope?
I recently solved this exact problem. There are a few things you can do. First, read up on ServletScopes.continueRequest(), which wraps a callable so it will execute as if it is within the current request. However, that's not a complete solution because it won't forward #RequestScoped objects, only basic things like the HttpServletResponse. That's because #RequestScoped objects are not expected to be thread safe. You have some options:
If your entire #RequestScoped hierarchy is computable from just the HTTP response, you're done! You will get new instances of these objects in the other thread though.
You can use the code snippet below to explicitly forward all RequestScoped objects, with the caveat that they will all be eagerly instantiated.
Some of my #RequestScoped objects couldn't handle being eagerly instantiated because they only work for certain requests. I extended the below solution with my own scope, #ThreadSafeRequestScoped, and only forwarded those ones.
Code sample:
public class RequestScopePropagator {
private final Map<Key<?>, Provider<?>> requestScopedValues = new HashMap<>();
#Inject
RequestScopePropagator(Injector injector) {
for (Map.Entry<Key<?>, Binding<?>> entry : injector.getAllBindings().entrySet()) {
Key<?> key = entry.getKey();
Binding<?> binding = entry.getValue();
// This is like Scopes.isSingleton() but we don't have to follow linked bindings
if (binding.acceptScopingVisitor(IS_REQUEST_SCOPED)) {
requestScopedValues.put(key, binding.getProvider());
}
}
}
private final BindingScopingVisitor<Boolean> IS_REQUEST_SCOPED = new BindingScopingVisitor<Boolean>() {
#Override
public Boolean visitScopeAnnotation(Class<? extends Annotation> scopeAnnotation) {
return scopeAnnotation == RequestScoped.class;
}
#Override
public Boolean visitScope(Scope scope) {
return scope == ServletScopes.REQUEST;
}
#Override
public Boolean visitNoScoping() {
return false;
}
#Override
public Boolean visitEagerSingleton() {
return false;
}
};
public <T> Callable<T> continueRequest(Callable<T> callable) {
Map<Key<?>, Object> seedMap = new HashMap<>();
for (Map.Entry<Key<?>, Provider<?>> entry : requestScopedValues.entrySet()) {
// This instantiates objects eagerly
seedMap.put(entry.getKey(), entry.getValue().get());
}
return ServletScopes.continueRequest(callable, seedMap);
}
}
I have faced the exact same problem but solved it in a different way. I use jOOQ in my projects and I have implemented transactions using a request scope object and an HTTP filter.
But then I created a background task which is spawned by the server in the middle of the night. And the injection is not working because there is no request scope.
Well. The solutions is simple: create a request scope manually. Of course there is no HTTP request going on but that's not the point (mostly). It is the concept of the request scope. So I just need a request scope that exists alongside my background task.
Guice has an easy way to create a request scope: ServletScope.scopeRequest.
public class MyBackgroundTask extends Thread {
#Override
public void run() {
RequestScoper scope = ServletScopes.scopeRequest(Collections.emptyMap());
try ( RequestScoper.CloseableScope ignored = scope.open() ) {
doTask();
}
}
private void doTask() {
}
}
Oh, and you probably will need some injections. Be sure to use providers there, you want to delay it's creation until inside the created scope.
Better use ServletScopes.transferRequest(Callable) in Guice 4
I have an input (JSF) that should be bound to a property in my bean. This property represents another bean and has an auxiliar method that checks if it's null (I use this method a lot).
The problem is that the binding is failing to get the proper getter and setter. Instead of reading the method that returns the bean, it reads the one that return a boolean value.
The property name is guest. The methods are:
getGuest;
setGuest;
isGuest (checks if guest is null).
JSF is trying to bind the object to isGuest and setGuest, instead of getGuest and setGuest.
I cannot rename isGuest to guestIsNull or something, because that would'nt make to much sense (see the class below).
Finally, my question is: how can I bind this property to the object without renaming my methods? Is it possible?
I also accept suggestions of a better method name (but the meaning must be the same).
Entity
#Entity
public class Passenger {
private Employee employee;
private Guest guest;
public Passenger() {
}
#Transient
public boolean isEmployee() {
return null != this.employee;
}
#Transient
public boolean isGuest() {
return null != this.guest;
}
#OneToOne
public Employee getEmployee() {
return this.employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
#OneToOne
public Guest getGuest() {
return this.guest;
}
public void setGuest(Guest guest) {
this.guest = guest;
}
}
JSF
<h:inputText value="#{passenger.employee}" />
<h:inputText value="#{passenger.guest}" />
Change the method name to isGuestNull.
The problem you're seeing is due to the fact that the EL lets you use getFoo or isFoo as the naming style for getter methods that return booleans.
No, that's not possible. You've to rename them.
Another way is to add a single getter returning an enum which covers all cases.
public enum Type {
GUEST, EMPLOYEE;
}
public Type getType() {
return guest != null ? Type.GUEST
: employee != null ? Type.EMPLOYEE
: null;
}
with
<h:something rendered="#{passenger.type == 'GUEST'}">
Binding to any property using any method is possible and quite easy if you create your custom ELResolver (apidocs). elresolvers are registered in faces config, and they are responsible, given an Object and a String defining a property, for determining the value and type of the given properties (and, as the need arises, to change it).
You could easily write your own ELResolver that would only work for your chosen, single type, and use (for example in a switch statement) the specific methods you need to write and read properties. And for other types it would delegate resolving up the resolver chain. It's really easy to do, much easier than it sounds.
But don't do it. The standard naming pattern of properties predates EL by many years. It is part of the JavaBeans™ standard - one of the very few undisputed standards in Javaland, working everywhere - from ant scripts, through spring configuration files to JSF. Seeing methods isPerson and getPerson in one class actually makes me fill uneasy, as it breaks something I always take for granted and can always count on.
If you like DDD and want to have your method's names pure, use an adapter. It's easy, fun, and gives a couple of additional lines, which is not something to sneer at if you get paid for the ammount of code produced:
public class MyNotReallyBean {
public String checkName() { ... }
public String lookUpLastName() { ... }
public String carefullyAskAboutAge() { ... }
public class BeanAdapter {
public String getName() { return checkName(); }
public String getLastName() { return lookUpLastName(); }
public String getAge() { return carefullyAskAboutAge(); }
}
private static BeanAdapter beanAdapter = new BeanAdapter();
private BeanAdapter getBeanAdapter(){ return beanAdapter; }
}