8

I have such classes and Spring context.

How to fix this wrong Java configuration, not xml?

I'd tried some solutions from other posts, but without success.

@Service
@Transactional
public class XCalculationService implements VoidService<X> {
}

public interface VoidService<Input> {
}

@AllArgsConstructor
public class XService {
private XCalculationService calculationService;
}

@Configuration
public class ServiceConfiguration {
@Bean
public OrderService orderService(XCalculationService calculationService) {
    return new XService(calculationService);
}

@Bean
public XCalculationService calculationService() {
    return new XCalculationService ();
}
}

Error

BeanNotOfRequiredTypeException: Bean named 'calculationService' is expected to be of type 'com.x.XCalculationService' but was actually of type 'com.sun.proxy.$Proxy
Arthur
  • 1,156
  • 3
  • 20
  • 49

3 Answers3

14

Here is 100% fix:

@EnableTransactionManagement(proxyTargetClass = true)
Arthur
  • 1,156
  • 3
  • 20
  • 49
  • Makes it "Cannot subclass final class X" - kotlin woes – Neikius Jan 14 '19 at 13:13
  • 1
    Know why you have this problem, why this fixes it, and what that means: https://docs.spring.io/spring/docs/3.0.0.M3/reference/html/ch08s06.html – Tadhg Nov 22 '19 at 21:10
2

Java proxies are working on interfaces, not concrete classes.
Reasoning with spring documentation: https://docs.spring.io/spring-framework/docs/3.0.0.M3/reference/html/ch08s06.html

If the target object to be proxied implements at least one interface then a JDK dynamic proxy will be used.

Therefore, when using aspect/proxy based annotations as @Transactional, Spring will attempt to proxify the concrete class and resulting object will be instance of VoidService interface not XCalculationService.

Therefore you can solve it two ways:

  1. use @Arthur solution and turn off Java's interface proxy in favor of CGLib for transaction support @EnableTransactionManagement(proxyTargetClass = true)
  2. Instead of using XCalculationService type in injectable fields, use only its proxied interface aka VoidService.
oneat
  • 10,778
  • 16
  • 52
  • 70
1

I suppose you have got @ComponentScan somewhere activated and it scans your @Service annotated XCalculationService class.

So you should either remove @Service from XCalculationService

or remove

@Bean
public XCalculationService calculationService() {
    return new XCalculationService ();
}

from ServiceConfiguration

mrkernelpanic
  • 4,268
  • 4
  • 28
  • 52
  • Removed @Service, same error. I have only for web @ComponentScan(basePackages = {"com.x.web"}) – Arthur Oct 02 '18 at 08:23