I want to introduce CDI to existing project. Currently we are creating new objects inside for loop like
Context context;
for(String string : strings) {
context = new Context();
// do some operations with string.
// set outcomes of above operation in context.
}
Now if I am injecting Context as
#Inject Context context;
I'm getting same instance every time.
I'm wondering if there is any way available in CDI to create new Context inside loop?
As long as you do not use special scopes, you can use
#Inject
Instance<B> bProvider;
...
B b = bProvider.get();
and you will get a new "B" everytime. Check out this gist.
Related
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 some button on my form. When I click on every buttons run new form with same buttons. When I am clicking many times, show error OutOfMemory.
I think this is because I create a lot of form objects.
May be can clear stack or use form from stack if form is there?
You are keeping pointers (references) to old components which causes a memory leak. Make sure never to store components as members of your class unless you clear them later.
you need to use the Singleton pattern for your code. In Singleton Pattern, It will create only one object of your Form Class. If the object is null then it will create a new one else , it will return the current one. For this kindly refer to following code.
// Private Constructor
private static myForm thisForm = null;
private myForm()
{
thisForm = this;
}
// Now to Create Object, you need to create following getInstance Method
public static myForm getInstance()
{
if ( thisForm == null )
{
thisForm = new myForm();
}
return thisForm;
}
try above logic in your whole code. Your OutOfMemory Problem will 100% get solved.
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]}
Actually in my JSF application I have this code to compute a component clientId from its id:
public static String getComponentClientId(String id) {
try {
FacesContext fctx = FacesContext.getCurrentInstance();
UIComponent found = getComponentWithId(fctx.getViewRoot(), id);
if (found!=null)
return found.getClientId(fctx);
else
return null;
} catch (Exception e) {
return null;
}
}
public static UIComponent getComponentWithId(UIComponent parent, String id) {
for (Iterator<UIComponent> chs = parent.getFacetsAndChildren(); chs.hasNext();) {
UIComponent ch = chs.next();
if (ch.getId().equalsIgnoreCase(id))
return ch;
else {
UIComponent found = getComponentWithId(ch, id);
if (found!=null)
return found;
}
}
return null;
}
The method works, but it navigate through the view component tree, so it can be very inefficient, specially in presence of highly populated pages. There is a clever way or an API that I don't know to make the job faster/easier?
Not that I know of.
It is difficult to cache this information, because:
The relationship between an instance of UIComponent and its clientIds can be 1:N. This is required for components like UIData that manage the state of their children. The return value from getClientId can be context-sensitive.
The lifetime of a UIComponent instance probably won't exceed the request. Some implementations of StateManager can be configured to save the view state in the session, in which case the lifetime of the objects might be longer, but making your code rely on this makes it fragile and it would be easy to introduce memory leaks.
Views can be dynamic. Admittedly, this is an edge case, but it is possible to add, remove and move components programmatically.
I would prove that this is a problem before trying another approach.
You don't say what you need the clientIds for, but I'm guessing it is for some form of JavaScript support. Consider writing a custom component and emitting your markup via its renderer. This could be used with a for attribute, similar to the label control. Finding a neighbour in the same NamingContainer is relatively easy. You might use code like this in your renderer implementation:
// untested code!
String clientId = mycomponent.getClientId(context);
// get id of target control
String _for = mycomponent.getFor();
int n = clientId.lastIndexOf(NamingContainer.SEPARATOR_CHAR);
String targetClientId = clientId.substring(0, n)
+ NamingContainer.SEPARATOR_CHAR + _for;
ResponseWriter writer = context.getResponseWriter();
// write markup
Components usually need to share a naming container to make use of each other's clientId anyway, so this isn't a big constraint. If you can make the component a child, it is easier to find a parent.
Of course, this approach has problems too. It makes your UI tree even bigger, with a knock-on effect on lifecycle processing and state-management. Whether the trade-off is worth it would require testing.
EDIT:
I thought about this over the weekend. Since 50% of JSF queries seem to be about how to work with IDs, I wrote a post so I can just refer people to it - JSF: working with component IDs. In includes a mechanism for caching the IDs (sort of!) with some sample code.