Kotlin doesn't work with repository unlike service with jdbc - spring

I have repository class in Kotlin Spring application to which I inject JDBC Template only. Looks like this:
#Repository
class MobileRepository(
private var jdbcTemplate: JdbcTemplate
) {...}
It doesn't work throwing org.springframework.beans.factory.UnsatisfiedDependencyException and suggests that final class may be the reason. Then if I change it to open class it says: java.lang.NullPointerException: Cannot invoke "org.springframework.jdbc.core.JdbcTemplate.queryForList(String)" because "this.jdbcTemplate" is null .
If I replace it with Component (or Service) annotation (with or without open class) like this:
#Component
class MobileRepository(
private var jdbcTemplate: JdbcTemplate
) {...}
it works.
I assume the whole code is not necessary, because it works with replacing Repository with Component/Service. What might be the case? Till now I was believing that Repository, Service, Component annotations are basically the same, it's just the semantics. But it turns out that they are sort of not the same.

Related

Null Pointer Exception using Spring Boot service as a dependency in a batch job

I'm re-using an old, standalone AWT-based Java class which backs up and restores mysql databases.
One thing it needs to do is decrypt a password that it reads from a properties file.
The logic for this is contained in a Spring Boot application.
I'm instantiating the encryption service and decryptor in the standalone class as follows:
DecryptionService decryptionService = new DecryptionService();
The decryptionService uses the #AutoWired annotation to create a decryptor:
#Autowired
private IRSADecryptor decryptor;
For now, I'm running it Eclipse from the same project as the service.
When I try to decrypt the password as follows:
String decryptedPassword = decryptionService.decryptTextUsingProductKeys("abc");
the debugger show the decryptionService is null.
Here are the first few lines of the stack trace:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at com.ap.services.decryption.service.DecryptionService.decryptTextUsingProductKeys(DecryptionService.java:21)
at com.ilcore.util.SosaMaintenanceJFrame.jButtonDatabaseBackupActionPerformed(SosaMaintenanceJFrame.java:529)
at com.ilcore.util.SosaMaintenanceJFrame$6.actionPerformed(SosaMaintenanceJFrame.java:207)
I'm pretty sure I'm not going about this the right way, but I'd like to not have to import the decryption logic. What are my options?
The #Autowired annotation will not create your decryptor object, but will try to locate a Bean of that type and inject it in your DecryptionService. This means that you should not use a constructor to instantiate your DecryptionService. The DecryptionService should be defined as a #Service and injected in another component (#Component, #Controller etc.), from where you will invoke the specific methods for decrypting your data.

MockBean and MyBatis Mapper not working together (as they did before Spring Boot 2.2.7)

I am using MyBatis Spring Boot Starter version 2.1.3. Ever since moving to Spring Boot 2.2.7 (I've also tried 2.2.8 and 2.3.1 with the same results), I've had a problem using the MockBean annotation to mock a MyBatis interface (e.g. DAO). Let's say I have an interface like this one:
#Mapper
#Repository
public interface OrderDAO {
int insertOrder(#Param("order") Order order);
}
I'd like to execute an integration test and mock this mapper within my OrderService that contains a field of type OrderDAO.
My integration test is annotated with #SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) and contains this field:
#MockBean
private OrderDAO orderDAO;
When I run a test such as this and look at what the references to the OrderDAO objects are, in my integration test I see this:
com.example.dao.OrderDAO$MockitoMock$1819884459
But inside my OrderService class the field is this:
com.sun.proxy.$Proxy179 (org.apache.ibatis.binding.MapperProxy#37d9310e)
So, calls to Mockito.verify obviously don't work because my mock has not been injected into my OrderService class. Now, very oddly, I found that adding this code makes everything work:
#TestConfiguration
static class MockConfig {
#Bean
public OrderDAO orderDAO() {
return Mockito.mock(OrderDAO.class);
}
}
Adding this nested class along with adding the ContextConfiguration annotation on the integration test class, and now the object that gets injected into the OrderService class is the MockitoMock -- the same object that is referenced by the MockBean annotated field in the test class. I didn't have to do this with Spring Boot 1.2.6 and earlier and I couldn't find any reference to a change that would have caused this (although perhaps I didn't search long enough).
So, I am wondering if I am doing something incorrectly, or, am I missing something I should be doing? It seems like this should just work like it did before, which the need for this extra nested TestConfiguration class. Appreciate any insights anyone can provide. Thanks.
As mentioned by ave in the comments, I had to add the name to the mock bean annotation to get it to work
#MockBean(name = "orderDAO")
private OrderDAO orderDAO;

Decorate spring boot repository

I'm working on a Spring Boot API that's supposed to be deployed later this month. We created our own interface for a repository, and extended the CrudRepository. Spring boot autowires everything.
What I would like to do is add more logging capabilities, such as LOGGER.info("searched for solution ID").
Currently our code looks like this:
#Repository
public interface ProductSolutionRepository extends CrudRepository<ProductSolution, String> {
public List<ProductSolution> findBySolutionId(#Param("solutionId") int solutionId);
Since Spring configures everything don't really see a way of decorating these functions to add logging functionality. Can someone help me out by pointing me to the documentation, showing a nice example, or explaining the concept behind logging decorators?
First, I would like to point out some redundant codes for you.
You don't need to annotate the repository with #Repository, spring boot can autowire it automatically.
#Param is used when you write a sql with #Query, you just need to declare your parameters here.
The repository is the dao layer. A normal practice, you should create a service for each repository and autowire the repository into the service. Then you can implement transaction or write logs there.
You can use a single file AOP Logging Aspect using AspectJ cutting across your repository interfaces layer and logging method name, input args and output.
Assuming for this purpose a RepositoryLoggingAspect class, you'd have to annotate it first with #Aspect:
import org.aspectj.lang.annotation.Aspect;
#Aspect
public class RepositoryLoggingAspect {
//..
}
And then create a Pointcut aiming at your repository package you want to cut-accross:
#Pointcut("within(package.of.my.repositories..*)")
public void repositoriesPackagePointcut() {}
And finally define the logging logic in an #Around annotated method:
#Around("repositoriesPackagePointcut()")
public Object logMyRepos(ProceedingJoinPoint joinPoint) throws Throwable {
//log method name using: joinPoint.getSignature().getName()
//log method arguments using: Arrays.toString(joinPoint.getArgs())
//store and log method output using: Object myResult = joinPoint.proceed();
}

Spring Boot NoUniqueBeanDefinitionException

I am converting a Java EE project to Spring Boot 1.1.9. Before converting, I was used to CDI 1.2 for Dependency Injection.
I have an interface :
public interface AdminManager<V extends AdminView>
I also have a few implementations of this interface. They look like this :
#Repository
#Transactional(propagation=Propagation.REQUIRED)
public class DBRuleManager implements AdminManager<AdminRuleView>
#Repository
#Transactional(propagation=Propagation.REQUIRED)
public class DBFlagLogicManager implements AdminManager<AdminFlagLogicView>
Now, I have coded a REST endpoint, that is supposed to use the DBRuleManager:
#Controller
#RequestMapping("/admin/rule")
public class RestAdminRule {
#Inject
private AdminManager<AdminRuleView> manager;
}
When I run mvn spring-boot:run I get the following NoUniqueBeanDefinitionException :
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.company.server.admin.AdminManager] is defined: expected single matching but found 2: DBRuleManager,DBFlagLogicManager
I've read that Spring 4 is supposed to manage this kind of situation. What's the problem then? This was working well using CDI.
When trying to solve another problem (about proxies for #Transactional implementations), I found a way to get rid of this issue.
I used this parameter :
#EnableTransactionManagement(proxyTargetClass=true)
And then I was able to inject my AdminManager<AdminRuleView> directly. I don't understand why, though...

How to use spring to resolve dependencies of an object created manually?

I would like to know if it's possible to use Spring to resolve the dependencies of an object created manually in my program. Take a look at the following class:
public class TestClass {
private MyDependency md;
public TestClass() {
}
...
public void methodThaUsesMyDependency() {
...
md.someMethod();
...
}
}
This TestClass is not a spring bean, but needs MyDependency, that is a spring bean. Is there some way I can inject this dependency through Spring, even if I instantiate TestClass with a new operator inside my code?
Thanks
Edit: The method I'm describing in my original answer below is the general way to accomplish DI external of the container. For your specific need - testing - I agree with DJ's answer. It's much more appropriate to use Spring's test support, for example:
#Test
#ContextConfiguration(locations = { "classpath*:**/applicationContext.xml" })
public class MyTest extends AbstractTestNGSpringContextTests {
#Resource
private MyDependency md;
#Test
public void myTest() {
...
While the above example is a TestNG test, there is also Junit support explained in 8.3.7.2. Context management and caching.
General approach: Annotate your class with #Configurable and utilize AspectJ load-time or compile-time weaving. See 6.8.1 in the Spring documentation on AOP for more details.
You can then annotate your instance variables with #Resource or #Autowired. Though they accomplish the same goal of dependency injection, I recommend using #Resource since it's a Java standard rather than Spring-specific.
Lastly, remember to consider using the transient keyword (or #Transient for JPA) if you plan on serializing or persisting the objects in the future. Chances are you don't want to serialize references to your DI'd repository, service, or component beans.
See the autowire() method on the AutowireCapableBeanFactory class. If you use an ClasspathXmlApplicationContext, you can get the factory with getAutowireCapableBeanFactory()
To get the ApplicationContext, you would need to use a static singleton or other central repository, such as JNDI or a Servlet container. See DefaultLocatorFactory on how to get an instance of the ApplicationContext.
If what you need is for testing purposes, Spring has good support for the scenario that you described above.
Check out Spring Reference manual section on Testing

Resources