I would like to get an unproxied instance of a bean so that another module won't break as it throws an exception indicating the object I'm passing to it isn't of the right type.
Is this possible, if so how? I don't want to create a new instance of the object because it already has some state saved. I am hoping there is a short and quick way for me to get the actual object from the proxied instance.
You can't in a none implementation specific way, and you shouldn't.
The only thing you can do is to use a scope that doesnt need proxies. The two common ones are #javax.enterprise.context.Dependent and #javax.inject.Singleton.
Depending on use case you might be able to wrap it in an #Dependent scope been.
Related
The "binding" basic property is described as a property that "Specifies an expression that binds a control to a particular control property". I tried to google and read at HCL docs but there is no example on how to use it.
The binding property allows you to specify an object property (say, on a managed bean or dataContext) that will be set to the specified component. For example, you could do:
<xp:inputText binding="#{someBean.textField}"/>
...and that would call someBean.setTextField(XspInputText inputText).
All that said, it's kind of an edge-case property. I've made good use of it, but it's largely an artifact of earlier JSF revisions, when it was more common to have backing logic that "knew" about the front-end XPage explicitly.
In general, it's better design to stick to value bindings like value="#{someBean.firstName}" and not make your backing objects aware of the front-end UI, unless you have an explicit reason to do otherwise.
What's the difference? When should I prefer one over another?
And some minor questions related to this:
if I have object data, when is saveObject called?
it looks like garbage collector recycles all my domino handles. I tried to downcast then clone it, but it didn't help (how does it know its still a domino object?). Is there a workaround?
if I create "var tmpVar = new package.TestClass()" from xPages, it gets recycled on update. But if I create java object from bean it stays there. Correct?
Managed beans are exactly that, managed by the XPages runtime. They are created as and when there is a first call to them. Although they have an empty constructor, managed-properties elements in the faces-config allow you to define values (and I believe you can add SSJS code to the faces-config to compute the values).
Object data sources allow you to handle what's created when, and it means they can be scoped to a smaller level than viewScope - to a Panel or Custom Control. The saveObject method is called by a Save All Datasources event. In reality, if you're coding object data sources, you'll code a button and call the relevant method rather than use a simple action.
Java variables can get recycled, but Domino objects are only recycled via two methods. The first is calling recycle() methods, the second is at the end of each request, when the session gets recycled. Because recycle() calls recycle all child elements, everything gets recycled at the end of a request. Which is why you can't store Domino objects in scoped variable or any other persisted object (i.e. a bean). Note that objects like DateTimes, RichTextStyles etc are children of the session, not of any more granular Domino object like a NotesItem or NotesRichTextItem.
var tmpVar = new package.TestClass() will only get persisted beyond the current request if you store tmpVar somewhere. If you're using that code in a crerateObject method, return tmpVar will pass that instance of TestClass into the Data Object.
I go back and forth on pure Managed Beans vs. Data Object. I was using a lot of Data Objects for a while but then ran into some issue with the JSF lifecycle I think that I just couldn't make work. Not sure if a repeat or custom control was involved. So I pretty much have gone back and given up on them for now.
Other then that problem I had I'm not sure there's a ton of difference. I think dataObject can tend to be a little more confusion. Since you can set it on an XPage - but you can change the scope of it to session or application I believe. But if you do then that seems messier and hard to find then making the bean in the faces-config.
I'm not sure about the saveObject part of your question.
You never want to put a pure domino object inside a bean, or scoped variable because they are not serializable and will be tossed by the garbage collector at some point that will likely be most inconvenient to you.
if you just do "var tmpVar = new package.TestClass()" then yeah that will get killed pretty quick because of limited life of that variable. if you want to create an object that way and keep it around longer put it in a true scope: viewScope.put("myObject", tmpVar);
I have a video where I tried to give examples of I think 4 ways to use java Objects. In the blog posting are some really good comments by Tim Tripcony which might give you further information.
http://www.notesin9.com/2013/08/01/notesin9-122-working-with-java-objects-in-xpages/
I am using the IBM Social Business Toolkit. I have defined a connection for my Notes app via endpoints in the faces-config xml file. I wonder how I can access this file pro grammatically since I could not find a service that returns me the base url of IBM Connections.
It's useful to remember that an endpoint definition is really just creating a managed bean. The managed bean has a variable name you refer to it - the managed-bean-name property. You can access this directly from SSJS or via ExtLibUtil.resolveVariable() in Java. The definition also tells you the Java class that's being used, e.g. com.ibm.sbt.services.endpoints.ConnectionsBasicEndpoint. That really gives you all the information you need to get or set the properties.
So from SSJS you can just cast it to the class name, e.g.
var myService:com.ibm.sbt.services.endpoints.ConnectionsBasicEndpoint = connections
So the bit after the colon will be the managed-bean-class value and the bit after the equals sign will be the managed-bean-name. In Java, you can use
ConnectionsBasicEndpoint myService = (ConnectionsBasicEndpoint) ExtLibUtil.resolveVariable(ExtLibUtil.getXspContext().getFacesContext(), "connections");
You'll then have access to all the methods of the class, so you should be able to retrieve what you need.
The properties are part of the Java class, who are referred to in the Faces-Config.xml. So get the class by his fully qualified name or by bean name and set or get the properties
I think the best route will most likely be what Paul is suggesting: resolve the variable by its name and use the getters to get the effective properties that way.
Sven's suggestion is a good one to keep in mind for other situations. By accessing the faces-config.xml file as a resource, you could load it into an XML parser and find the values using XPath. I'm doing much that sort of technique in the next version of the OpenNTF Domino API, which will have a set of methods for manipulating the Faces config. However, one key aspect there is that reading the XML file directly will just get you the string values, which may be EL expressions, whereas going the resolveVariable route will get you the real current properties.
Ok I know scope questions come up all the time but I'm interested in a slightly different approach to the solution. The #ViewScope is a fantastic bridge between the #RequestScope and the #SessionScope.
However there is still a common use case (at least for me) where I really don't want to use #SessionScope but I need the data over a couple of views. A really simple case is when I have multiple datatables chained together each one depending on previous selections.
It's perfectly possible to use <f:paramView> and pass a single or even a couple of pieces of data as params in the address and then retrieve everything from the database again. I am more interested in finding a way of creating a 'snapshot' of the beans state / variables, creating the new #ViewScope and then 'restoring' the 'snapshot state' to the new bean.
Does such a thing exist? Ideas? Opinions?
I don't know if this is the 'accepted solution' but I've implemented an idea that works for me. (Feedback appreciated!)
So I have created a #SessionScoped class with a couple of static maps:
private static Map<String, Object> objectVariableMap;
// Getters, setters and methods etc. are omitted for simplicity
The idea being that I have specified a map that accepts a String as the key and an Object as the value. I've specifically not set the type of object to allow me to store any type of object in there. The caveat is that you need to be sure of the type of object when retrieving it so you can cast it back into its original type.
Now comes the time to set the data from the first #ViewScoped. I generate a random UUID (or what ever you want) as the Map key and then set the value to the object I'm working with (ie. this, or indeed any other objects you might want to pass to the next view). Save the key, value into the map and set the URL param to the key.
I'm never keen on passing data like user id's etc. in URL params (even when its encrypted). This idea has the added benefit of offering disposable URL values that have a specifiable life span.
On the receiving end (ie. The new #ViewScoped bean, or any other scope for that matter) you read in the URL param (the map key) using <f:paramView> and then use a preRenderView event to retrieve and set the Object where working with.
At this point you can choose to remove the key pair from the Map and invalidate the ability to retrieve that object or you can keep keep the key pair for a longer duration by simply updating the object if there are any changes.
UPDATE: Conceptually this has been really successful (for me at least). I've created a handfull of useful methods and classes surrounding the concept to make it more universal. If anybody wants more specific instructions or I might even create a small library if anybody wants.
You can use the CDI "Conversation Scope" for this. This is narrower than the session scope but wider than the view scope.
If the pages between which you pass parameters are a unit, you can also make them a flow in JSF 2.2 and use the flow scope.
Projects like CODI offer various other scopes that can be used between pages.
It seems controllerDidChangeContent: is being called as soon as I create a new managed object in my context. The documentation seems to suggest this method is called only once you save: the context.
This "bug" if it is one, is causing my application to crash because as part of my table view cell, I need to load other managed objects that don't exist at the time of creating the main managed object.
Someone seems to have spotted this too, please check out the following link and I would love to hear your opinions on this: http://openradar.appspot.com/10207615
More information
Although the link I added to this post showcases an example using two NSManagedObjectContext, my application is using one context, but the controllerDidChangeContent: is being messaged none the less as soon as an object is created in the one and only context, and controllerDidChangeContent: is being called a second time when I save: this context. It is to my understanding that this method should only be messaged when the context is saved.
The solution is to avoid dealing with more than one managedObjectContext. If your cell needs to load other managed objects, it should still use the same managed object context as the main managed object.
I have yet to see a use case where it is absolutely unavoidable to use more than one managed object context referring to the same model active at the same time.