I am creating a custom CDI scope and am using the BeanManager to get an injection of my NavigationHandler custom class. But the beans it returns are quite strange.
So I use the BeanManager that way :
public class ScreenContext implements Context
{
private NavigationHandler getNavigationHandler()
{
final Set<Bean<?>> beans = m_beanManager.getBeans(NavigationHandler.class);
final Bean<?> bean = m_beanManager.resolve(beans);
NavigationHandler reference =
(NavigationHandler) m_beanManager.getReference(bean, NavigationHandler.class,
m_beanManager.createCreationalContext(bean));
System.out.println("Found "+reference+" (hash="+reference.hashCode()+")");
return reference;
}
...
}
I expect, when I use my project using two different browsers, to get two different NavigationHandler, which are defined that way :
#Named
#WindowScoped
public class NavigationHandler
implements Serializable, INavigationHandlerController
But my debugger returns true when I test reference1==reference2. I also get strange hash codes :
Found NavigationHandler#593e785f (hash=1261587818)
Found NavigationHandler#b6d51bd (hash=1261587818)
I don't understand why the hashes used in the toString() are different, but the hash used in hashCode() are the same.
I think I figured out the reason for these two linked problems, that was a tricky one !
m_beanManager.getReference(..) does not return the NavigationHandler instance, but a proxy which is supposed to select and act as the correct NavigationHandler among the existing ones in the scope's context.
Link to understand the concept of Proxy/Context/BeanManager: https://developer.jboss.org/blogs/stuartdouglas/2010/10/12/weld-cdi-and-proxies
So my getNavigationHandler() method is not suited for the work : my pool which calls this method will hold NavigationHandler proxies instead of NavigationHandlers. Because my pool is not an #Injected field, the proxy will not get automatically updated by CDI, hence the reference returned is always the one from the last context actively used by a proxy.
For the same reason in this output:
Found NavigationHandler#593e785f (hash=1261587818)
Found NavigationHandler#b6d51bd (hash=1261587818)
In one case I get the hash of the NavigationHandler instance, and in the other case I get the hash of the NavigationHandler's proxy. Yet I don't know which one is which. I am willing to believe the proxy's toString() is used, as beanManager.getReference(..) is supposed to serve a new proxy each time, and the hashCode is supposed to be practically unique for object each instances.
Link that says every instance's hashcode is unique hashcode and cannot change over time: http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#hashCode%28%29
So the correct way to implement getNavigationHandler() is:
private getNavigationHandlergetgetNavigationHandler()
{
final Set<Bean<?>> beans = m_beanManager.getBeans(getNavigationHandler.class);
final Bean<?> bean = m_beanManager.resolve(beans);
/* Works : pure reference (not proxied) */
Class<? extends Annotation> scopeType = bean.getScope();
Context context = m_beanManager.getContext(scopeType);
CreationalContext<?> creationalContext = m_beanManager.createCreationalContext(bean);
// Casts below are necessary since inheritence does not work for templates
getNavigationHandler reference =
context.get((Bean<NavigationHandler>) bean, (CreationalContext<NavigationHandler>) creationalContext);
return reference;
}
Link that explains the difference between beanManager.getReference(..) and beanManager.getContext(..).get(..): Canonical way to obtain CDI managed bean instance: BeanManager#getReference() vs Context#get()
Related
Another question appeared during my migration from an E3 application to a pure E4.
I got a Structure using inheritance as in the following pic.
There I have an invocation sequence going from the AbstractRootEditor to the FormRootEditor to the SashCompositeSubView to the TableSubView.
There I want to use my EMenuService, but it is null due to it can´t be injected.
The AbstractRootEditor is the only class connected to the Application Model (as a MPart created out of an MPartDescriptor).
I´d like to inject the EMenuService anyway in the AbstractSubView, otherwise I would´ve the need to carry the Service through all of my classes. But I don´t have an IEclipseContext there, due to my AbstractSubView is not connected with Application Model (Do I ?).
I there any chance to get the service injected in the AvstractSubView?
EDIT:
I noticed that injecting this in my AbstractSubView isn´t possible (?), so I´m trying to get it into my TableSubView.
After gregs comment i want to show some code:
in the AbstractRootEditor:
#PostConstruct
public final void createPartControl(Composite parent, #Active MPart mPart) {
...
ContextInjectionFactory.make(TableSubView.class, mPart.getContext());
First I got an Exception, saying that my TableSubView.class got an invalid constructor, so now the Constructor there is:
public TableSubView() {
this.tableInputController=null;
}
as well as my Field-Injection:
#Inject EMenuService eMenuService
This is kind of not working, eMenuService is still null
If you create your objects using ContextInjectionFactory they will be injected. Use:
MyClass myClass = ContextInjectionFactory.make(MyClass.class, context);
where context is an IEclipseContext (so you have to do this for every class starting from one that is injected by Eclipse).
There is also a seconds version of ContextInjectionFactory.make which lets you provide two contexts the second one being a temporary context which can contain additional values.
Using the Null Analysis of Eclipse:
It it possible to define other methods as initializing methods than Constructors?
I have a class like this:
public class Foo {
#NonNull
private Object fooObject;
public Foo() {
super();
}
public void onCreate() {
fooObject = //Something which is not available in the Constructor;
}
Here i get the warning that the NonNull field may has not been initialized. Is there any possibility to kind of declare the init-method as an initalizing one?
I could use #SuppressWarnings("null") for the constructor. But then I ignore all fields, which may instanciated somewhere.
Second chance i see is to make fooObject as #Nullable - but then i need check for null each time i use fooObject.
So is there any better solution?
Null-checking object initialization beyond the constructor is inherently difficult. Several sophisticated approaches exist, all of which require additional annotations.
In your example it seems to be near-impossible, to prove to the compiler, that onCreate() is always called before accessing the field.
A weaker solution has been proposed: #LazyNonNull, an annotation to be used on fields that are initially null, but once initialized can never go back to null. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=414237
Obviously, a static factory method, that gathers all necessary values before invoking a constructor (with arguments) would be a lot easier to get right.
ConfigProperty.idPropertyMap is filled on the server side. (verified via log output)
Accessing it on the client side shows it's empty. :-( (verified via log output)
Is this some default behaviour? (I don't think so)
Is the problem maybe related to the inner class ConfigProperty.IdPropertyMap, java.util.HashMap usage, serialization or some field access modifier issue?
Thanks for your help
// the transfer object
public class ConfigProperty implements IsSerializable, Comparable {
...
static public class IdPropertyMap extends HashMap
implements IsSerializable
{
...
}
protected static IdPropertyMap idPropertyMap = new IdPropertyMap();
...
}
// the server service
public class ManagerServiceImpl extends RemoteServiceServlet implements
ManagerService
{
...
public IdPropertyMap getConfigProps(String timeToken)
throws ConfiguratorException
{
...
}
}
added from below after some good answers (thanks!):
answer bottom line: static field sync is not implemented/supported currently. someone/me would have to file a feature request
just my perspective (an fallen-in-love newby to GWT :-)):
I understand pretty good (not perfect! ;-)) the possible implications of "global" variable syncing (a dependency graph or usage of annotations could be useful).
But from a new (otherwise experienced Java EE/web) user it looks like this:
you create some myapp.shared.dto.MyClass class (dto = data transfer objects)
you add some static fields in it that just represent collections of those objects (and maybe some other DTOs)
you can also do this on the client side and all the other static methods work as well
only thing not working is synchronization (which is not sooo bad in the first place)
BUT: some provided annotation, let's say #Transfer static Collection<MyClass> myObjList; would be handy, since I seem to know the impact and benefits that this would bring.
In my case it's rather simple since the client is more static, but would like to have this data without explicitely implementing it if the GWT framework could do it.
static variables are purely class variable It has nothing to do with individual instances. serialization applies only to object.
So ,your are getting always empty a ConfigProperty.idPropertyMap
The idea of RPC is not that you can act as though the client and the server are exactly the same JVM, but that they can share the objects that you pass over the wire. To send a static field over the wire, from the server to the client, the object stored in that field must be returned from the RPC method.
Static properties are not serialized and sent over the wire, because they do not belong to a single object, but to the class itself.
public class MyData implements Serializable {
protected String name;//sent over the wire, each MyData has its own name
protected String key;
protected static String masterKey;//All objects on the server or client
// share this, it cannot be sent over RPC. Instead, another RPC method
// could access it
}
Note, however, that it will only be that one instance which will be shared - if something else on the server changes that field, all clients which have asked for a copy will need to be updated
I am using version 4 of MVVM Light for Windows 8; it includes SimpleIOC. In various examples I sometimes see code to request an object based on SimpleIoc... and sometimes it is based on ServiceLocator...
Examples include:
userToken = SimpleIoc.Default.GetInstance();
mainVM = ServiceLocator.Current.GetInstance();
What is the difference between using SimpleIoc.Default.GetInstance and ServiceLocator.Current.GetInstance?
If there is no difference, does ServiceLocator just let me to have an option to change my mind about what IOC library I want to use? Does ServiceLocator just provide an additional layer of abstraction that is irrelevant if I am satified with SimpleIoc; or, does ServiceLocator perform some other useful magic that is not obvious to we IOC novices?
Thanks for the insight!
In your ViewModelLocator class you probably have the following line of code:
public ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc implements the IServiceLocator interface, which means that the ServiceLocator will use it as a DI source when invoked.
Edit:
OK, people want the "full fat and don't spare the cream" answer. Here we go!
ServiceLocator is basically a shell. The code for Service locator is:
public static class ServiceLocator
{
private static ServiceLocatorProvider currentProvider;
public static IServiceLocator Current
{
get
{
return ServiceLocator.currentProvider();
}
}
public static void SetLocatorProvider(ServiceLocatorProvider newProvider)
{
ServiceLocator.currentProvider = newProvider;
}
}
Yup, that's it.
What's ServiceLocatorProvider? It's a delegate that returns an object that implements IServiceLocator.
SimpleIoc Implements IServiceLocator. So when we do:
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
We put our SimpleIoc object into the ServiceLocator. You can use either of these now because whether you call ServiceLocator.Current or SimpleIoc.Default you're returning the same object instance.
So, is there any difference between
userToken = SimpleIoc.Default.GetInstance();
mainVM = ServiceLocator.Current.GetInstance();
?
Nope. None. Both are singletons exposing a static property that is an implementation of IServiceLocator. As mentioned above, you're returning the same instance of object that implements IServiceLocator regardless of which you call.
The only reason why you might want to user ServiceLocator.Current.GetInstance() rather than SimpleIoc.Default.GetInstance() is that at some point in the future you may change DI containers and, if you use ServiceLocator, you won't have to change your code.
Based on Mr. Bugnion's article on MSDN (in the section, "Various Ways to Register a Class"), I am presuming interchangeability of IoC providers is the one and only reason for using ServiceLocator.
As #FasterSolutions stated, SimpleIoc implements IServiceLocator, so I suspect the opposite to your statement about abstraction layers is true. I think you should use ServiceLocator, but this is without empirical evidence; maybe someone can prove me wrong (?)
I'm trying to wrap my mind around RequestFactory, but I'm having some problems. I have an entityproxy that has a property which is a valueproxy of an immutable type (joda-time LocalDate), and I'm having problems using this entityproxy in any calls to the server.
I've made the property read-only by only including a getter for the property in the entityproxy, and only including getters for the primitive properties in the valueproxy.
However, as far as I can tell, If I use an entityproxy as an argument in a call to a service method, any referenced valueproxy is automatically marked as edited and all its properties are included in the delta?
This in turn causes ReflectiveServiceLayer to throw an exception about a missing setter on LocalDate.
I've been toying with the idea of implementing a ServiceLayerDecorator which overrides "setProperty" to get around this, but I'm not sure if that's a good solution. Is there any "proper" way to fix this? Ideally, I'd like AbstractRequestContext not to include immutable properties in calls to the server.
I'm using GWT 2.3
edit: I created a workaround like this, but I'm still unsure of whether this is the correct approach:
public class ImmutablePropertyFixServiceLayer extends ServiceLayerDecorator {
#Override
public void setProperty(Object domainObject, String property, Class<?> expectedType, Object value) {
Method setter = getTop().getSetter(domainObject.getClass(), property);
if (setter != null) {
super.setProperty(domainObject, property, expectedType, value);
} else {
//System.out.println(domainObject.getClass().getName() + "." + property + " doesn't have a setter");
}
}
}
EntityProxy objects have some way they can be easily retreived on the server, so when sending an object back to the server, just the ID is required. ValueProxy objects on the other hand can only be sent as the combination of all of their sub-values. When sending an immutable value back to the server, the server code doesn't know how to turn a proxy back into a server-side value.
I'd be concerned with your solution that you might not be correctly getting the same date on the server as was sent from the client.