java - 使用 Lombok 和构造函数注入(inject) Spring 注入(inject) bean 为 null

标签 java spring spring-boot

我正在将使用 Spring 实现的 maven 项目迁移到 Spring Boot 1.5.20.RELEASE

我有一个适配器类,它将由所有用 @RestControllers 注释的类进行扩展,以保证与前端的向后兼容性

public class RestControllerAdapter {

    private MessageTemplate messageTemplate;

    private MessageTemplate getMessageTemplate() {

        if (messageTemplate == null) {
            messageTemplate = ApplicationContextUtils.getBean(MessageTemplate.class);
        }

        return messageTemplate;
    }

    protected final String message(@NonNull String code) {
        return getMessageTemplate().getMessage(code);
    }

    protected final String message(@NonNull String code, Object... args) {
        return getMessageTemplate().getMessage(code, args);
    }

    protected final ModelMap success() {
        val map = new ModelMap();
        map.put("success", true);
        map.put("message", getMessageTemplate().getMessage("message.success.default"));
        return map;
    }

    protected final ModelMap error(@NonNull String message) {
        val map = new ModelMap(2);
        map.put("success", false);
        map.put("error", message);
        return map;
    }

    protected final ModelMap retry(@NonNull Exception ex) {
        val map = new ModelMap(3);
        map.put("success", false);
        map.put("error", ex.getMessage());
        map.put("confirmar", true);
        return map;
    }

    protected final ModelMap empty() {
        return new ModelMap();
    }

    @ExceptionHandler(JpaSystemException.class)
    public ModelMap handleJpaSystemException(JpaSystemException ex) {
        log.error(ex.getMessage(), ex);
        return createError(ex.getMostSpecificCause());
    }

    @ExceptionHandler(DataIntegrityViolationException.class)
    public ModelMap handleDataIntegrityViolationException(DataIntegrityViolationException ex) {
        log.error(ex.getMessage(), ex);
        return createError(ex.getMostSpecificCause());
    }

    private ModelMap createError(Throwable ex) {
        val modelMap = new ModelMap();
        modelMap.put("error", translateErrorMessage(ex));
        modelMap.put("success", false);
        return modelMap;
    }

    protected String translateErrorMessage(@NonNull Throwable ex) {
        String message = ex.getLocalizedMessage().isEmpty() ? ex.getMessage() : ex.getLocalizedMessage();

        if (message.contains("12519")) {
            message = getMessageTemplate().getMessage("db.connection.error");
        } else if (message.contains("SYS_C0015328")) {
            message = getMessageTemplate().getMessage("plan.tasks.successors.sequence.error");
        } else if (message.contains("SYS_C0012415")) {
            message = getMessageTemplate().getMessage("positions.sequence.error");
        } else if (message.contains("SYS_C006343")) {
            message = getMessageTemplate().getMessage("documents.sequence.error");
        } else if (message.contains("UNIQUE_EMAIL")) {
            message = getMessageTemplate().getMessage("user.email.unique");
        } else if (message.contains("FK_PLTASK_TASK")) {
            message = getMessageTemplate().getMessage("task.delete.error");
        }

        return message;
    }
}

我有一个用于用户管理的休息 Controller 类

 @RestController
 @RequestMapping(value = "/usuario")
 @RequiredArgsConstructor
 public class UserRestController extends RestControllerAdapter {
    
   private final UserService usersService;
   private final UsersRepository usersRepository;
   private final UserBackupRepository userBackupRepository;
   private final AreaRepository areaRepository;
   private final PositionRepository positionRepository;
   private final UserMapper userMapper; 
         
   @PreAuthorize(value = SecurityUtils.ADMIN_EDIT_AUTHORITY)
   @PutMapping("/{userId}")
   public ModelMap update(@Valid @RequestBody UserCommand userCommand, 
                         @PathVariable int userId) {
       try {
           usersService.update(userId, userCommand);
           return success();
       } catch (DuplicateHolderException ex) {
           return retry(ex);
       }
   }
 
      @PreAuthorize(value = SecurityUtils.ADMIN_EDIT_AUTHORITY)
      @PostMapping("/activarUsuario")
      public ModelMap enable(@RequestParam("usuario_id") Integer id, 
                                     @AuthenticationPrincipal Users user) {
 
           if (user.getRol().getId() == 1 || user.getRol().getId() == 3) {
             usersService.enable(id);
             return success();
           }
 
           return empty();
     }
 
   @Override
   protected String translateErrorMessage(@NonNull Throwable ex) {
     String message = ex.getMessage();
 
     if (message.contains("correo_unico")) {
         message = "Ya este correo está asigado a un usuario.";
     } else if (message.contains("SYS_C0012422") || 
         message.contains("SYS_C0015349")) {
         message = "La secuencia de usuarios no está correctamente 
                                                               configurada.";
     } else if (message.contains("UNIQUE_BACKUP")) {
         message = "Un usuario no puede ser backup mas de una ocasión.";
     } else if (message.contains("UNIQUE_EMAIL")) {
         message = "No se puede insertar el usuario porque este correo ya 
           está en uso.";
     } else if (message.contains("FK_PLAN_USER_ACTIVADO")) {
         message = "No se puede insertar el usuario porque existe un plan que 
         ha sido activado por dicho usuario.";
     } else if (message.contains("FK_TASK_EXECUTED_BY")) {
         message = "No se puede insertar el usuario porque existen tareas 
         ejecutadas por dicho usuario.";
     }
 
     return super.translateErrorMessage(ex);
  }
 
 }

当调用 UserRestController::update 时,由于注入(inject)到 UserServiceImpl 的所有依赖项均为 null,因此会引发 NullPointerException,如图所示下面。

error

但是,当调用 UserRestController::enable 时,一切正常。两者都取决于 UserServiceImpl 的方法调用。

    @Service
    @RequiredArgsConstructor
    @Transactional(rollbackFor = Exception.class)
    class UserServiceImpl implements UserService {
    
        private static final int POSITION_USERS_LIMIT = 3;
        private static final int BACKUPS_LIMIT = 2;
        private static final String POSITION_LIMIT_ERROR = "user.position.limit";
        private static final String BACKUP_LIMIT_ERROR = "user.backup.limit";
    
        private final UsersRepository usersRepository;
        private final UserBackupRepository userBackupRepository;
        private final RolRepository rolRepository;
        private final PositionRepository positionRepository;
        private final PlanRepository planRepository;
        private final PlTaskRepository plTaskRepository;
        private final UserNotificationRepository userNotificationRepository;
        private final NotificacionBackupRepository notificacionBackupRepository;
        private final UserTokenRepository userTokenRepository;
        private final UserMapper userMapper;
        private final PasswordTemplate passwordTemplate;
        private final MessageTemplate messageTemplate;
    
           @Override
        public final Users update(int id, @NonNull UserCommand userCommand) {
            val user = usersRepository.findById(id)
                    .orElseThrow(() -> new IllegalArgumentException("Usuario a editar requerido"));
            val role = loadRoleFrom(userCommand);
            val newPosition = loadPositionFrom(userCommand);
    
            if (userCommand.isCheckConstraints()) {
                assertUserUpdate(userCommand, user, newPosition);
            }
    
            if (userCommand.isHolder()) {
    
                if (!user.isTitular() && usersRepository.existsByPositionAndTitularTrue(user.getPosition())) {
                    userBackupRepository.deleteAllByUsuarioPositionAndUsuarioTitularTrue(user.getPosition());
                    usersRepository.updateTitularFalse(user.getPosition());
                } else if (!user.hasPosition(newPosition) && usersRepository.existsByPositionAndTitularTrue(newPosition)) {
                    userBackupRepository.deleteAllByUsuarioPositionAndUsuarioTitularTrue(newPosition);
                    usersRepository.updateTitularFalse(newPosition);
                } else if (user.isTitular()) {
                    userBackupRepository.deleteAllByUsuarioPositionAndUsuarioTitularTrue(user.getPosition());
                }
            } else {
                userBackupRepository.deleteAllByUsuarioPositionAndUsuarioTitularTrue(user.getPosition());
            }
    
            user.setEmail(userCommand.getEmail());
            user.setUsuario(userCommand.getEmail());
            user.setName(userCommand.getName());
            user.setLastname(userCommand.getLastname());
            user.setActive(userCommand.isEnabled());
            user.setTitular(userCommand.isHolder());
            user.setPosition(newPosition);
            user.setRol(role);
    
            if (!StringUtils.isEmpty(userCommand.getPassword())) {
                user.setKeypass(passwordTemplate.encode(user.getPassword()));
            }
    
            usersRepository.save(user);
            addBackups(userCommand, user);
            return user;
        }
    
         @Override
        public Users enable(@NonNull Integer id) {
            val user = usersRepository.findById(id).orElseThrow(NoSuchElementException::new);
            user.setActive(!user.isActive());
            usersRepository.save(user);
            return user;
        }    
    }

这个错误快要了我的命,这是一种奇怪的行为。

最佳答案

终于解决了这个问题。

UserServiceImpl::update方法中的final关键字相关

它不允许注入(inject)过程正常工作,而且这是完全有意义的,因为用 @Transactional 注释的类不能是 final

我已经删除了它,现在一切正常。示例代码为here

关于java - 使用 Lombok 和构造函数注入(inject) Spring 注入(inject) bean 为 null,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56483269/

相关文章:

spring-boot - 如何使 Redis 存储库具有事务性

java - 发布到 Spring Controller 给出 404 Bad Request

java - 使用 AmqpAppender for log4j 需要什么依赖项?

java - Spring Data JPA 中查询关键字 Containing、IsContaining、Contains、Like 之间的区别

JavaFX ComboBox 在使用箭头键时自动填充编辑器文本

spring - 想要在 JHipster 中创建 URL

java - 返回包含信息的 ResponseEntity

java - 使用 Java 8 的整数列表的总和

java - 从 CodeName One for Java 中的 TextField 获取文本

java - 我们可以不使用 final 关键字来避免继承吗?