简体   繁体   中英

Hibernate LazyInitializationException if entity is fetched in JWTAuthorizationFilter

I'm using Spring Rest. I have an Entity called Operator that goes like this:

@Entity
@Table(name = "operators")
public class Operator {

    //various properties

    private List<OperatorRole> operatorRoles;

    //various getters and setters

    @LazyCollection(LazyCollectionOption.TRUE)
    @OneToMany(mappedBy = "operator", cascade = CascadeType.ALL)
    public List<OperatorRole> getOperatorRoles() {
        return operatorRoles;
    }

    public void setOperatorRoles(List<OperatorRole> operatorRoles) {
        this.operatorRoles = operatorRoles;
    }
}

I also have the corresponding OperatorRepository extends JpaRepository
I defined a controller that exposes this API:

@RestController
@RequestMapping("/api/operators")
public class OperatorController{

    private final OperatorRepository operatorRepository;

    @Autowired
    public OperatorController(OperatorRepository operatorRepository) {
        this.operatorRepository = operatorRepository;
    }

    @GetMapping(value = "/myApi")
    @Transactional(readOnly = true)
    public MyResponseBody myApi(@ApiIgnore @AuthorizedConsumer Operator operator){

        if(operator.getOperatorRoles()!=null) {
            for (OperatorRole current : operator.getOperatorRoles()) {
                //do things
            }
        }

    }
}

This used to work before I made the OperatorRoles list lazy; now if I try to iterate through the list it throws LazyInitializationException.
The Operator parameter is fetched from the DB by a filter that extends Spring's BasicAuthenticationFilter, and is then somehow autowired into the API call.
I can get other, non-lazy initialized, properties without problem. If i do something like operator = operatorRepository.getOne(operator.getId()); , everything works, but I would need to change this in too many points in the code.
From what I understand, the problem is that the session used to fetch the Operator in the BasicAuthenticationFilter is no longer open by the time i reach the actual API in OperatorController.
I managed to wrap everything in a OpenSessionInViewFilter, but it still doesn't work.
Anyone has any ideas?

I was having this very same problem for a long time and was using FetchType.EAGER but today something has clicked in my head ...

@Transactional didn't work so I thought "if declarative transactions don't work? Maybe programmatically do" And they do!

Based on Spring Programmatic Transactions docs :

public class JwtAuthorizationFilter extends BasicAuthenticationFilter {        
    
    private final TransactionTemplate transactionTemplate;

    public JwtAuthorizationFilter(AuthenticationManager authenticationManager,
                                  PlatformTransactionManager transactionManager) {
        super(authenticationManager);
        this.transactionTemplate = new TransactionTemplate(transactionManager);
        
        // Set your desired propagation behavior, isolation level, readOnly, etc.
        this.transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
    }

    private void doSomething() {
        transactionTemplate.execute(transactionStatus -> {
            // execute your queries
        });
    }

}

It could be late for you, but I hope it helps others.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM