2017-11-30 4 views
0

Ich versuche, eine Spring-Data-Rest-App mit Spring Boot 1.5.9.RELEASE einrichten. Ich habe ein ConstraintValidator wie diese ein:@Autowired Repository in ConstraintValidator null, wenn von CommandLineRunner verwendet

UniqueEmail.java:

import javax.validation.Constraint; 
import javax.validation.Payload; 
import javax.validation.ReportAsSingleViolation; 
import javax.validation.constraints.NotNull; 
import java.lang.annotation.*; 

@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER}) 
@Retention(RetentionPolicy.RUNTIME) 
@Documented 
@Constraint(validatedBy = {UniqueEmailValidator.class}) 
@NotNull 
@ReportAsSingleViolation 
public @interface UniqueEmail { 

    Class<?>[] groups() default {}; 

    String message() default "{eu.icarus.momca.backend.domain.validation.UniqueEmail.message}"; 

    Class<? extends Payload>[] payload() default {}; 

    @Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER}) 
    @Retention(RetentionPolicy.RUNTIME) 
    @Documented 
    static @interface List { 
     UniqueEmail[] value(); 
    } 

} 

UniqueEmailValidator.java:

import eu.icarus.momca.backend.domain.repository.AccountRepository; 
import org.springframework.beans.factory.annotation.Autowired; 

import javax.validation.ConstraintValidator; 
import javax.validation.ConstraintValidatorContext; 

public class UniqueEmailValidator implements ConstraintValidator<UniqueEmail, String> { 

    @Autowired 
    private AccountRepository accountRepository; 

    @Override 
    public void initialize(UniqueEmail annotation) { 
    } 

    @Override 
    public boolean isValid(String email, ConstraintValidatorContext context) { 
     return accountRepository.findByEmail(email) == null; 
    } 

} 

Ich habe auch Listener für die beforeCreate und beforeSave Repository Methoden ein:

RestConfiguration.java:

import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.context.annotation.Primary; 
import org.springframework.data.rest.core.event.ValidatingRepositoryEventListener; 
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter; 
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; 

@Configuration 
public class RestConfiguration extends RepositoryRestConfigurerAdapter { 

    @Override 
    public void configureValidatingRepositoryEventListener(ValidatingRepositoryEventListener validatingListener) { 
     validatingListener.addValidator("beforeCreate", localValidatorFactoryBean()); 
     validatingListener.addValidator("beforeSave", localValidatorFactoryBean()); 
    } 

    @Bean 
    @Primary 
    LocalValidatorFactoryBean localValidatorFactoryBean() { 
     return new LocalValidatorFactoryBean(); 
    } 

} 

Mein Problem:

Der Validator scheint zu funktionieren, wenn die Repository-Methoden durch REST-Endpunkte genannt werden, jedoch über ein CommandLineRunner ein paar Sachen in der angeschlossenen Datenbank einzurichten Ich versuche auch, die gleich verwendet Repository. Wenn die Aufrufe an das Repository validiert werden, ist der Autowired AccountRepository im ConstraintValidatornull, auch wenn es nicht gleichzeitig im CommandLineRunner null ist, das auch dasselbe Repository autowired hat. Ich verstehe das nicht.

Hat jemand eine Idee, warum das Repository null ist, wenn die Validierung vom CommandLineRunner ausgelöst wird?

Jede Hilfe wird sehr geschätzt. Daniel

Edit: hat die CommandLineRunner-Code

InitAdminData.java:

import eu.icarus.momca.backend.domain.entity.Account; 
import eu.icarus.momca.backend.domain.entity.AccountDetails; 
import eu.icarus.momca.backend.domain.entity.AccountProfile; 
import eu.icarus.momca.backend.domain.entity.Client; 
import eu.icarus.momca.backend.domain.enumeration.AccountRoles; 
import eu.icarus.momca.backend.domain.enumeration.ClientRoles; 
import eu.icarus.momca.backend.domain.enumeration.GrantTypes; 
import eu.icarus.momca.backend.domain.repository.AccountRepository; 
import eu.icarus.momca.backend.domain.repository.ClientRepository; 
import eu.icarus.momca.backend.domain.service.AccountService; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.beans.factory.annotation.Value; 
import org.springframework.boot.CommandLineRunner; 
import org.springframework.stereotype.Component; 

import java.util.Arrays; 
import java.util.Collection; 
import java.util.HashSet; 

@Component 
public class InitAdminData implements CommandLineRunner { 

    private static final Collection<AccountRoles> DEFAULT_ACCOUNT_ROLES = Arrays.asList(AccountRoles.ROLE_ACCOUNT, AccountRoles.ROLE_ADMINISTRATOR, AccountRoles.ROLE_CLIENT_OWNER); 

    private static final Logger logger = LoggerFactory.getLogger(InitAdminData.class); 

    private AccountRepository accountRepository; 

    private AccountService accountService; 

    @Value("${app.admin-email}") 
    private String adminEmail; 

    @Value("${app.admin-name}") 
    private String adminName; 

    @Value("${app.admin-password}") 
    private String adminPassword; 

    private ClientRepository clientRepository; 

    @Value("${app.default-client-description}") 
    private String defaultClientDescription; 

    @Autowired 
    public InitAdminData(AccountRepository accountRepository, AccountService accountService, ClientRepository clientRepository) { 
     this.accountRepository = accountRepository; 
     this.clientRepository = clientRepository; 
     this.accountService = accountService; 
    } 

    private Account initAdminAccount() { 
     Account adminAccount = accountRepository.findByAccountProfile_Name(adminName); 
     if (adminAccount == null) { 
      adminAccount = new Account(); 
      logger.info("Initialized new admin account"); 
     } else { 
      logger.info("Refreshed admin account"); 
     } 
     setAdminAccountData(adminAccount); 
     return accountService.save(adminAccount, adminPassword); 
    } 

    private void initDefaultClient(Account adminAccount) { 
     long adminAccountId = adminAccount.getId(); 
     Collection<Client> adminClients = clientRepository.findAllByOwnerId(adminAccountId); 
     if (adminClients.isEmpty()) { 
      Client defaultClient = new Client(); 
      defaultClient.setOwnerId(adminAccountId); 
      defaultClient.setDescription(defaultClientDescription); 
      Collection<ClientRoles> clientRoles = new HashSet<>(2); 
      clientRoles.add(ClientRoles.ROLE_CLIENT); 
      clientRoles.add(ClientRoles.ROLE_DEFAULT_CLIENT); 
      defaultClient.setRoles(clientRoles); 
      Collection<GrantTypes> grantTypes = new HashSet<>(); 
      grantTypes.add(GrantTypes.authorization_code); 
      grantTypes.add(GrantTypes.client_credentials); 
      grantTypes.add(GrantTypes.password); 
      grantTypes.add(GrantTypes.refresh_token); 
      defaultClient.setGrantTypes(grantTypes); 
      defaultClient = clientRepository.save(defaultClient); 
      logger.info(String.format("Added new default client with id '%s'", defaultClient.getId())); 
     } 
    } 

    @Override 
    public void run(String... args) { 
     Account adminAccount = initAdminAccount(); 
     initDefaultClient(adminAccount); 
    } 

    private void setAdminAccountData(Account adminAccount) { 
     adminAccount.setEmail(adminEmail); 
     adminAccount.setRoles(DEFAULT_ACCOUNT_ROLES); 
     adminAccount.setAccountDetails(new AccountDetails()); 
     adminAccount.setAccountProfile(new AccountProfile(adminName)); 
    } 

} 
+0

wie die Komponenten Sieht aus, wo beim Start nicht initialisiert, wenn die CommandLineRunner verwenden. Bitte versuchen Sie, die Klasse, die mit dem CommandLineRunner gestartet wurde, mit '@ ComponentScan' zu kommentieren. – alltej

+0

Bitte teilen Sie Ihren Code/Klasse, die mit dem CommandLineRunner gestartet wurde – alltej

+0

Danke für Ihre Antwort @alltej! Ich habe die Frage bearbeitet, um den CommandLineRunner hinzuzufügen. – yngwi

Antwort

0

Fügen Sie die @ComponentScan Anmerkung.

@ComponentScan 
public class InitAdminData implements CommandLineRunner { 
... 
} 
+0

Hallo, danke für die Antwort, aber es scheint nicht zu funktionieren. Das Ersetzen von '@ Component' durch' @ ComponentScan' bewirkt, dass es nicht durch den Spring-Boot-Vorgang aufgerufen wird und dass das Hinzufügen von '@ Component' zusätzlich dazu führt, dass es sich wie zuvor verhält. – yngwi

+0

Können Sie beide Anmerkungen hinzufügen/haben und sehen, ob es funktioniert? – alltej

+0

tat ich. Es scheint keinen Unterschied zu geben. – yngwi

0

Ich glaube, Sie einige Fälle haben: -

  1. Sie Ihren Service und Repo nicht autowired
  2. Sie nicht scannen Sie Ihren Repo, wo Sie Ihren Service und Repo haben.
  3. Oder Sie haben nicht @Component (jedes Klischee) Anmerkung auf Ihre Klassen verwenden, die Sie autowiring
+0

Hallo, außerhalb des CommandLineRunner sind der Service und das Repository gut aufgehoben, es scheint nur so, als ob der Anwendungskontext im Kommandozeilen-Runner irgendwie anders ist. Ich habe auch gerade gemerkt, dass Ereignisse wie '@ HandleBeforeSave' nicht während des Befehlszeilenlaufwerks ausgelöst zu werden scheinen, aber nach dem Startvorgang gut funktionieren. Ich würde gerne wissen, warum das so ist. – yngwi

Verwandte Themen