Spring Data JPA - Repositories werden nicht injected

shortys

Mitglied
Hallo zusammen,
ich habe das Problem, dass meine Entity-Repositories nicht injected werden.
Diese sind mit @Resource annotiert:

Java:
@Repository
public class BudgetService implements IBudgetService {

	@Resource
	private IAccountRepository accountRepository;

	@Resource
	private IEntryRepository entryRepository;

Beide Repositories sind JpaRepositories:

Java:
public interface IAccountRepository extends JpaRepository<Account, Long> {

	Account findByAccountNumber(String accountNumber);

}

Java:
public interface IEntryRepository extends JpaRepository<Entry, Long> {

}

Meine Konfiguration sieht wie folgt aus:

Java:
@Configuration
@ComponentScan(basePackages = "org.houseoffice.budget.model")
@ImportResource(value = "classpath:org/houseoffice/budget/config/spring-context.xml")
public class ApplicationConfig {

	@Bean
	public LocalContainerEntityManagerFactoryBean emf(final DataSource dataSource) {
		final LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
		emf.setDataSource(dataSource);
		emf.setJpaDialect(new HibernateJpaDialect());
		emf.setJpaVendorAdapter(jpaVendorAdapter());
		emf.setPersistenceUnitManager(null);
		emf.setPackagesToScan("org.houseoffice.budget.model.entities");
		return emf;
	}

	@Bean
	public JpaVendorAdapter jpaVendorAdapter() {
		final HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
		jpaVendorAdapter.setShowSql(true);
		jpaVendorAdapter.setDatabase(Database.HSQL);
		jpaVendorAdapter.setGenerateDdl(true);
		return jpaVendorAdapter;
	}

	@Bean
	public JpaTransactionManager transactionManager(final EntityManagerFactory emf) {
		return new JpaTransactionManager(emf);
	}

}

Hier noch der importierte Spring-Context:

[XML]<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd Index of /schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd Index of /schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.0.xsd">
<!-- HSQLDB Configuration -->
<bean id="embeddedDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url" value="jdbc:hsqldb:file:database/data" />
<property name="username" value="SA" />
<property name="password" value="" />
</bean>

<!-- Base packages for JpaRepositories -->
<jpa:repositories base-package="org.houseoffice.budget.model.repositories" />
</beans>
[/XML]

Kann mir vielleicht jemand weiterhelfen. Google hat das bisher leider nicht getan.
Ich wäre sehr dankbar.

Gruß
Patrick
 
Soweit ich weiß injiziert @Resource by-name (siehe hier). Deine Repository-Instanzen heißen aber dank eures I-Präfix eben iAccountRepository. Ich vermute deshalb gibt es da keinen Match. Hast du mal @Autowired oder @Inject versucht?

Ein paar grundsätzliche Hinweise bzw. ein paar Fragen zum Setup noch:

1. Gibt es einen Grund warum du XML und JavaConfig verwendest? Repositories kannst du mit @EnableJpaRepositories aktivieren und die DataSource könntest du auch bequem als @Bean definieren. Bei einem Konfigurationsstil zu bleiben erhöht die Konsistenz und damit die Erschließbarkeit des Codes.
2. Sollte dein Service nicht mit @Service annotiert sein? Ich vermute @Repository an einem Service stiftet Verwirrung.
3. Wir empfehlen eigentlich immer auf JpaRepository zu verzichten und stattdessen PagingAndSortingRepository oder ein anderes Super-Interface zu verwenden um zu vermeiden, dass der Client persistenztechnologiespezifische Typen und Methoden zu sehen bekommt.

Gruß
Ollie
 
Zuletzt bearbeitet:
Erstmal vielen Dank Ollie!

Ich habe einen JUnit - Test der Funktioniert und das ergibt für mich leider keinen Sinn.
Java:
@ContextConfiguration(classes = { ApplicationConfig.class })
public class ApplicationConfigTest extends AbstractJUnit4SpringContextTests {

	@Resource
	private IAccountRepository accountRepository;
	@Resource
	private IEntryRepository entryRepository;

	@Test
	public void saveAndDeleteBook() {
		Assert.assertThat(this.accountRepository.findAll().isEmpty(), is(true));
		final Account account = new Account();
		account.setAccountNumber("testAccountNumber");
		this.accountRepository.save(account);
		Assert.assertThat(this.accountRepository.findAll().isEmpty(), is(false));
		Assert.assertThat(this.accountRepository.exists(account.getId()), is(true));
		this.accountRepository.delete(account);
		Assert.assertThat(this.accountRepository.findAll().isEmpty(), is(true));
	}

	@Test
	public void testBootstrap() {
		Assert.assertThat(this.accountRepository, is(notNullValue()));
	}

	@Test
	public void testEntries() {
		final Account account = new Account();
		account.setAccountNumber("testAccountNumber");

		final Entry entry = new Entry();
		entry.setValue(12.5);
		this.entryRepository.save(entry);

		account.getEntries().add(entry);
		this.accountRepository.save(account);

		final Entry secondEntry = new Entry();
		this.entryRepository.save(secondEntry);
		account.getEntries().add(secondEntry);
		Assert.assertThat(this.accountRepository.findByAccountNumber("testAccountNumber").getEntries().size(), is(1));
		this.accountRepository.save(account);
		Assert.assertThat(this.accountRepository.findByAccountNumber("testAccountNumber").getEntries().size(), is(2));
		this.accountRepository.delete(account);
		this.entryRepository.delete(entry);
		this.entryRepository.delete(secondEntry);
	}

	@Test
	public void testFindByAccountNumber() {
		final Account account = new Account();
		account.setAccountNumber("testAccountNumber");
		this.accountRepository.save(account);
		Assert.assertThat(this.accountRepository.findByAccountNumber("notExistingAccountNumber"), is(nullValue()));
		Assert.assertThat(this.accountRepository.findByAccountNumber("testAccountNumber"), is(equalTo(account)));
		this.accountRepository.delete(account);
	}

Zu deinen Hinweisen:
1. Der Grund is recht simple. Ich hab eines der Tutorials, die ich gefunden habe, umgesetzt 😉
2. Ah ja, das ist ein Versuch gewesen, da mich die @Service Annotation leider nicht weiter gebracht hat :/
3. Die einzige Methode, die nicht auch durch das CRUD-Repo zur Verfügung gestellt wird ist saveAndFlush(). Also da sehe ich nicht wirklich den Grund deswegen auf eine findAll-Methode zu verzichten die direkt eine List anstatt eines Iterable zurück gibt.

Gruß
Patrick
 

Zurück
Oben