UnsatisfiedDependencyException because of the JDK proxy - java

I'm trying to use the default aop proxy provided by Spring, but i'm getting an execption error.
Here is my code:
A first class that run the test example.
#EnableAspectJAutoProxy()
#ComponentScan(basePackageClasses = {MyDaoRepository.class, MyService.class,MyAdvices.class})
#Configuration
public class SpringAdvices {
public static void main( String[] args ) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringAdvices.class);
service myService = ctx.getBean(MyService.class);
Person p1 = (Person) ctx.getBean("person");
myService.save(p1);
}
#Bean
public Person person(){
return Person.builder()
.name("Bagna")
.age(52)
.profession(null)
.dateOfBirth(LocalDate.of(1950,12,13))
.build();
}
}
A second class that represent my advices:
#Aspect
#Component
public class MyAdvices {
#Before("execution(boolean *.dao.save(..))")
public void beforesavamethod(){
System.out.println("beforesavamethod");
}
#After("execution(boolean *.dao.save(..))")
public void aftersavamethod(){
System.out.println("aftersavamethod");
}
}
My service and repository classes:
#Service
public class MyService implements service {
#Autowired
MyDaoRepository myDaoRepository;
#Override
public boolean save( Person person ){
return this.myDaoRepository.save(person);
}
#Override
public boolean delete(Person person){
return this.myDaoRepository.delete(person);
}
}
public interface service {
public boolean save( Person person );
public boolean delete( Person person );
}
#Repository
public class MyDaoRepository implements dao {
List<Person> personList = new ArrayList<>();
#Override
public boolean save( Person person ){
return this.personList.add(person);
}
#Override
public boolean delete( Person person ){
return this.personList.remove(person);
}
}
public interface dao {
public boolean save( Person person );
public boolean delete( Person person );
}
The exceptin I'm getting concern the injection of the dao object to the service object.
UnsatisfiedDependencyException: Error creating bean with name
'myService': Unsatisfied dependency expressed through field
'myDaoRepository'; nested exception is
org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean
named 'myDaoRepository' is expected to be of type
'aop.question_005.dao.MyDaoRepository' but was actually of type
'com.sun.proxy.$Proxy22'
I can solve this problem by enabling the GCLIB mechanism, but i'm wondering how can i solve this problem using the same JDK dynamic proxy?

The problem in your code is that you are using the class MyDaoRepository instead of the dao interface. You can cast your proxy to the interface dao but you can not cast it to its implementation. You need to modify your service code to use interfaces:
#Service
public class MyService implements service {
#Autowired
dao myDaoRepository;
#Override
public boolean save( Person person ){
return this.myDaoRepository.save(person);
}
#Override
public boolean delete(Person person){
return this.myDaoRepository.delete(person);
}
}

Related

Custom Repository Implementation is not being recognized

I am currently working on a project where I have created the following custom Repository:
public interface ServiceRepository<T extends ServiceEntity> extends JpaRepository<T, UUID>, ServiceRepositoryCustom {
}
public interface ServiceRepositoryCustom {
List<ServiceEntity> findAllContainingName(String query);
}
#Repository("Repo")
public class ServiceRepositoryCustomImpl implements ServiceRepositoryCustom {
private final EntityManager em;
public ServiceRepositoryCustomImpl(EntityManager em) {
System.out.println("I got constructed");
this.em = em;
}
#Override
public List<ServiceEntity> findAllContainingName(String name) {
System.out.println("I got called with: " + name);
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<ServiceEntity> cq = cb.createQuery(ServiceEntity.class);
Root<ServiceEntity> serviceEntity = cq.from(ServiceEntity.class);
List<Predicate> predicates = new ArrayList<>();
if(name != null) {
// predicates.add(cb.equal(serviceEntity.get("name"), name));
predicates.add(cb.like(serviceEntity.get("name"), name + "%"));
}
cq.where(predicates.toArray(predicates.toArray(new Predicate[0])));
return em.createQuery(cq).getResultList();
}
}
The print statement "I got called with: " never gets called. So for whatever reason Spring Boot is not running the method through my custom implementation.
Any suggestions? Any help is much appreciated
Edit:
Here is the code that injects and uses the Repository in question
#Repository
public interface PineappleServiceRepository extends ServiceRepository<PineappleServiceEntity> {
}
#Component("Registry")
#DependsOn({"Context", "Repo"})
public class Registry {
private final List<ServiceRepository<? extends ServiceEntity>> serviceRepositories = new ArrayList<>();
public Registry(PineappleServiceRepository pineappleServiceRepository) {
this.serviceRepositories.add(pineappleServiceRepository);
}
}
Edit 2:
The code prints "I got constructed"
Edit 3:
Class where findAllContainingName is called
#RestController
#RequestMapping("/test")
#DependsOn("Registry")
public class ServiceController {
private final Registry registry;
public ServiceController(#NotNull Registry registry) {
this.registry = registry;
}
#GetMapping("")
List<ServiceEntity> all(#RequestParam("q") String query) {
return getAllServices(query);
}
private #NotNull List<ServiceEntity> getAllServices(String query) {
List<ServiceEntity> response = new ArrayList<>();
for(ServiceRepository<? extends ServiceEntity> repo: this.registry.getServiceRepositories()){
response.addAll(repo.findAllContainingName(query));
}
return response;
}
}
Edit 4:
Here the entities:
#Entity
#Table(name = "services")
public abstract class ServiceEntity {
protected #Id
UUID id = UUID.randomUUID();
protected String name;
// Constructor + Getters and Setters
}
#Entity
public class PineappleServiceEntity extends ServiceEntity {
// Additional Properties, matching Constructors, Getters and Setters
}
So I was able to reproduce your problem and fix it. Issue with your code is that your PineappleServiceRepository is not extending ServiceRepositoryCustom directly. It seems your repository needs to implement it directly if you are accessing custom repository methods from that repository. I got that idea from this post.
So to fix your issue, either remove PineappleServiceRepository(as you don't have any properties in PineappleEntity) and use ServiceRepository to call that custom method or make PineappleServiceRepository extend ServiceRepositoryCustom.
I have pushed changes to GitHub with fix. You can take a look. If you want to keep PineappleServiceRepository and access custom method using this repository, let me know, I can update code.

Share one interface instance on whole application

I'm creating an application based on Hazelcast and spring-boot-starter-web. The application structure is:
Book controller-> BookService interface-> BookServiceImplementation-> put into hazelcast queue
Author controller-> AuthorService interface-> AuthorServiceImplementation-> put into hazelcast queue.
For that purpose i need one class that contains hazelcastInstance to share it in all services so i created blackboard interface but because i use #Autowired it is creating new instance for every service and i need to set hazelcast instance again.
My code so far:
Controller:
#GetMapping("book")
public ResponseEntity<Void> getBookDetails(
#RequestParam(value = "bookId", required = false) Long bookId) {
bookService.add(bookId);
return new ResponseEntity<Void>(HttpStatus.OK);
}
Service impl:
#Service("bookService")
public class BookServiceImpl extends BaseService implements BookService {
#Override
public void add(Long bookId) {
blackboard.add(bookId, Listeners.BOOK_QUEUE_NAME);
}
BaseService:
public class BaseService {
#Autowired
protected Blackboard blackboard;
public void loadInstance(ClientConfig clientConfig) {
HazelcastInstance hazelcastInstanceClient = HazelcastClient.newHazelcastClient(clientConfig);
blackboard.setHazelcastInstance(hazelcastInstanceClient);
}
}
Blackboard interface impl:
#Component("blackboard")
public class BlackboardImpl implements Blackboard {
private HazelcastInstance hazelcastInstance;
#Override
public HazelcastInstance getHazelcastInstance() {
return hazelcastInstance;
}
#Override
public void setHazelcastInstance(HazelcastInstance hazelcastInstance) {
this.hazelcastInstance = hazelcastInstance;
}
#Override
public boolean add(Object obj, String collectionId) {
IQueue<Object> queue = hazelcastInstance.getQueue(collectionId);
return queue.add(obj);
}
}

Abstract properties in an abstract class [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 1 year ago.
Improve this question
I have an abstract class with some configuration properties value which are set using #Value. I want to reuse the abstract class but with another set of configuration properties. The issue is that, those properties value have already been set in the abstract class and all of the concrete classes have inherited it.
I have thought about:
creating another set of config values in the abstract class, but that seems to be creating duplicate, but this is not quite extensible when in future there is yet a third set of config values.
changing the accessibly of the config value in the abstract class from private to protected and have the concrete class to override it. But I'm not sure this kind of overriding is good as it seems create confusion as to what is the actual config value.
create another abstract class which is similar as "AbstractService" but injecting the different set of config value using #Value. This also seems to create duplication.
public abstract class AbstractService {
#Value("${config1}")
private String config1;
#Value("${config2}")
private String config2;
public void serviceMethod() {
//using config1 and config 2 values
}
}
public class concreteServiceA extends AbstractService {
public void serviceA() {
// using serviceMethod in the abstract class
}
}
public class concreteServiceB extends AbstractService {
public void serviceB() {
// using serviceMethod in the abstract class
}
}
Would it be a good way if using constructor to pass the required parameters in the abstract class, and let the concrete classes to use constructor injection and #Value to set those values ? though if there are long list of config values this may not scale well.
public abstract class AbstractService {
private String config1;
private String config2;
public AbstractService(String config1, String config2) {
this.config1 = config1;
this.config2 = config2;
}
public void serviceMethod() {
//using config1 and config2 values
}
}
public concreteServiceA extends AbstractService {
public concreteServiceA(#Value("${config1}") String config1,
#Value("${config2}") String config2) {
super(config1, config2);
}
public void serviceA() {
//using serviceMethod in the abstract class
}
}
public concreteServiceB extends AbstractService {
public concreteServiceB(#Value("${configB1}") String config1,
#Value("${configB2}") String config2) {
super(config1, config2);
}
public void serviceB() {
//using serviceMethod in the abstract class
}
}
You can go like following:
public abstract class AbstractService {
public void serviceMethod() {
String config1 = getConfig1();
String config2 = getConfig2();
//using config1 and config 2 values
}
public abstract String getConfig1();
public abstract String getConfig2();
}
public class concreteServiceA extends AbstractService {
#Value("${config1}") private String config1;
#Value("${config2}") private String config2;
public String getConfig1(){
return config1;
}
public String getConfig2(){
return config2;
}
public void serviceA() { // using serviceMethod in the abstract class }
}
public class concreteServiceB extends AbstractService {
#Value("${config1.1}") private String config1;
#Value("${config2.1}") private String config2;
public String getConfig1(){
return config1;
}
public String getConfig2(){
return config2;
}
public void serviceB() { // using serviceMethod in the abstract class }
}
You could either use setter injection or (probably more elegant) constructor injection like this:
public abstract class AbstractService {
protected AbstractService(String config1, String config2) {
this.config1 = config1;
this.config2 = config2;
}
private String config1;
private String config2;
public void serviceMethod() {
//using config1 and config 2 values
}
}
public class ConcreteServiceA extends AbstractService {
public ConcreteServiceA(#Value("${config1a}") String config1, #Value("${config2a}") String config2) {
super(config1, config2);
}
public void serviceA() {
// using serviceMethod in the abstract class
}
}
public class ConcreteServiceB extends AbstractService {
public ConcreteServiceB(#Value("${config1b}") String config1, #Value("${config2b}") String config2) {
super(config1, config2);
}
public void serviceB() {
// using serviceMethod in the abstract class
}
}
But if you have lots of values you can also use setter injection and override the setters in each subclass. Or you can still use constructor injection but pass a container class holding the config like this:
public class ServiceConfig {
private String config1;
private String config2;
// getters, setters and more properties
}
Then pass it like this
public abstract class AbstractService {
private ServiceConfig config;
protected AbstractService(ServiceConfig config) {
this.config = config;
}
}
public class ConcreteServiceA extends AbstractService {
public ConcreteServiceA(#Value("${configA}") ServiceConfig config) {
super(config);
}
}
You can externalize your properties to specific beans which will be autowired to the concrete classes.
Spring annotation #ConfigurationProperties allows you to initialise simple POJO properties based on properties prefix.
First create your POJO which we will inject in the concrete services :
public class ServiceProperties {
private String config1;
private String config2;
//getters and setters
}
Then create a configuration class in a package scanned by spring :
#Configuration
public class ServicePropertiesConfiguration {
#Bean
#ConfigurationProperties(prefix = "service-a")
public ServiceProperties serviceAProperties() {
return new ServiceProperties();
}
#Bean
#ConfigurationProperties(prefix = "service-b")
public ServiceProperties serviceBProperties() {
return new ServiceProperties();
}
}
As you can see, prefix tells to spring where he has to search the properties. Your application.properties will look like this :
service-a.config1=serviceAConfig1
service-a.config2=serviceAConfig2
service-b.config1=serviceBConfig1
service-b.config2=serviceBConfig2
At this stage, you will have two beans of type ServiceProperties with specific values inside
The abstract service looks like this :
public abstract class AbstractService {
private final ServiceProperties serviceProperties;
protected AbstractService(ServiceProperties serviceProperties) {
this.serviceProperties = serviceProperties;
}
public void serviceMethod() {
//using config1 and config 2 values
// serviceProperties.getConfig1();
// serviceProperties.getConfig2();
}
}
In the concrete service, you have to use #Qualifier annotation with name of created bean
#Service
public class ConcreteServiceA extends AbstractService{
public ConcreteServiceA(#Qualifier("serviceAProperties") ServiceProperties serviceProperties) {
super(serviceProperties);
}
}
#Service
public class ConcreteServiceB extends AbstractService{
protected ConcreteServiceB(#Qualifier("serviceBProperties") ServiceProperties serviceProperties) {
super(serviceProperties);
}
}

What is the difference between #Bean and #Component in Spring when using #Conditional?

I want to register a Boss when there is a Car in Spring container.
My code is below
#Configuration
#ComponentScan(value ={"org.example.springframework.condition","org.example.springframework.bean"})
public class ConditionConfig {
}
#Component
public class Car {
}
#Conditional(value = BossCondition.class)
#Component
public class Boss {
}
public class BossCondition implements Condition {
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return context.getRegistry().containsBeanDefinition("car");
}
}
But it doesn't work, I can't discover the car in Condition.
Then, I change my code below, it can work well.
#Configuration
public class ConditionConfig {
#Bean
public Car car() {
return new Car();
}
#Bean
#Conditional(value = BossCondition.class)
public Boss boss() {
return new Boss();
}
}
public class Car {
}
public class Boss {
}
public class BossCondition implements Condition {
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return context.getRegistry().containsBeanDefinition("car");
}
}
So, what is the difference between #Bean and #Component?

#Inject in abstract class based on subclass

let imagine I have per entity a repository class (spring data jpa) for database access and a service class. The dependencies are managed by spring framework. Every service method does in most cases the same, so there is mainly code duplication:
public class NewsService {
#Inject
private NewsRepository newsRepository;
public void add(News news) {
// do some validation
newsRepository.save(news);
}
}
public class UserService {
#Inject
private UserRepository userRepository;
public void add(User user) {
// do some validation
userRepository.save(user);
}
}
Now i thought about creating an abstract class like this:
public abstract class AbstractService<T> {
private UnknownRepository unknownRepository;
public void add(T entity) {
// do some validation
unknownRepository.save(entity);
}
}
public class NewsService extends AbstractService<News> {
}
public class UserService extends AbstractService<User> {
}
My problem: How can i overwrite the repository used inside the abstract class based on my entities?
You can replace the UnknownRepository field with an abstract method and a type parameter:
// R is the type of the repository
public abstract class AbstractService<T,R extends BaseRepository> {
protected abstract R getRepository();
public void add(T entity) {
getRepository().save(entity);
}
}
And inject the specific repository to the implementations of this class:
public class NewsService extends AbstractService<News, NewsRepository> {
#Inject private NewsRepository newsRepository;
#Override
public NewsRepository getRepository() {
return newsRepository;
}
// the inherited add() method works now
}

Categories