I have the following code :
public interface CreatorFactory<E extends Vehicle> {
public VehicleType<E> getVehicle();
public boolean supports(String game);
}
public abstract AbstractVehicleFactory<E extends Vehicle> implements CreatorFactory {
public VehicleType<E> getVehicle() {
// do some generic init
getVehicle();
}
public abstract getVehicle();
public abstract boolean supports(String game);
}
and i have multiple factories, for car, truck..etc..
#Component
public CarFactory extends AbstractVehicleFactory<Car> {
/// implemented methods
}
#Component
public TruckFactory extends AbstractVehicleFactory<Truck> {
/// implemented methods
}
What I would like to do is pull the implemented factories into a seperate class as a list, but im not sure how generics works in this case... I know in spring you can get all beans of a specific type... would this still work?...
With erasure, i guess the generic types would be removed .. ??
Firstly, I think there is maybe no need to get a list of beans. And you just want get the exact bean which has declared with generics type.
In BeanFactory interface in Spring framework, there is a method to use for your requirement:
public interface BeanFactory {
/**
* Return the bean instance that uniquely matches the given object type, if any.
* #param requiredType type the bean must match; can be an interface or superclass.
* {#code null} is disallowed.
* <p>This method goes into {#link ListableBeanFactory} by-type lookup territory
* but may also be translated into a conventional by-name lookup based on the name
* of the given type. For more extensive retrieval operations across sets of beans,
* use {#link ListableBeanFactory} and/or {#link BeanFactoryUtils}.
* #return an instance of the single bean matching the required type
* #throws NoSuchBeanDefinitionException if there is not exactly one matching bean found
* #since 3.0
* #see ListableBeanFactory
*/
<T> T getBean(Class<T> requiredType) throws BeansException;
}
You can use code like:
Car carFactory = applicationContext.getBean( CarFactory.class );
Trunk trunkFactory = applicationContext.getBean( TrunkFactory.class );
or just see #Qualifier annotation for injection automaticly.
#Component("carFactory")
public CarFactory extends AbstractVehicleFactory<Car> {
/// implemented methods
}
#Component("truckFactory ")
public TruckFactory extends AbstractVehicleFactory<Truck> {
/// implemented methods
}
In client side code:
#Qualifier("carFactory")
#Autowired
private CarFactory carFactory ;
#Qualifier("truckFactory")
#Autowired
private TruckFactory TruckFactory;
Looks like you need:
#Autowired
List<AbstractVehicleFactory> abstractVehicleFactories;
Related
I have code which uses AssistedInject to create factories of my classes. Now what I want to do is create a number of objects, each of which gets injected with a different item of a collection (reverse Multibinding one could say).
My approach is to use a custom Scope which contains the Iterator to provide the Items, but I am doing something wrong:
IterationScope.java:
public class IterationScope implements Scope {
private Iterator<?> iterator;
public IterationScope() {
}
/**
* provide scoped Items
* #param key - the key for the requested item
* #param unscoped - the unscoped provider
* #param <T> - the type of the requested object
* #return - the requested provider
*/
#SuppressWarnings("unchecked")
#Override
public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) {
return Providers.<T>of((T)iterator.next());
}
public void enterScope(Iterator<?> iterator) {
this.iterator = iterator;
}
}
IterationScoped.java:
#Target({ FIELD, PARAMETER })
#Retention(RUNTIME)
#ScopeAnnotation #BindingAnnotation
public #interface IterationScoped {
}
In the module:
IterationScope itScope = new IterationScope();
bindScope(IterationScoped.class, itScope);
bind(IterationScope.class).toInstance(itScope);
bind(ImplementationDataType.class).annotatedWith(IterationScoped.class).toProvider(Providers.of(null)).in(itScope);
/* do AssistedInject stuff */
I try to get the value like this:
#Inject #IterationScoped ImplementationDataTypedataType
And set the scope like this:
#Inject private IterationScope iterationScope;
[...]
iterationScope.enterScope(someCollection.iterator);
for (ImplementationDataType message: someCollection){
generatorChain.addNextFileGenerator(generatorFactory.create(param1,false));
}
The problem I have is that already when creating the factories, I get a NullPointerException in IteratorScope.scope because no Iterator is set.
java.lang.NullPointerException
at com.conti.xcit.utilities.guice.IterationScope.scope(IterationScope.java:45)
at com.google.inject.internal.Scoping.scope(Scoping.java:240)
at com.google.inject.internal.BindingProcessor$1.visit(BindingProcessor.java:104)
at com.google.inject.internal.BindingProcessor$1.visit(BindingProcessor.java:68)
at com.google.inject.internal.ProviderInstanceBindingImpl.acceptTargetVisitor(ProviderInstanceBindingImpl.java:62)
at com.google.inject.internal.BindingProcessor.visit(BindingProcessor.java:68)
at com.google.inject.internal.BindingProcessor.visit(BindingProcessor.java:42)
at com.google.inject.internal.BindingImpl.acceptVisitor(BindingImpl.java:93)
at com.google.inject.internal.AbstractProcessor.process(AbstractProcessor.java:55)
at com.google.inject.internal.InjectorShell$Builder.build(InjectorShell.java:177)
at com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:103)
at com.google.inject.internal.InjectorImpl.createChildInjector(InjectorImpl.java:217)
at com.google.inject.internal.InjectorImpl.createChildInjector(InjectorImpl.java:224)
at [... where I inject the Factory ... ]
My expectation would have been that the factory only tries to find the scoped provider when I actually request an object, not at creation of the factory. Is there any way to get around this? I have an ugly idea involving a scoped provider with an incrementing counter in order to select the right item of the collection, but I would like a cleaner approach.
Let's say that there's class A that's constructor looks something like that:
public A(#Assited long id, #Assisten String name, ServiceA serviceA, ServiceB serviceB)
And there's AFactory:
public interface AFactory{
A create(long id, String name);
}
So to create an instance of A I obviously need to do something like that:
injector = Guice.createInjector(new MyModule());
AFactory af = injector.getInstance(AFactory .class);
A a = AFactory.create(100, "mike");
BUT,
Let's say I have other classes: Class B, Class C and Class D that has a member with type A, for example(with field injection but can be ctor also):
public class B{
#Inject
A a;
}
And I want that the same instance of A will be injected to those classes.
But still have the option to inject another instance of A to other classes (let's say Class E and F).
What is the correct way of doing that?
I just can't think of a clean way to do that.
You could structure your module to use Providers (I'm using #Provides methods below, but you can use full Provider classes or instances if you'd like), and mark the consistent A as #Singleton. If you want two bindings of A (consistent and inconsistent), at least one of them should be marked with a binding annotation; I'm using #Named here out of convenience, but you can use any binding annotation as listed in the docs.
public class AModule extends AbstractModule {
#Override public void configure() {
// Install your AFactory module. Here, injections for AFactory should succeed.
install(new FactoryModuleBuilder().build(AFactory.class));
}
/**
* Provides a singleton #Named("consistent") A.
* Inject #Named("consistent") A into B, C, and D; Guice will cache the instance.
*/
#Provides #Singleton #Named("consistent")
A provideConsistentA(AFactory factory) {
return factory.create(100, "mike");
}
/**
* Provides an unscoped A.
* Inject A without an annotation into E and F; each instance will be separate.
*/
#Provides #Singleton A provideUnscopedA(AFactory factory) {
return factory.create(200, "jeff");
}
}
I would like to use goolge/guice inject a value based on a class i provide with the annotation.
AutoConfig annotation
#BindingAnnotation
#Retention(RetentionPolicy.RUNTIME)
#Target({ ElementType.PARAMETER, ElementType.FIELD })
public #interface AutoConfig {
// default null not possible
Class<? extends Provider<? extends ConfigLoader<?>>> provider() default XMLAutoConfigProvider.class;
}
This is my annotation which allows configuring the type of config, that should be used for the annotated fields.
Usecase:
#AutoConfig()
ConfigLoader<?> defaultConfig;
#AutoConfig(provider = JsonConfigProvider)
ConfigLoader<?> jsonConfig;
I want to have two configs, one default/xml one and a json one. They will probably never occur in the same class at the same time. But i don't know when the one or the other is used. I used the approach with a class because they are provided by some dependencies/libs and this annotation will be used for some (plugable) submodules.
MyGuiceModule
public class MyGuiceModule extends AbstractModule {
#Override
protected void configure() {
bind(new TypeLiteral<ConfigLoader<?>>() {})
.annotatedWith(AutoConfig.class)
.toProvider(autoConfig.provider());
}
}
This the critical part, i just cannot imagine how to implement it.
So basically i just want to use the provider class specified in the annotation.
Its not necessary to use the provider class here too. Because autoConfig.provider().newInstance() is basically all i need. (I need to use a setter on the new instance but thats all i want to do at this place)
To sum it up all i really want to do is push the annotation (or its values to the provider) either using the get(AutoConfig autoConfig) or in the constructor.
Currently i only use the constructor to inject the configFile value i want to set on the newly generated config instance.
If you know that #AutoConfig(provider = JsonConfigProvider) ConfigLoader<?> jsonConfig is going to return you exactly the results of jsonConfigProvider.get(), and JsonConfigProvider obviously has a public parameterless constructor for newInstance to work, why wouldn't you just ask for a JsonConfigProvider in the first place?
Fundamentally Guice is just a Map<Key, Provider> with fancy wrapping. The bad news is that this makes variable bindings like "bind Foo<T> for all T" impossible to express concisely, and that includes your "bind #Annotation(T) Foo for all T". The good news is that you still have two options.
Bind each provider separately
Though you can't inspect annotations during provision (or tell Guice to do so for you), Guice will compare annotations using their equals methods if you bind an annotation instance rather than an annotation class (the way you would with Names.named("some-name")). This means that you can bind a ConfigLoader<?> with each expected annotation in a Module. Of course, this also means you'll have to have a list of possible ConfigLoader Providers available at configuration time, but they have to be compile-time constants anyway if you're using them as annotation parameters.
This solution works with constructor injection as well, but for fields you'll need both #Inject and #AutoConfig(...), and AutoConfig will need to keep its #BindingAnnotation meta-annotation.
To do this, you're going to have to write an implementation of your annotation, the way Guice does with NamedImpl. Note that the implementations of equals and hashCode must match the ones Java provides in java.lang.Annotation. Then it's just a matter of (redundantly) binding like this:
for(Class<ConfigLoader<?>> clazz : loaders) {
bind(ConfigLoader.class).annotatedWith(new AutoConfigImpl(clazz))
.toProvider(clazz);
}
The definition of equals is up to you, which means you can (and should) bind #AutoConfig(ConfigEnum.JSON) and keep the Guice bindings in your modules rather than specifying your requested implementation all over your codebase.
Use custom injections
You can also use custom injections to search your injected types for custom annotations like #AutoConfig. At this point, you'd be using Guice as a platform to interpret #AutoConfig instead of #Inject, which means that constructor injection won't work but that you can control your injection based on the injected instance, field name, field annotation, annotation parameters, or any combination thereof. If you choose this style, you can drop #BindingAnnotation from AutoConfig.
Use the example in the wiki article linked above as your template, but at minimum you'll need to:
Use bindListener on Binder or AbstractModule to match types that need this custom injection.
In the TypeListener you bind, search injected types for #AutoConfig-annotated fields, and if they have any matching methods then bind those matching methods to a MembersInjector or InjectionListener. You'll probably want to tease the class literal out of the annotation instance here, and pass in the Field and Class as constructor arguments to the MembersInjector/InjectionListener.
In the MembersInjector or InjectionListener you write, instantiate the provider and set the field to the instance the provider provides.
This is a very powerful feature, which would futher allow you to--for instance--automatically provide the configuration based on which instance you're injecting into or based on the name of the field. However, use it carefully and document it heavily, because it may be counter-intuitive to your coworkers that Guice is providing for an annotation other than #Inject. Also bear in mind that this won't work for constructor injection, so refactoring from field injection to constructor injection will cause Guice to complain that it's missing a required binding to instantiate the class.
I had a similar problem. I wanted to use a custom annotation that receives a enum param to choose the implementation. After a lot of research, debug and testing, I came to the following solution:
//enum to define authentication types
public enum AuthType {
Ldap, Saml
}
//custom annotation to be used in injection
#Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
#BindingAnnotation
public #interface Auth {
AuthType value();
}
//defintion of authenticator
public interface Authenticator {
public void doSomehting();
}
//Authenticator implementations
public class LdapAuthenticator implements Authenticator {
#Override
public void doSomehting() {
// doing ldap stuff
}
}
public class SamlAuthenticator implements Authenticator {
#Override
public void doSomehting() {
// doing saml stuff
}
}
public class MyModule extends AbstractModule {
// annotate fields to bind to implementations
private #Auth(AuthType.Ldap) Authenticator ldap;
private #Auth(AuthType.Saml) Authenticator saml;
#Override
protected void configure() {
//bind the implementation to the annotation from field
bindAnnotated("ldap", LdapAuthenticator.class);
bindAnnotated("saml", SamlAuthenticator.class);
}
private void bindAnnotated(String fieldName, Class<? extends Authenticator> implementation) {
try {
//get the annotation from fields, then bind it to implementation
Annotation ann = MyModule.class.getDeclaredField(fieldName).getAnnotation(Auth.class);
bind(Authenticator.class).annotatedWith(ann).to(implementation);
} catch (NoSuchFieldException | SecurityException e) {
throw new RuntimeException(e);
}
}
}
//usage: add #Auth(<AuthType>) to the dependency
public class ClientClass {
private Authenticator authenticator;
#Inject
public ClientClass(#Auth(AuthType.Ldap) Authenticator authenticator) {
this.authenticator = authenticator;
}
}
Check the documentation of Binder
I tested the Jeff Bowman solution, but it apparently works only binding to providers
As a BindingAnnotations#binding-annotations-with-attributes states equals() and hashCode() should be properly implemented. So given that there is MyAnnotation
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.FIELD, ElementType.PARAMETER})
public #interface MyAnnotation {
SomeEnum value() default SomeEnum.A;
}
which is used to specify SomeInterface implementation(SomeDefault and SomeOther), SomeModule class could look like
public class SomeModule extends AbstractModule {
#Override
protected void configure() {
bind(Key.get(SomeInterface.class, createAnnotationClass(A))).to(SomeDefault.class);
// more common binding expresion
bind(SomeInterface.class).annotatedWith(createAnnotationClass(B)).to(SomeDefault.class);
}
private Annotation createAnnotationClass(SomeEnum someEnum) {
return new MyAnnotation() {
#Override
public SomeEnum value() {
return someEnum;
}
#Override
public Class<? extends Annotation> annotationType() {
return MyAnnotation.class;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyAnnotationCl myAnnoCl = (MyAnnotationCl) o;
return A == myAnnoCl.getValue();
}
#Override
public int hashCode() {
// from java annotation documentation
return (127 * "value".hashCode()) ^ value().hashCode();
}
};
}
}
Then annotation could be used as follows:
public class DoSomethingWithSomething {
private final SomeInterface someImplementation;
#Inject
public DoSomethingWithSomething(
#MyAnnotation SomeInterface someDefault
// #MyAnnotation(A) SomeInterface someDefault
// #MyAnnotation(B) SomeInterface someOther
) {
this.someImplementation = someDefault;
}
}
Here goes a command object which needs to be populated from a Spring form
public class Person {
private String name;
private Integer age;
/**
* on-demand initialized
*/
private Address address;
// getter's and setter's
}
And Address
public class Address {
private String street;
// getter's and setter's
}
Now suppose the following MultiActionController
#Component
public class PersonController extends MultiActionController {
#Autowired
#Qualifier("personRepository")
private Repository<Person, Integer> personRepository;
/**
* mapped To /person/add
*/
public ModelAndView add(HttpServletRequest request, HttpServletResponse response, Person person) throws Exception {
personRepository.add(person);
return new ModelAndView("redirect:/home.htm");
}
}
Because Address attribute of Person needs to be initialized on-demand, i need to override newCommandObject to create an instance of Person to initiaze address property. Otherwise, i will get NullPointerException
#Component
public class PersonController extends MultiActionController {
/**
* code as shown above
*/
#Override
public Object newCommandObject(Class clazz) thorws Exception {
if(clazz.isAssignableFrom(Person.class)) {
Person person = new Person();
person.setAddress(new Address());
return person;
}
}
}
Ok, Expert Spring MVC and Web Flow says
Options for alternate object creation include pulling an instance from a BeanFactory or using method injection to transparently return a new instance.
First option
pulling an instance from a BeanFactory
can be written as
#Override
public Object newCommandObject(Class clazz) thorws Exception {
/**
* Will retrieve a prototype instance from ApplicationContext whose name matchs its clazz.getSimpleName()
*/
getApplicationContext().getBean(clazz.getSimpleName());
}
But what does he want to say by using method injection to transparently return a new instance ??? Can you show how i implement what he said ???
ATT: I know this funcionality can be filled by a SimpleFormController instead of MultiActionController. But it is shown just as an example, nothing else
I'm pretty sure he means using the lookup-method system as documented in chapter 3 of the spring reference manual
Only down side is that <lookup-method> requires a no arg method rather than the newCommandObject(Class) method of MultiActionController.
this can be solved with something like:
public abstract class PersonController extends MultiActionController {
/**
* code as shown above
*/
#Override
public Object newCommandObject(Class clazz) thorws Exception {
if(clazz.isAssignableFrom(Person.class)) {
return newPerson();
}
}
public abstract Person newPerson();
}
in the context file:
<bean id="personController" class="org.yourapp.PersonController">
<lookup-method name="newPerson" bean="personPrototype"/>
</bean>
The down side is that using this sort of thing is you are kinda stuck with configuring the controller bean via xml it's not possible (certainly in < 3) to do this with annotations.
GWT's serializer has limited java.io.Serializable support, but for security reasons there is a whitelist of types it supports. The documentation I've found, for example this FAQ entry says that any types you want to serialize "must be included in the serialization policy whitelist", and that the list is generated at compile time, but doesn't explain how the compiler decides what goes on the whitelist.
The generated list contains a number of types that are part of the standard library, such as java.lang.String and java.util.HashMap. I get an error when trying to serialize java.sql.Date, which implements the Serializable interface, but is not on the whitelist. How can I add this type to the list?
There's a workaround: define a new Dummy class with member fields of all the types that you want to be included in serialization. Then add a method to your RPC interface:
Dummy dummy(Dummy d);
The implementation is just this:
Dummy dummy(Dummy d) { return d; }
And the async interface will have this:
void dummy(Dummy d, AsyncCallback< Dummy> callback);
The GWT compiler will pick this up, and because the Dummy class references those types, it will include them in the white list.
Example Dummy class:
public class Dummy implements IsSerializable {
private java.sql.Date d;
}
Any specific types that you include in your service interface and any types that they reference will be automatically whitelisted, as long as they implement java.io.Serializable, eg:
public String getStringForDates(ArrayList<java.util.Date> dates);
Will result in ArrayList and Date both being included on the whitelist.
It gets trickier if you try and use java.lang.Object instead of specific types:
public Object getObjectForString(String str);
Because the compiler doesn't know what to whitelist. In that case if the objects are not referenced anywhere in your service interface, you have to mark them explicitly with the IsSerializable interface, otherwise it won't let you pass them through the RPC mechanism.
The whitelist is generated by the GWT compiler and contains all the entries that are designated by the IsSerializable marker interface.
To add a type to the list you just need to make sure that the class implements the IsSerializable interface.
Additionally for serialization to work correctly the class must have a default no arg constructor (constructor can be private if needed). Also if the class is an inner it must be marked as static.
IMHO the simpliest way to access whitelist programmatically is to create a class similar to this:
public class SerializableWhitelist implements IsSerializable {
String[] dummy1;
SomeOtherThingsIWishToSerialize dummy2;
}
Then include it in the .client package and reference from the RPC service (so it gets analyzed by the compiler).
I couldn't find a better way to enable tranfer of unparameterized maps, which is obviously what you sometimes need in order to create more generic services...
The whitelist is generated by the gwt compiler and contains all the entries that are designated by the IsSerializable marker interface.
To add a type to the list you just need to make sure that the class implements the IsSerializable interface.
-- Andrej
This is probably the easiest solution.
The only thing to remember with this is that all the classes that you want to serialize should have "public, no-argument" constructor, and (depending upon requirements) setter methods for the member fields.
to ensure the desired result delete all war/<app>/gwt/*.gwt.rpc
To anyone who will have the same question and doesn't find previous answers satisfactory...
I'm using GWT with GWTController, since I'm using Spring, which I modified as described in this message. The message explains how to modify GrailsRemoteServiceServlet, but GWTController calls RPC.decodeRequest() and RPC.encodeResponseForSuccess() in the same way.
This is the final version of GWTController I'm using:
/**
* Used to instantiate GWT server in Spring context.
*
* Original version from this tutorial.
*
* ...fixed to work as explained in this tutorial.
*
* ...and then fixed to use StandardSerializationPolicy as explained in
* this message to allow
* using Serializable instead of IsSerializable in model.
*/
public class GWTController extends RemoteServiceServlet implements Controller, ServletContextAware {
// Instance fields
private RemoteService remoteService;
private Class<? extends RemoteService> remoteServiceClass;
private ServletContext servletContext;
// Public methods
/**
* Call GWT's RemoteService doPost() method and return null.
*
* #param request
* The current HTTP request
* #param response
* The current HTTP response
* #return A ModelAndView to render, or null if handled directly
* #throws Exception
* In case of errors
*/
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
doPost(request, response);
return null; // response handled by GWT RPC over XmlHttpRequest
}
/**
* Process the RPC request encoded into the payload string and return a string that encodes either the method return
* or an exception thrown by it.
*
* #param payload
* The RPC payload
*/
public String processCall(String payload) throws SerializationException {
try {
RPCRequest rpcRequest = RPC.decodeRequest(payload, this.remoteServiceClass, this);
// delegate work to the spring injected service
return RPC.invokeAndEncodeResponse(this.remoteService, rpcRequest.getMethod(), rpcRequest.getParameters(), rpcRequest.getSerializationPolicy());
} catch (IncompatibleRemoteServiceException e) {
return RPC.encodeResponseForFailure(null, e);
}
}
/**
* Setter for Spring injection of the GWT RemoteService object.
*
* #param RemoteService
* The GWT RemoteService implementation that will be delegated to by the {#code GWTController}.
*/
public void setRemoteService(RemoteService remoteService) {
this.remoteService = remoteService;
this.remoteServiceClass = this.remoteService.getClass();
}
#Override
public ServletContext getServletContext() {
return servletContext;
}
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
}
I found that just putting it in the client package or using it in a dummy service interface was not sufficient as it seemed the system optimized it away.
I found it easiest to create a class that derived from one of the types already used in the service interface and stick it in the client package. Nothing else needed.
public class GWTSerializableTypes extends SomeTypeInServiceInterface implements IsSerializable {
Long l;
Double d;
private GWTSerializableTypes() {}
}
I had this problem but ended up tracing the problem back to a line of code in my Serializable object:
Logger.getLogger(this.getClass().getCanonicalName()).log(Level.INFO, "Foo");
There were no other complaints before the exception gets caught in:
#Override
protected void serialize(Object instance, String typeSignature)
throws SerializationException {
assert (instance != null);
Class<?> clazz = getClassForSerialization(instance);
try {
serializationPolicy.validateSerialize(clazz);
} catch (SerializationException e) {
throw new SerializationException(e.getMessage() + ": instance = " + instance);
}
serializeImpl(instance, clazz);
}
And the business end of the stack trace is:
com.google.gwt.user.client.rpc.SerializationException: Type 'net.your.class' was not included in the set of types which can be serialized by this SerializationPolicy or its Class object could not be loaded. For security purposes, this type will not be serialized.: instance = net.your.class#9c7edce
at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter.serialize(ServerSerializationStreamWriter.java:619)