简体   繁体   中英

Java unchecked exception thrown by lambda is not caught

I have a function that takes two lambdas as a parameters. These functions throw a specific unchecked exception that I want the function to catch:

    /**
     *
     * @param insert function to insert the entity
     * @param fetch function to fetch the entity
     * @param <T> type of entity being inserted
     * @return
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_COMMITTED)
    public <T> T getOrInsertWithUniqueConstraints(Supplier<Optional<T>> fetch, Supplier<T> insert) {
        try {
            Optional<T> entity = fetch.get();
            T insertedEntity = entity.orElseGet(insert);
            return insertedEntity;
        }
        catch (Exception e){
            //I expect/want the exception to be caught here, 
            //but this code is never called when debugging
            Optional<T> entityAlreadyInserted = fetch.get();
            return entityAlreadyInserted.get();
        }
    }

Which is called in a function belonging to another transaction:

@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
...
try {
    Player persistedPlayer = insertOrGetUtil.getOrInsertWithUniqueConstraints(
        () -> playerRepository.findOne(newPlayer.getUsername()),
        //this lambda throws the unchecked DataIntegrityViolationException
        () -> playerRepository.save(newPlayer)
    );
}
catch (Exception e){
    //the exception is caught here for some reason...
}

Am I misunderstanding how Java lambdas work? Also worth noting is the code is using Spring's @Transactional and CrudRepository

The exception is actually happening while the transaction is being committed, which occurs after the method returns. To get around this, I used EntityManager#flush() to trigger any exceptions that would happen on commit before the method returns:

    @Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_COMMITTED)
    public <T> T getOrInsertWithUniqueConstraints(Supplier<Optional<T>> fetch, Supplier<T> insert) {
        try {
            Optional<T> entity = fetch.get();
            T insertedEntity = entity.orElseGet(insert);
            entityManager.flush();
            return insertedEntity;
        }
        catch (PersistenceException e){
            DataAccessException dae = persistenceExceptionTranslator.translateExceptionIfPossible(e);
            if (dae instanceof DataIntegrityViolationException){
                Optional<T> entityAlreadyInserted = fetch.get();
                return entityAlreadyInserted.get();
            }
            else {
                throw e;
            }
        }
    }

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