0

I have a RestController that has a Service with a public method annotated with @Transactional. The RestController class is annotated with @RestController, and the service bean is injected using Constructor injection. You can assume that the service is written as a different public class. MyRespository is annotated with @Repository annotation.

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.transaction.Transactional;

@RestController
@RequiredArgsConstructor
public class MyController {

    private final MyService myService;

    @PatchMapping("/some-endpoint")
    public SomeCustomObject updateSomeObject(){
        // This prints `package.x.y.z.MyService` as opposed to something like `package.x.y.z.MyService$$EnhancerBySpringCGLIB$$a1b2c3d4`
        log.info("myService proxy {}", myService.getClass());
        return myService.updateSomeObject();
    }

}


@Service
@RequiredArgsConstructor
public class MyService extends SomeBaseService{

    private final MyRepository myRepository;

    @Transactional(rollbackOn = SomeCustomException.class)
    public SomeCustomObject updateSomeObject(){
        log.info("Is Transaction Active {} Name {} ", TransactionSynchronizationManager.isActualTransactionActive(),
                TransactionSynchronizationManager.getCurrentTransactionName()); // This prints `false` and `null`
        SomeCustomObject someCustomObject = getTheObj();
        updateTheObject(someCustomObject);
    } // Updates are not persisted to the database.

    private SomeCustomObject getTheObj(){
        return myRepository.HugeMethodNameThatsWhyUsedAMethodAsWrapper();
    }

    private void updateTheObject(SomeCustomObject someCustomObject){
        myRepository.setSomething(someCustomObject);
    }
}

On googling, I found Spring may not be able to create a proxy if circular dependencies are there. So I tried Field injection using @Autowired still the log output show the real object.

In one of the other controllers which have another service, which also extends from the SomeBaseService like MyService class, injected, the proxy is being created and all these classes are within the same base package.

vvs14
  • 720
  • 8
  • 19
  • Possibly related: https://stackoverflow.com/questions/1201726/tracking-down-cause-of-springs-not-eligible-for-auto-proxying – meriton May 31 '23 at 14:15
  • `javax.transaction.Transactional` - that is wrong annotation, should be `org.springframework.transaction.annotation.Transactional` – Andrey B. Panfilov May 31 '23 at 14:16
  • Did you add `@EnableTransactionManagement` to your `@SpringBootApplication` class? Also, `TransactionSynchronizationManager` class belongs to `...reactive` package, so maybe you will need to define `ReactiveTransactionManager` bean, e.g. `org.springframework.data.mongodb.ReactiveMongoTransactionManager` – geobreze May 31 '23 at 14:16
  • @AndreyB.Panfilov Nope, it is not. It works as expected. – vvs14 Jun 01 '23 at 06:27
  • @geobreze Yes. `@EnableTransactionManagement` is added. – vvs14 Jun 01 '23 at 06:28