How to call Spring Framework repositories methods - java

I know that there are questions similar to this one, but none of them have helped me. I'm following along this tutorial, and the part I can't wrap my mind around is:
#SpringBootApplication
public class Application {
private static final Logger log =
LoggerFactory.getLogger(Application.class);
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
#Bean
public CommandLineRunner demo(CustomerRepository repository) {
return (args) -> {
// save a couple of customers
...
// more lines, etc...
What I don't understand is where the repository passed into demo comes from. I know that the Autowired annotation can do something like that, but it isn't used at all here.
The more specific reason I ask is because I'm trying to adapt what they do here to an application I'm working on. I have a class, separate from all of the persistence/repository stuff, and I want to call repository methods like save and findAll. The issue is that the repository is an interface, so I can't instantiate an object of it to call the methods. So do I have to make a new class that implements the interface and create an object of that? Or is there an easier way using annotations?

When creating a #Bean, adding the repository in the parameters of the bean is enough to wire the repos in your bean. This works pretty much like adding #Autowired annotation inside a class that is annotated as #Component or something similar.
Spring works mostly with interface, since that is simplier to wire vs wiring concrete classes.

Can you try #Repository before the declaration of class? Worked for me in a Spring MVC structure.
#Repository
public class EntityDAOImpl implements EntityDAO{
...
}

The thing to wrap your head around is a Spring Boot application at startup time aims to resolve its dependancy tree. This means discovering and instantiating Beans that the application defines, and those are classes annotated with #Service, #Repository, etc.
This means the default constructor (or the one marked with #Autowire) of all beans is invoked, and after all beans have been constructed the application starts to run.
Where the #Bean annotation comes into play is if you have a bean which does not know the values of it's constructor parameters at compile time (e.g. if you want to wire in a "started at" timestamp): then you would define a class with an #Configuration annotation on it, and expose an #Bean method in it, which would return your bean and have parameters that are the beans dependencies. In it you would invoke the beans constructor and return the bean.
Now, if you want a certain method of some class to be invoked after the application is resolved, you can implement the CommandLineRunner interface, or you can annotate a method with #PostConstruct.
Some useful links / references:
https://docs.spring.io/spring-javaconfig/docs/1.0.0.m3/reference/html/creating-bean-definitions.html
https://www.baeldung.com/spring-inject-prototype-bean-into-singleton
Running code after Spring Boot starts
Execute method on startup in Spring

Related

Creating objects that implement JpaRepo interfaces via Autowiring in JUnit?

I'm tasked with writing JUnit classes. To do this, I need to create an object that implements an interface that extends org.springframework.data.jpa.repository.JpaRepository, (called "KanjiRepo") yet no classes in this application actually implement KanjiRepo.
Rather than with new, all objects that implement KanjiRepo seem to be created via #Autowiring.
The KanjiRepo interface is a member of a package that has only interfaces, and they all extend org.springframework.data.jpa.repository.JpaRepository.
[question] I don't think I understand the problem. Can someone tell me if what I just said sounds correct. In my junit, do I also use #Autowire to create objects that implement the interfaces in the same package as KanjiRepo?Maintaining 2 separate Application Contexts will be needed as a last step?
I think Autowiring KanjiRepo is enough in your test class unless you annotate your repository as #Repository.
#Repository
public interface KanjiRepo extends JpaRepository....
If you have #Repository annotation on top of KanjiRepo and if you annototated your main class or configuration class to auto scan beans; spring would handle creating and autowiring beans succesfully.
Please check for component scan
#SpringBootApplication
// or #ComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
And then, you can create your test class with the following code;
#Autowired
KanjiRepo repo;
#Test
public void testFindById() {
Kanji instance = repo.findById(0L);
assert.....
}
should be fine.
Can the application and JUnit share the same configuration files?
Actually, it is. But, if you do component scan, you don't have to worry that. Spring will handle where your bean is and it should autowire succesfully.
do I also use #Autowire to create objects that implement the interfaces in the same package as KanjiRepo?
Spring will do component scan and will find where your repository is, so, you don't have to worry that where you locate your repository.

How to create a bean by type in Spring?

In my ApplicationContext I have several Beans being created the same style. So I have a lot of dublicated code writing a FactoryBean for each of this beans. Those beans have a common ground, implementing all one special interface.
I would like to move all that bean creation to one factory. That one would have to provide a methode like this
<T extends CommonInterface> T createInstance(Class<T> clazz);
There I could implement all the instantiation necessary to create one of my special beans.
My implementation would be called by spring for
#Autowired
private MyCommonInterfaceImplementation impl;
in that way
createInstance(MyCommonInterfaceImplementation.class)
So far I looked at BeanFactory and FactoryBean, both seem not to be I'm searching for.
Any suggestions?
why not use #bean
#Bean
public MyCommonInterfaceImplementation getMyCommonInterfaceImplementation(){
return MyBeanFactory.createInstance(MyCommonInterfaceImplementation.class);
}
//should autowire here
#Autowired
private MyCommonInterfaceImplementation impl;
Basically you need the #Bean annotation on a "factory" only if you need some special handling during the creation of a bean.
If everything can be #Autowired, either by setters, fields, or one constructor, and nothing else needs to be done on a bean during initialization, you can simply declare the annotation #Component on each implementation of your interface. This works as long as you have component scanning active inside your application. The result will be that for each component spring will create a bean which you can use.
I'm writing this on a mobile so showing code is not the best. Just follow some tutorial on #ComponentScan, or if you need, let me know and I can augment this answer with an example.
As of Spring 4.3 you no longer have to annotate your bean classes and you can let them be instantiated via a componentscan.
#Configuration
#ComponentScan(
value = "some.package.path",
includeFilters = {
#Filter(type = ASSIGNABLE_TYPE, value = {
MyClass1.class,
MyClass2.class,
MyClass3.class
})
})
This actually creates beans for the three classes listed there. The example should work without filters as well (everything in the package becomes a bean). This works as long as the classes have a single constructor that can be used for autowiring. I don't think it is possible to filter for all implementations of a particular interface and then register a bean.
To do that, you might do something with a ContextListener and e.g. use reflection to find out what classes to instantiate and then use context.autowire(..) to inject any dependencies from your context. A bit hacky but it might work.
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
ApplicationContext context = event.getApplicationContext();
MyClass bean
= context
.getAutowireCapableBeanFactory()
.autowire(MyClass.class, Autowire.BY_NAME.value(), true);
...
}
That still leaves the problem of how to get the bean registered in the context of course.
You might also be able to adapt the answer to this SO question on how to add beans programmatically.
Finally the best approach I've found is using a ConfigurationClassPostProcessor. As example I've used https://github.com/rinoto/spring-auto-mock
But, since it is quite complicated and "too much magic" to create beans from nothing, we decided to explicitly create those beans via #Bean.
Thanks for your answers.

Rest + Spring AOP + interface doesn't inject

I have a Spring AOP aspect used for logging, where a method can be included for logging by adding an annotation to it, like this:
#AspectLogging("do something")
public void doSomething() {
...
}
I've been using this on Spring beans and it's been working just fine. Now, I wanted to use it on a REST-service, but I ran into some problems. So, I have:
#Path("/path")
#Service
public class MyRestService {
#Inject
private Something something;
#GET
#AspectLogging("get some stuff")
public Response getSomeStuff() {
...
}
}
and this setup works just fine. The Rest-service that I'm trying to add the logging to now has an interface, and somehow that messes stuff up. As soon as I add the #AspectLogging annotation to one of the methods, no dependencies are injected in the bean, and also, the aspect is newer called!
I've tried adding an interface to the REST-service that works, and it gets the same error.
How can having an interface lead to this type of problems? The aspect-logger works on classes with interfaces elsewhere, seems it's only a problem when it's a REST-service..
Ref the below Spring documentation (para 2) -
To enable AspectJ annotation support in the Spring IoC container, you
only have to define an empty XML element aop:aspectj-autoproxy in your
bean configuration file. Then, Spring will automatically create
proxies for any of your beans that are matched by your AspectJ
aspects.
For cases in which interfaces are not available or not used in an
application’s design, it’s possible to create proxies by relying on
CGLIB. To enable CGLIB, you need to set the attribute
proxy-targetclass= true in aop:aspectj-autoproxy.
In case your class implements an interface, a JDK dynamic proxy will be used. However if your class does not implement any interfaces then a CGLIB proxy will be created. You can achieve this #EnableAspectJAutoProxy. Here is the sample
#Configuration
#EnableAspectJAutoProxy
public class AppConfig {
#Bean
public LoggingAspect logingAspect(){
return new LoggingAspect();
}
}
#Component
#Aspect
public class LoggingAspect {
...
...
}
In my opinion what you are actually trying to do is to add spring annotations to a class maintained by jersey. In the result you are receiving a proxy of proxy of proxy of somethng. I do not think so this is a good idea and this will work without any problems. I had a similar issue when I tried to implement bean based validation. For some reasons when there were #PahtParam and #Valid annotations in the same place validation annotations were not visible. My advice is to move your logging to a #Service layer instead of #Controller.

#Inject not injecting and causing NullPointerException using component scanning

My application context XML is simple:
<context:component-scan base-package="com.depressio.spring" />
In that package, I have my configuration:
package com.depressio.spring
#Configuration
#ComponentScan(basePackages = "com.depressio")
public class DepressioConfiguration
{
#Inject private ApplicationContext context;
}
Within com.depressio, there's a repository (DAO):
package com.depressio.dao;
#Repository
public class ParameterDAO
{
public Parameter getParameter(long ID) { ... }
}
... and a service where injection is working just fine (no NPE when parameterDAO is used):
package com.depressio.resource;
#Service
#Path("/depressio/parameters")
public class ParameterResource
{
#Inject private ParameterDAO parameterDAO;
#Path("{id}")
public Response getParameter(long parameterID)
{
return Response.ok(parameterDAO.getParameter(parameterID).legacyFormat()).build();
}
}
However, the legacyFormat() method call there constructs another object. Within that object, I have to inject a different DAO (also annotated with #Repository, though). That injection isn't working.
So, we have the original Parameter object:
package com.depressio.domain;
public class Parameter
{
...
public LegacyParameter legacyFormat()
{
return new LegacyParameter(this);
}
}
... and the LegacyParameter where the injection isn't working:
package com.depressio.domain.legacy;
public class LegacyParameter
{
#Inject private LegacyDAO legacyDAO;
....
public LegacyParameter(Parameter newParameter)
{
// NullPointerException when using the injected legacyDAO.
}
}
I've tried a few things, including:
Using an no-args constructor for LegacyParameter, then calling a populate method so I'm not using the injected DAO until after the object is constructed. This didn't work.
Injecting the LegacyDAO into the ParameterResource and passing it in. This worked, but isn't ideal since I have to pass it around a whole lot (which injection should help avoid, no?). It did prove that LegacyDAO is injectible... just not into LegacyParameter apparently.
Adding a #Service, #Component, or #Named annotation on LegacyParameter. All end up with the NullPointerException on the line I try to reference the injected legacyDAO.
What am I missing?
As Sotirios has pointed out, it can't work since you create a regular Java object and do not give Spring a chance to enhance it.
Either let Spring create objects for which you want to enjoy the Spring 'magic' (like setting #Inject dependencies etc).
Or create your own objects and set the dependencies yourself (yourObject.setDao(dao)).
That said, there are exceptional cases in which you still want to create your objects 'on the fly' by yourself but rely on Spring to inject dependencies to these objects. In this case you should call Spring explicitly:
LegacyParameter p = new LegacyParameter(...);
applicationContext.getAutowireCapableBeanFactory().autowireBean(p);
I don't think you really need it in your case.
(see this link inject bean reference into a Quartz job in Spring? for an example when this is really required).
In addition, I would advice to simplify your configuration.
Why do you use both xml-based and java-based configuration that do actually the same? In your example you could keep only one of them and have the same effect.

Spring #Value annotation always evaluating as null?

So, I have a simple properties file with the following entries:
my.value=123
another.value=hello world
This properties file is being loaded using a PropertyPlaceHolderConfigurer, which references the properties file above.
I have the following class, for which I'm trying to load these properties in to like so:
public class Config
{
#Value("${my.value}")
private String mValue;
#Value("${another.value}")
private String mAnotherValue;
// More below...
}
The problem is that, mValue and mAnotherValue are ALWAYS null... yet in my Controllers, the value is being loaded just fine. What gives?
If instances of Config are being instantiated manually via new, then Spring isn't getting involved, and so the annotations will be ignored.
If you can't change your code to make Spring instantiate the bean (maybe using a prototype-scoped bean), then the other option is to use Spring's load-time classloader weaving functionality (see docs). This is some low-level AOP which allows you to instantiate objects as you normally would, but Spring will pass them through the application context to get them wired up, configured, initialized, etc.
It doesn't work on all platforms, though, so read the above documentation link to see if it'll work for you.
I had similar issues but was a newbie to Spring.
I was trying to load properties into an #Service, and tried to use #Value to retrieve the property value with...
#Autowired
public #Value("#{myProperties['myValue']}") String myValue;
I spend a whole day trying various combinations of annotations, but it always returned null.
In the end the answer as always is obvious after the fact.
1) make sure Spring is scanning your class for annotations by including the package hierachy
In your servlet.xml (it will scan everything below the base value you insert.
2) Make sure you are NOT 'new'ing the class that you just told Spring to look at. Instead, you use #Autowire in the #Controller class.
Everything in Spring is a Singleton, and what was happening was Spring loaded the values into its Singleton, then I had 'new'ed another instance of the class which did not contain the newly loaded values so it was always null.
Instead in the #Controller use...
#Autowired
private MyService service;
Debugging...
One thing I did to find this was to extend my Service as follows...
#Service
public class MyService implements InitializingBean
Then put in debug statements in...
#Override
public void afterPropertiesSet() throws Exception {
// TODO Auto-generated method stub
LOGGER.debug("property myValue:" + myValue);
}
Here I could see the value being set on initialization, and later when I printed it in a method it was null, so this was a good clue for me that it was not the same instance.
Another clue to this error was that Tomcat complained of Timeouts trying to read from the Socket with Unable to parse HTTPheader... This was because Spring had created an instance of the service and so had I, so my one was doing the real work, and Spring was timing out on its instance.
See my answer here.
I ran into the same symptoms (#Value-annotated fields being null) but with a different underlying issue:
import com.google.api.client.util.Value;
Ensure that you are importing the correct #Value annotation class! Especially with the convenience of IDEs nowadays, this is a VERY easy mistake to make (I am using IntelliJ, and if you auto-import too quickly without reading WHAT you are auto-importing, you might waste a few hours like I did).
The correct import is:
org.springframework.beans.factory.annotation.Value
As its working with #Controller, it seems you are instantiating Config yourself. Let the Spring instantiate it.
You can also make your properties private, make sure your class is a Spring bean using #Service or #Component annotations so it always gets instantiated and finally add setter methods annotated with #Value . This ensures your properties will be assigned the values specified in your application.properties or yml config files.
#Service
public class Config {
private static String myProperty;
private static String myOtherProperty;
#Value("${my.value}")
public void setMyProperty(String myValue) {
this.myProperty = myValue;}
#Value("${other.value}")
public void setMyOtherProperty(String otherValue) {
this.myOtherProperty = otherValue;}
//rest of your code...
}
Add <context:spring-configured /> to you application context file.
Then add the #Configurable annotation to Config class.
In my case in my unit test, executeScenarioRequest always is null
#RunWith(SpringRunner.class)
#ExtendWith(MockitoExtension.class)
class ScenarioServiceTestOld {
#Value("classpath:scenario/SampleScenario.json")
Resource executeScenarioRequest;
Change #ExtendWith(MockitoExtension.class) to #ExtendWith(SpringExtension.class)

Categories

Resources