How do I wire a (subclass/subinterface) of JpaRepository via Xml configuration?
So I have an "implementation" of JpaRepository
import org.springframework.data.jpa.repository.JpaRepository;
import java.time.OffsetDateTime;
import java.util.Collection;
import java.util.Optional;
public interface MyDepartmentJpaRepo extends JpaRepository<Department, Long> {
/* "lookup strategy". see https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods */
Optional<Department> findDepartmentByDepartmentNameEquals(String departmentName);
Collection<Department> findByCreateOffsetDateTimeBefore(OffsetDateTime zdt);
}
and the entity
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import java.time.OffsetDateTime;
@Entity
@Table(name = "DepartmentTable")
public class Department {
@Id
@Column(name = "DepartmentKey", unique = true)
@GeneratedValue(strategy = GenerationType.AUTO)
private long departmentKey;
@Column(name = "DepartmentName", unique = true)
private String departmentName;
@Column(name = "CreateOffsetDateTime", columnDefinition = "TIMESTAMP WITH TIME ZONE" )
private OffsetDateTime createOffsetDateTime;
public long getDepartmentKey() {
return departmentKey;
}
public void setDepartmentKey(long departmentKey) {
this.departmentKey = departmentKey;
}
public String getDepartmentName() {
return departmentName;
}
public void setDepartmentName(String departmentName) {
this.departmentName = departmentName;
}
public OffsetDateTime getCreateOffsetDateTime() {
return createOffsetDateTime;
}
public void setCreateOffsetDateTime(OffsetDateTime createOffsetDateTime) {
this.createOffsetDateTime = createOffsetDateTime;
}
}
and a class where I need to inject the MyDepartmentJpaRepo
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import java.time.OffsetDateTime;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
public class DepartmentManager implements IDepartmentManager {
private final Logger logger;
private final MyDepartmentJpaRepo deptRepo;
/* The Inject annotation marks which constructor to use for IoC when there are multiple constructors */
@Inject
public DepartmentManager(MyDepartmentJpaRepo deptRepo) {
this(LoggerFactory.getLogger(DepartmentManager.class), deptRepo);
}
public DepartmentManager(Logger lgr, MyDepartmentJpaRepo deptRepo) {
if (null == lgr) {
throw new IllegalArgumentException("Logger is null");
}
if (null == deptRepo) {
throw new IllegalArgumentException("IDepartmentDomainData is null");
}
this.logger = lgr;
this.deptRepo = deptRepo;
}
@Override
public Collection<Department> getAll() {
List<Department> returnItems = this.deptRepo.findAll();
return returnItems;
}
@Override
public Optional<Department> getSingle(long key) {
Optional<Department> returnItem = this.deptRepo.findById(key);
return returnItem;
}
@Override
public Optional<Department> getSingleByName(String deptName) {
Optional<Department> returnItem = this.deptRepo.findDepartmentByDepartmentNameEquals(deptName);
return returnItem;
}
public Collection<Department> getDepartmentsOlderThanDate(OffsetDateTime zdt)
{
Collection<Department> returnItems = this.deptRepo.findByCreateOffsetDateTimeBefore(zdt);
return returnItems;
}
@Override
public Department save(Department item) {
Department returnItem = this.deptRepo.save(item);
return returnItem;
}
}
and the interface of the "manager" for completeness.
import java.time.OffsetDateTime;
import java.util.Collection;
import java.util.Optional;
public interface IDepartmentManager {
Collection<Department> getAll();
Optional<Department> getSingle(long key);
Optional<Department> getSingleByName(String deptName);
Department save(Department item);
Collection<Department> getDepartmentsOlderThanDate(OffsetDateTime zdt);
}
The issue is in the applicationcontext.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="jpaSetup.di.xml"/>
<bean id="MyDepartmentJpaRepoBean" class="com.mycompany.blah.blah.blah.MyDepartmentJpaRepo">
</bean>
<bean id="IDepartmentManagerBean" class="com.mycompany.blah.blah.blah.DepartmentManager">
<constructor-arg ref="MyDepartmentJpaRepoBean"/>
</bean>
</beans>
So..the spring-boot-data makes one define the (sub-interfaced JpaRepository) AS AN INTERFACE
interface MyDepartmentJpaRepo extends JpaRepository<Department, Long>
So when you try to xml-define the IoC/DI..you get "interface not allowed for non-abtract beans".
This looks like a catch-22 ...... :(
The magic question:
How does one use xml-config for IoC/DI...................and take advantage of a sub-interfaced JpaRepository ????
APPEND:
If I add in "jpa:repositories", then I don't have a constructor-arg for the "manager".
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/data/jpa https://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<import resource="jpaSetup.di.xml"/>
<jpa:repositories base-package="com.mycompany.blah.blah.blah" />
--> -->
<bean id="IDepartmentManagerBean" class="com.mycompany.organizationdemo.businesslayer.managers.DepartmentManager">
<constructor-arg ref="NotDoesNotExistMyDepartmentJpaRepoBean"/> <!-- DOES NOT WORK -->
</bean>
..................
other files below for completeness.
jpaSetup.di.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<beans>
<bean id="myLocalContainerEntityManagerFactoryBeanBean"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="com.blah.blah.blah.entities"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="${spring.jpa.show-sql}"/>
<property name="generateDdl" value="${spring.jpa.generate-ddl}"/>
</bean>
</property>
<!-- See https://stackoverflow.com/questions/16088112/how-to-auto-detect-entities-in-jpa-2-0/16088340#16088340 -->
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">${spring.jpa.hibernate.ddl-auto}</prop>
<prop key="hibernate.dialect">${spring.jpa.properties.hibernate.dialect}</prop>
</props>
</property>
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="${SPRING_DATASOURCE_URL}"/>
<property name="username" value="${SPRING_DATASOURCE_USERNAME}"/>
<property name="password" value="${SPRING_DATASOURCE_PASSWORD}"/>
<property name="driverClassName" value="${SPRING_DATASOURCE_DRIVER-CLASS-NAME}"/>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="myLocalContainerEntityManagerFactoryBeanBean"/>
</bean>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
<bean id="persistenceExceptionTranslationPostProcessor" class=
"org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
</beans>
</beans>
and application.yml
spring:
jpa:
generate-ddl: true
show-sql: true
hibernate:
ddl-auto: update
naming_strategy: org.hibernate.cfg.ImprovedNamingStrategy
properties:
hibernate:
dialect: org.hibernate.dialect.H2Dialect
datasource:
url: ${SPRING_DATASOURCE_URL}
username: ${SPRING_DATASOURCE_USERNAME}
password: ${SPRING_DATASOURCE_PASSWORD}
driverClassName: ${SPRING_DATASOURCE_DRIVER-CLASS-NAME}