I've read questions here in stackoverflow such as:
Anyway to #Autowire a bean that requires constructor arguments?
How to #Autowire bean with constructor
I've also read links provided in these questions such as 3.9.3 Fine-tuning annotation-based autowiring with qualifiers but nothing that I tried worked.
Here's my class:
public class UmbrellaRestClient implements UmbrellaClient {
private static final Logger LOGGER = LoggerFactory.getLogger(UmbrellaRestClient.class);
private static final Map<String, String> PARAMETROS_INFRA_UMBRELLA = ApplicationContextProvider.getApplicationContext().getBean(ParametrosInfraComponent.class)
.findByIdParametroLikeAsMap("%UMBRELLA%");
private final HttpConnectionRest conexaoHttp;
#Autowired
#Qualifier
private TemplateLoaderImpl templateLoader;
public UmbrellaRestClient(final String url) {
this.conexaoHttp = new HttpConnectionRest(UmbrellaRestClient.PARAMETROS_INFRA_UMBRELLA.get("UMBRELLA_HOST") + url, "POST", true);
}
/**
* {#inheritDoc}
*/
#Override
public String enviarNfe(final String cnpjFilial, final String idPedido, final BigDecimal valorGNRE, final String arquivoNfe) {
if (StringUtils.isBlank(arquivoNfe)) {
throw new ClientException("Arquivo de NF-e não carregado.");
}
final String usuario = StringUtils.defaultIfBlank(UmbrellaRestClient.PARAMETROS_INFRA_UMBRELLA.get("USUARIO_UMBRELLA"), "WS.INTEGRADOR");
Map<String, String> parametrosTemplate = new HashMap<>(6);
parametrosTemplate.put("usuario", usuario);
parametrosTemplate.put("senha", StringUtils.defaultIfBlank(UmbrellaRestClient.PARAMETROS_INFRA_UMBRELLA.get("SENHA_UMBRELLA"), "WS.INTEGRADOR"));
parametrosTemplate.put("valorGNRE", valorGNRE.toPlainString());
parametrosTemplate.put("idPedido", idPedido);
parametrosTemplate.put("cnpjFilial", cnpjFilial);
parametrosTemplate.put("arquivoNfe", arquivoNfe);
final String xmlRequisicao = ConverterUtils.retornarXMLNormalizado(this.templateLoader.preencherTemplate(TemplateType.ENVIO_XML_NFE, parametrosTemplate));
this.conexaoHttp.setXmlEnvio(xmlRequisicao);
UmbrellaRestClient.LOGGER.info("XML ENVIO #####################: {}", xmlRequisicao);
return this.conexaoHttp.enviarXML();
}
}
The field templateLoader does not get injected. I tested in other classes that have dependency injection and works. I guess this is happening because I have a constructor that depends on a parameter and this parameter is really passed by each class that needs to use it so I cannot use dependency injection to the parameter of the constructor in applicationContext for example.
What should I do to get field injected?
Using Rest APIs with Spring framework needs to be handled differently. Here is brief explanation.
Spring is a framework that maintains the lifecycle of the component beans and is fully responsible from bean creation to their destruction.
REST APIs are also responsible for maintaining the life cycle of the web services they create.
So, Spring and REST container are working independently to manage the components they have created effeciently.
In my recent project what I did to use both technologies, by creating a seperate class which implements Spring's ApplicationContextAware interface, and collect the beans in a HashMap. This resource can be accessed statically from REST contexts.
The weak point about this is we have to use beans.xml file and register the beans and in the class that implements ApplicationContextAware interface getting the beans by name etc.
The easiest way to create a Spring controlled bean is directly through the ApplicationContext:
#Autowired
private ApplicationContext context;
private UmbrellaRestClient getNewUmbrellaRestClient(String url) {
return context.getBean("umbrellaRestClient", new Object[]{url});
}
Basically this is a factory method. For this to work the UmbrellaRestClient must be declared a bean of scope prototype. As all beans that have a non default constructor must be of scope prototype.
In the case where the class is in a package that is component scanned, this will suffice:
#Service
#Scope("prototype")
public class UmbrellaRestClient implements UmbrellaClient {
...
Related
I have my JWT utils class:
#Component
public class JwtUtils {
private final String jwtSecret;
private final int jwtExpirationMs;
public JwtUtils(#Value("${app.jwtSecret}") String jwtSecret, #Value("${app.jwtExpirationMs}") String jwtExpirationMs)){
this.jwtSecret = jwtSecret;
this.jwtExpirationMs = jwtExpirationMs;
}
...
}
and inside my WebTokenConfig I need to initialize it for my AuthTokenFilter:
#Bean
public AuthTokenFilter authenticationJwtTokenFilter() {
return new AuthTokenFilter(new JwtUtils(..., ...), ...);
}
So basically, JwtUtils needs 2 parameters, but those parameters should be set from properties' context. How to handle the constructor's injection?
Plus, I'm trying to test JwtUtils class with a junit test with mockito.
Using #Autowired on fields (and not on constructor) and then instantiating the bean with new JwtUtils(), those parameters are not being init'd, staying null and 0 (even with #TestPropertySource, System.setProperties, ...). That's why I'm trying with constructor injection (which as I read is always the best option). This way I just have to pass the parameters through the new JwtUtils() and that's it.
But when done inside other beans (no test), it just makes no sense to me to pass them since they should be retrieved from context and not be passed.
I'm probably missing something.
I know similar questions have been asked so many times here before, but I am still confused by the mechanisms.
Here is my problem. There is a null pointer exception coming from the CategoryDAO object in the CategoryService.
#Service
public class CategoryService {
#Autowired
private CategoryDAO categoryDAO;
public List<Category> list(){
List<Category> categories = categoryDAO.list();
for (Category category : categories){
List<Record> rs = recordDAO.list(category.getID());
category.setRecordNumber(rs.size());
}
return categories;
}
public void add(String name){
Category newCategory = new Category();
newCategory.setName(name);
categoryDAO.add(newCategory);
}
}
#Repository
public class CategoryDAO {
#Autowired
private SqlSessionFactory sqlSessionFactory;
public int getTotal(){
SqlSession sqlSession = sqlSessionFactory.openSession();
List<Category> categories = sqlSession.selectList("category.selectAll");
return categories.size();
}
}
In this top rated post and this one, both of the top answers mentioned that The most preferable option is to let Spring autowire all of your beans.
Does it mean I have to also autowire the CategoryService in other classes once I need it? Which means I cannot use new operator to initialise a class if it contains autowired object?
If yes, could you please explain the reason behind it?
Thanks
UPDATE
Here is an example about using the autowired class CategoryService:
public class RecordListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
RecordPanel panel = RecordPanel.getInstance();
if (new CategoryService().list().size() == 0){
JOptionPane.showMessageDialog(panel, "NO category is recorded, set category first");
MainPanel.getInstance().getPanel().display(CategoryPanel.getInstance());
return;
}
}
The CategoryService is used in new CategoryService().list().size() == 0. If I autowire it as a property of this class here then this class will also need to be injected once I need it. I would like to avoid that so things could be easier. How can I achieve that?
Does it mean I have to also autowire the CategoryService in other classes once I need it?
Yes.
Which means I cannot use new operator to initialise a class if it contains autowired object?
Yes.
The #Autowire annotation enables you to use Dependency Injection. A technique (or good practice, actually) that makes it easy to change the implementations you use for your interfaces in your application. You define beans/component/services that will get injected whenever you use the #Autowire annotation over an attribute or a constructor parameter.
Instead of using new all over your code you just declare which concrete class should be used for an interface (or maybe the class itself) annotated with #Autowire.
Imagine you create an interface RemoteAccess and an implementation FtpRemoteAccess and then every time you need it you write RemoteAccess remoteAccess = new FtpRemoteAccess();
After a while you might end up with that line over several places. Now, if you need to change this to HttpRemoteAccess because you have this new, better alternative, you have to review all your code base. Instead, if you used dependency injection you would just change the bean (there is more than one way to do that using Spring).
For all this to work, Spring must be able to inject all the dependencies of a bean. If you create a bean, all its attributes must be injected too because Spring will create that object for you.
Clarification:
Inside your bean (namely, you classes that will be injected) you can create objects using new provided that makes sense and those object are not injected types. You are already doing that in CategoryService::add() and it is ok. Dependency injection doesn't mean you will not ever write new again. You will just avoid it for objects that will be managed by Spring dependency injection.
Then, there are other good practices that disencourage using new like the static factory method that recommend putting a static method in your class to build complete objects and letting the constructor to be private. But you don't need to apply all the patterns all the time.
UPDATE:
For your RecordListener class you have to add a CategoryService attribute and then be sure it is initialized. There are two options: you can convert RecordListener in a bean itself and have it autowired where you need that. This way Spring will construct a RecordListener object for injecting it and will also add any other bean that is needed (like CategoryService)
#Component
public class RecordListener implements ActionListener {
#Autowire
private CategoryService categoryService;
#Override
public void actionPerformed(ActionEvent e) {
RecordPanel panel = RecordPanel.getInstance();
if (categoryService.list().size() == 0) {
JOptionPane.showMessageDialog(panel, "NO category is recorded, set category first");
MainPanel.getInstance().getPanel().display(CategoryPanel.getInstance());
return;
}
}
}
The other option is you inject CategoryService in the class that is currently creating the RecordListener and then pass it as constructor argument. In that case RecordListener will not be a bean.
My current situation:
I want to inject the following class into my application:
public interface IConfigAccessor<T extends IConfig> {
...
}
ConfigAccessors are a proxy-objects, created dynamically at runtime. The creation of these object works as follows:
public class ConfigFactory implements IConfigFactory {
private final IConfigUpdater updater;
#Inject
public ConfigFactory(IConfigUpdater updater) {
this.updater = updater;
}
#Override
public <T extends IConfig> IConfigAccessor<T> register(final String configKey, final Class<T> configClass) {
ConfigCache<T> configCache = new ConfigCache<>(new SomeOtherThings(), configKey, configClass);
updater.register(configCache);
return new ConfigAccessor<>(configCache, configKey, configClass);
}
}
As you can see, to create these objects, I need to inject the ConfigUpdater and other depdencies. This means, that guice needs to be fully configured already.
To get the instance out of Guice, I use the following code:
IConfigFactory configClient = injector.getInstance(IConfigFactory.class);
IConfigAccessor<ConcreteConfig> accessor = configClient.register("key", ConcreteConfig.class)
How I want to inject them via Guice:
Currently, I can get the requried objects, but I have to manually pass them around in my application.
Instead, what I want to have is the following:
public class SomeClass {
#Inject
public SomeClass(#Config(configKey="key") IConfigAccessor<ConcreteConfig> accessor) {
// hurray!
}
}
What's the correct approach/technology to get this working?
After a lot of research, I'm feeling a bit lost on how to approach this topic. There are a lot of different things Guice offers, including simple Providers, custom Listeners which scan classes and identify custom annotations, FactoryModuleBuilders and more.
My problem is quite specific, and I'm not sure which of these things to use and how to get it working. I'm not even sure if this is even possible with Guice?
Edit: What I have so far
I have the following annotation which I want to use inside constructor paramters:
#Target({ ElementType.FIELD, ElementType.PARAMETER })
#Retention(RetentionPolicy.RUNTIME)
public #interface InjectConfig {
String configKey();
}
Inside the module, I can bind a provider to IConfigAccessor (with the above annotation) as such:
bind(IConfigAccessor.class).annotatedWith(InjectConfig.class)
.toProvider(new ConfigProvider<>());
However, there are two problems whith this:
The provider cannot provide IConfigAccessor. To create such an instance, the provider would need an IConfigUpdater, but since I use 'new' for the provider, I can't inject it.
Inside the provider, there is no way to find out about the configKey used in the Annotation.
Second approach:
Let's assume that I already know all configurations and configKeys I want to inject during startup. In this case, I could loop over all possible configKeys and have the following binding:
String configKey = "some key";
final Class<? extends IConfig> configClass =...;
bind(IConfigAccessor.class).annotatedWith(Names.named(configKey))
.toProvider(new ConfigProvider<>(configKey, configClass));
However, problem (1) still resides: The provider cannot get an IConfigUpdater instance.
The main problem here is that you cannot use the value of the annotation in the injection. There is another question which covers this part:
Guice inject based on annotation value
Instead of binding a provider instance, you should bind the provider class, and get the class by injecting a typeliteral.
That way, your config factory can look like that:
public class ConfigFactory<T extends IConfig> implements IConfigFactory {
#Inject private final IConfigUpdater updater;
#Inject private TypeLiteral<T> type;
#Override
public IConfigAccessor<T> register(final String configKey) {
Class<T> configClass = (Class<T>)type.getRawType();
ConfigCache<T> configCache = new ConfigCache<>(new SomeOtherThings(), configKey, configClass);
updater.register(configCache);
return new ConfigAccessor<>(configCache, configKey, configClass);
}
}
And then SomeClass:
public class SomeClass {
#Inject
public SomeClass(ConfigFactory<ConcreteConfig> accessor) {
ConcreteConfig config = accessor.register("key");
}
}
Since SomeClass needs to know "key" anyway, this is not too much a change information-wise. The downside is that the SomeClass API now gets a factory instead of the concrete config.
[EDIT]
And here is someone who actually did inject annotated values using custom injection.
I'd like to create a bean based on "which instance of which class the field belongs to (or even, just to which class this field belongs to). Something like:
#Configuration
#ComponentScan
public class MyConfiguration {
#Bean
SomeClass getTheRightInstance(SomeContext someContext) {
if(someContext.getinjectedFieldHostInstance.getId() == 7) {
return new SpecificSomeClassImplForId7();
} else {
return new SomeClass();
}
}
Bean is to be injected into following field:
public class A {
private int final id;
#Inject private SomeClass field;
int getId();
public A() {
id = SerialIdGenerator.getNextID();
}
}
Select bean injected into A's field based on A instance's id
public staitc void main(String[] args) {
A a1 = new A(); // has id '1', gets field injected with SimpleClass
A a2 = new A(); // has id '2', gets field injected with SimpleClass
...
A a7 = new A(); // gets field injected with SpecificSomeClassImplForId7
...
A last= new A(); // has id!=7, gets field injected with SimpleClass
}
The general idea is to have the decision as to which implementation to inject to which field in which class be defined in code.
Can I inject different bean instances to the same field of different instances of the same class? How can you configure it through code?
The bean you define is a Singleton, so its created at Context-Initialization before the app know that anyone might autowire the value. You must create the Bean as Prototype to request the instance on autowire only.
This is still not possible to get infos about the autowire-target. You can use *Aware-interfaces to get
very own unique Beanname
Beanfactory
ApplicationContext
But neither the target of the autowire nor the class of the target.
Notice that: if the autowire-field has been marked as #Lazy and the Bean's scope is Prototype you can elaborate the exact time the bean autowires using the bean's #PostConstruct.
I'm not sure why you want to do that but it seems like a bad idea.
Classes should never configure their behaviour around their caller, it leads to code that is tightly coupled and not very portable.
Instead, you should find out what makes those 2 fields different and refactor them to use 2 different interfaces (which may even have a common super interface in case of shared functionality). Then you can easily provide 2 different implementations for those interfaces. In your case you could also write a class that handles the specific case for id == 7 and the other cases (maybe via delegation) and use another way of configuring the instance either after or while injecting it into A.
I'm not aware of any possibility to do what you want directly.
Edit: After discussing a bit further in the comments and understanding more what you want to accomplish I think having one factory to create A instances would be best:
#Service
class AFactory {
#Autowired
private SpecificSomeClassImplForId7 specificSomeClassImplForId7;
#Autowired
private SomeClass someClass;
public A makeA() {
if(isSpecialA()) {
return new A(specificSomeClassImplForId7);
} else {
return new A(someClass);
}
}
Then you can use this factory in other Spring Beans in your Application to make As.
I want to reinject singleton-scoped dependencies into prototype Spring beans, after they have been deserialized.
Say I've got a Process bean, which depends on a Repository bean. The Repository bean is a scoped as a singleton, but the Process bean is prototype-scoped. Periodically I serialize the Process, and then later deserialize it.
class Process {
private Repository repository;
// getters, setters, etc.
}
I don't want to serialize and deserialize the Repository. Nor do I want to put "transient" on the member variable that holds a reference to it in Process, nor a reference to some kind of proxy, or anything other than a plain old member variable declared as a Repository.
What I think I want is for the Process to have its dependency filled with a serializable proxy that points (with a transient reference) to the Repository, and, upon deserialization, can find the Repository again. How could I customize Spring to do that?
I figure I could use a proxy to hold the dependency references, much like . I wish I could use that exact technique. But the proxy I've seen Spring generate isn't serializable, and the docs say that if I use it with a singleton bean, I'll get an exception.
I could use a custom scope, perhaps, on the singleton beans, that would always supply a proxy when asked for a custom-scoped bean. Is that a good idea? Other ideas?
I used this instead, without any proxy:
public class Process implements HttpSessionActivationListener {
...
#Override
public void sessionDidActivate(HttpSessionEvent e) {
ServletContext sc = e.getSession().getServletContext();
WebApplicationContext newContext = WebApplicationContextUtils
.getRequiredWebApplicationContext(sc);
newContext.getAutowireCapableBeanFactory().configureBean(this, beanName);
}
}
The example is for a web environment when the application server serializes the session, but it should work for any ApplicationContext.
Spring provides a solution for this problem.
Take a look at the spring documentation http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop.html#aop-atconfigurable.
7.8.1 Using AspectJ to dependency inject domain objects with Spring
...
The support is intended to be used for objects created outside
of the control of any container. Domain objects often fall into
this category because they are often created programmatically
using the new operator, or by an ORM tool as a result of a database query.
The trick is to use load time weaving. Just start the jvm with -javaagent:path/to/org.springframework.instrument-{version}.jar. This agent will recognize every object that is instantiated and if it is annotated with #Configurable it will configure (inject #Autowired or #Resource dependencies) that object.
Just change the Process class to
#Configurable
class Process {
#Autowired
private transient Repository repository;
// getters, setters, etc.
}
Whenever you create a new instance
Process process = new Process();
spring will automatically inject the dependencies.
This also works if the Process object is deserialized.
How about added using aspects to add an injection step when you deserialize the object?
You would need AspectJ or similar for this. It would work very similarly to the #Configurable function in Spring.
e.g. add some advice around the a "private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException" method
This article may also help: http://java.sun.com/developer/technicalArticles/Programming/serialization/
I think the idea of serializing a bean and then forcing a reinjection of dependencies is not the best architecture.
How about having some sort of ProcessWrapper bean instead which could be a singleton. It would be injected with the Repository and either manages the deserialization of the Process or has a setter for it. When a new Process is set in the wrapper, it would call setRepository() on the Process. The beans that use the Process could either be set with the new one by the wrapper or call the ProcessWrapper which would delegate to the Process.
class ProcessWrapper {
private Repository repository;
private Process process;
// getters, setters, etc.
public void do() {
process.do();
}
public void setProcess(Process process) {
this.process = process;
this.process.setRepository(repository);
}
}
Answering my own question: how I've solved the problem so far is to create a base class which serializes and deserializes using a cheap little proxy. The proxy contains only the name of the bean.
You'll note that it uses a global to access the Spring context; a more elegant solution might store the context in a thread-local variable, something like that.
public abstract class CheaplySerializableBase
implements Serializable, BeanNameAware {
private String name;
private static class SerializationProxy implements Serializable {
private final String name;
public SerializationProxy(CheaplySerializableBase target) {
this.name = target.name;
}
Object readResolve() throws ObjectStreamException {
return ContextLoader.globalEvilSpringContext.getBean(name);
}
}
#Override
public void setBeanName(String name) {
this.name = name;
}
protected Object writeReplace() throws ObjectStreamException {
if (name != null) {
return new SerializationProxy(this);
}
return this;
}
}
The resulting serialized object is 150 bytes or so (if I remember correctly).
The method applicationContext.getAutowireCapableBeanFactory().autowireBean(detachedBean); can be used to reconfigure a Spring-managed bean that was serialized and then de-serialized (whose #Autowired fields become null). See example below. The serialization details are omitted for simplicity.
public class DefaultFooService implements FooService {
#Autowired
private ApplicationContext ctx;
#Override
public SerializableBean bar() {
SerializableBean detachedBean = performAction();
ctx.getAutowireCapableBeanFactory().autowireBean(detachedBean);
return detachedBean;
}
private SerializableBean performAction() {
SerializableBean outcome = ... // Obtains a deserialized instance, whose #Autowired fields are detached.
return outcome;
}
}
public class SerializableBean {
#Autowired
private transient BarService barService;
private int value;
public void doSomething() {
barService.doBar(value);
}
}