Hello StackOverflow Community,
Attempted:
Accessing CriteriaQuery multiselect custom query via Spring Data REST
application.properties
spring.application.name=demo-app
db1.url=jdbc:sqlserver://localhost;databaseName=db1;encrypt=false
db1.username=admin
db1.password=admin
db2.url=jdbc:sqlserver://localhost;databaseName=db2;encrypt=false
db2.username=admin
db2.password=admin
# Spring JPA - These are logged to the console but not to log file
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.use_sql_comments=false
spring.jpa.properties.hibernate.id.new_generator_mappings=false
# Log levels
logging.level.ca=DEBUG
#logging.level.org.springframework=DEBUG
#logging.level.org.springframework.http=DEBUG
#logging.level.org.springframework.web=DEBUG
#logging.level.org.springframework.security=DEBUG
# Hibernate - These are logged to console & log file
logging.level.org.hibernate.SQL=DEBUG
#logging.level.org.hibernate.type.descriptor.sql=TRACE
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
#logging.level.org.springframework.jdbc.core.JdbcTemplate=DEBUG
#logging.level.org.springframework.jdbc.core.StatementCreatorUtils=TRACE
#logging.level.org.springframework.boot.autoconfigure=DEBUG
# Spring Data REST
spring.data.rest.base-path=/api
# Logging
logging.file.name=logs/app.log
pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<java.version>21</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
Config
DataSourceConfig.java (DB1)
package ca.demo.db1;
import java.util.HashMap;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
@Configuration(value = "ca.demo.db1.DataSourceConfig")
@EnableJpaRepositories( //
basePackages = { "ca.demo.db1" }, //
entityManagerFactoryRef = "db1EntityManagerFactory", //
transactionManagerRef = "db1TransactionManager" //
)
public class DataSourceConfig {
@Autowired
private Environment env;
@Bean
@Primary
DataSource db1Datasource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl(env.getProperty("db1.url"));
dataSource.setUsername(env.getProperty("db1.username"));
dataSource.setPassword(env.getProperty("db1.password"));
return dataSource;
}
@Bean
@Primary
LocalContainerEntityManagerFactoryBean db1EntityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(db1Datasource());
em.setPackagesToScan(new String[] { "ca.demo.db1" });
em.setPersistenceUnitName("db1EntityManagerFactory");
HashMap<String, String> properties = new HashMap<String, String>();
properties.put("hibernate.hbm2ddl.auto", env.getProperty("spring.jpa.hibernate.ddl-auto"));
properties.put("hibernate.show_sql", env.getProperty("spring.jpa.show-sql"));
properties.put("hibernate.format_sql", env.getProperty("spring.jpa.properties.hibernate.format_sql"));
properties.put("hibernate.use_sql_comments",
env.getProperty("spring.jpa.properties.hibernate.use_sql_comments"));
properties.put("hibernate.enable_lazy_load_no_trans",
env.getProperty("spring.jpa.properties.hibernate.enable_lazy_load_no_trans"));
properties.put("hibernate.id.new_generator_mappings",
env.getProperty("spring.jpa.properties.hibernate.id.new_generator_mappings"));
properties.put("org.hibernate.envers.audit_table_suffix", "_aud");
em.setJpaPropertyMap(properties);
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
return em;
}
@Bean
@Primary
PlatformTransactionManager db1TransactionManager() {
return new JpaTransactionManager(db1EntityManagerFactory().getObject());
}
}
DataSourceConfig.java (DB2)
package ca.demo.db2;
import java.util.HashMap;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
@Configuration(value = "ca.demo.db2.DataSourceConfig")
@EnableJpaRepositories( //
basePackages = { "ca.demo.db2" }, //
entityManagerFactoryRef = "db2EntityManagerFactory", //
transactionManagerRef = "db2TransactionManager" //
)
public class DataSourceConfig {
@Autowired
private Environment env;
@Bean
DataSource db2Datasource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl(env.getProperty("db2.url"));
dataSource.setUsername(env.getProperty("db2.username"));
dataSource.setPassword(env.getProperty("db2.password"));
return dataSource;
}
@Bean
LocalContainerEntityManagerFactoryBean db2EntityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(db2Datasource());
em.setPackagesToScan(new String[] { "ca.demo.db2" });
em.setPersistenceUnitName("db2EntityManagerFactory");
HashMap<String, String> properties = new HashMap<String, String>();
properties.put("hibernate.hbm2ddl.auto", env.getProperty("spring.jpa.hibernate.ddl-auto"));
properties.put("hibernate.show_sql", env.getProperty("spring.jpa.show-sql"));
properties.put("hibernate.format_sql", env.getProperty("spring.jpa.properties.hibernate.format_sql"));
properties.put("hibernate.use_sql_comments",
env.getProperty("spring.jpa.properties.hibernate.use_sql_comments"));
properties.put("hibernate.enable_lazy_load_no_trans",
env.getProperty("spring.jpa.properties.hibernate.enable_lazy_load_no_trans"));
properties.put("hibernate.id.new_generator_mappings",
env.getProperty("spring.jpa.properties.hibernate.id.new_generator_mappings"));
properties.put("org.hibernate.envers.audit_table_suffix", "_aud");
em.setJpaPropertyMap(properties);
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
return em;
}
@Bean
PlatformTransactionManager db2TransactionManager() {
return new JpaTransactionManager(db2EntityManagerFactory().getObject());
}
}
Entity
Fruit.java
package ca.demo.db1.model;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@Entity
public class Fruit {
@Id
@GeneratedValue(strategy = GenerationType.UUID)
String uuid;
String name;
}
Repository
FruitRepository.java
package ca.demo.db1.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import org.springframework.stereotype.Repository;
import ca.demo.db1.model.Fruit;
@Repository
@RepositoryRestResource(exported = true, collectionResourceRel = "fruit", path = "fruit")
public interface FruitRepository extends JpaRepository<Fruit, String>, FruitRepositoryCustom {
}
FruitRepositoryCustom.java
package ca.demo.db1.repository;
import java.util.List;
import ca.demo.db1.model.recomposition.RFruit;
public interface FruitRepositoryCustom {
List<RFruit> getByParams();
}
FruitRepositoryCustomImpl.java
package ca.demo.db1.repository.impl;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import ca.demo.db1.model.Fruit;
import ca.demo.db1.model.recomposition.RFruit;
import ca.demo.db1.repository.FruitRepositoryCustom;
import jakarta.persistence.EntityManager;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
public class FruitRepositoryCustomImpl implements FruitRepositoryCustom {
private static final Logger logger = LoggerFactory.getLogger(FruitRepositoryCustomImpl.class);
@Autowired
EntityManager em;
@Override
public List<RFruit> getByParams() {
logger.debug(">> search()");
List<String> log = new ArrayList<String>();
// Build search query
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<RFruit> cq = cb.createQuery(RFruit.class);
Root<Fruit> r = cq.from(Fruit.class);
List<Predicate> predicates = new ArrayList<Predicate>();
// Logging search parameters
logger.debug("-- search parameters: " + String.join(", ", log));
// Perform query and get result
cq.multiselect(//
r.get("name") //
);
cq.where(cb.and(predicates.toArray(new Predicate[] {})));
// Execute
List<RFruit> fruits = em.createQuery(cq).setMaxResults(1000).getResultList();
logger.debug("-- size - " + fruits.size());
logger.debug("<< search()");
return fruits;
}
}
Recomposition
RFruit.java
package ca.demo.db1.model.recomposition;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class RFruit {
String name;
}
Issue:
When accessing ‘http://localhost:8080/api/fruit/search/getByParams’ gives the error,
2024-09-12T14:39:41.839-04:00 DEBUG 4332 --- [demo-app] [http-nio-8080-exec-2] c.d.d.r.impl.FruitRepositoryCustomImpl : >> search()
2024-09-12T14:39:41.857-04:00 DEBUG 4332 --- [demo-app] [http-nio-8080-exec-2] c.d.d.r.impl.FruitRepositoryCustomImpl : -- search parameters:
2024-09-12T14:39:41.999-04:00 DEBUG 4332 --- [demo-app] [http-nio-8080-exec-2] org.hibernate.SQL :
select
top (?) f1_0.name
from
Fruit f1_0
where
1=1
2024-09-12T14:39:42.021-04:00 DEBUG 4332 --- [demo-app] [http-nio-8080-exec-2] c.d.d.r.impl.FruitRepositoryCustomImpl : -- size - 10
2024-09-12T14:39:42.021-04:00 DEBUG 4332 --- [demo-app] [http-nio-8080-exec-2] c.d.d.r.impl.FruitRepositoryCustomImpl : << search()
2024-09-12T14:39:42.029-04:00 ERROR 4332 --- [demo-app] [http-nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: org.springframework.data.mapping.MappingException: Couldn't find PersistentEntity for type class ca.demo.db1.model.recomposition.RFruit] with root cause
org.springframework.data.mapping.MappingException: Couldn't find PersistentEntity for type class ca.demo.db1.model.recomposition.RFruit
at org.springframework.data.mapping.context.MappingContext.getRequiredPersistentEntity(MappingContext.java:80) ~[spring-data-commons-3.3.3.jar:3.3.3]
at org.springframework.data.mapping.context.PersistentEntities.getRequiredPersistentEntity(PersistentEntities.java:116) ~[spring-data-commons-3.3.3.jar:3.3.3]
at org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler.wrap(PersistentEntityResourceAssembler.java:86) ~[spring-data-rest-webmvc-4.3.3.jar:4.3.3]
at org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler.toModel(PersistentEntityResourceAssembler.java:69) ~[spring-data-rest-webmvc-4.3.3.jar:4.3.3]
at org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler.toModel(PersistentEntityResourceAssembler.java:34) ~[spring-data-rest-webmvc-4.3.3.jar:4.3.3]
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) ~[na:na]
at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1708) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) ~[na:na]
at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:na]
at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682) ~[na:na]
at org.springframework.hateoas.server.RepresentationModelAssembler.toCollectionModel(RepresentationModelAssembler.java:51) ~[spring-hateoas-2.3.2.jar:2.3.2]
at org.springframework.data.rest.webmvc.RepresentationModelAssemblers.entitiesToResources(RepresentationModelAssemblers.java:140) ~[spring-data-rest-webmvc-4.3.3.jar:4.3.3]
at org.springframework.data.rest.webmvc.RepresentationModelAssemblers.toCollectionModel(RepresentationModelAssemblers.java:86) ~[spring-data-rest-webmvc-4.3.3.jar:4.3.3]
at org.springframework.data.rest.webmvc.RepositorySearchController.lambda$toModel$1(RepositorySearchController.java:195) ~[spring-data-rest-webmvc-4.3.3.jar:4.3.3]
at java.base/java.util.Optional.map(Optional.java:260) ~[na:na]
at org.springframework.data.rest.webmvc.RepositorySearchController.toModel(RepositorySearchController.java:192) ~[spring-data-rest-webmvc-4.3.3.jar:4.3.3]
at org.springframework.data.rest.webmvc.RepositorySearchController.executeSearch(RepositorySearchController.java:176) ~[spring-data-rest-webmvc-4.3.3.jar:4.3.3]
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:255) ~[spring-web-6.1.12.jar:6.1.12]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:188) ~[spring-web-6.1.12.jar:6.1.12]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) ~[spring-webmvc-6.1.12.jar:6.1.12]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:926) ~[spring-webmvc-6.1.12.jar:6.1.12]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:831) ~[spring-webmvc-6.1.12.jar:6.1.12]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-6.1.12.jar:6.1.12]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089) ~[spring-webmvc-6.1.12.jar:6.1.12]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979) ~[spring-webmvc-6.1.12.jar:6.1.12]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) ~[spring-webmvc-6.1.12.jar:6.1.12]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903) ~[spring-webmvc-6.1.12.jar:6.1.12]
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564) ~[tomcat-embed-core-10.1.28.jar:6.0]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) ~[spring-webmvc-6.1.12.jar:6.1.12]
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) ~[tomcat-embed-core-10.1.28.jar:6.0]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195) ~[tomcat-embed-core-10.1.28.jar:10.1.28]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.28.jar:10.1.28]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51) ~[tomcat-embed-websocket-10.1.28.jar:10.1.28]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[tomcat-embed-core-10.1.28.jar:10.1.28]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.28.jar:10.1.28]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-6.1.12.jar:6.1.12]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.12.jar:6.1.12]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[tomcat-embed-core-10.1.28.jar:10.1.28]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.28.jar:10.1.28]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-6.1.12.jar:6.1.12]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.12.jar:6.1.12]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[tomcat-embed-core-10.1.28.jar:10.1.28]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.28.jar:10.1.28]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-6.1.12.jar:6.1.12]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.12.jar:6.1.12]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[tomcat-embed-core-10.1.28.jar:10.1.28]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.28.jar:10.1.28]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167) ~[tomcat-embed-core-10.1.28.jar:10.1.28]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90) ~[tomcat-embed-core-10.1.28.jar:10.1.28]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:483) ~[tomcat-embed-core-10.1.28.jar:10.1.28]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115) ~[tomcat-embed-core-10.1.28.jar:10.1.28]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) ~[tomcat-embed-core-10.1.28.jar:10.1.28]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-10.1.28.jar:10.1.28]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344) ~[tomcat-embed-core-10.1.28.jar:10.1.28]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:384) ~[tomcat-embed-core-10.1.28.jar:10.1.28]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) ~[tomcat-embed-core-10.1.28.jar:10.1.28]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:904) ~[tomcat-embed-core-10.1.28.jar:10.1.28]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741) ~[tomcat-embed-core-10.1.28.jar:10.1.28]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[tomcat-embed-core-10.1.28.jar:10.1.28]
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190) ~[tomcat-embed-core-10.1.28.jar:10.1.28]
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-10.1.28.jar:10.1.28]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63) ~[tomcat-embed-core-10.1.28.jar:10.1.28]
at java.base/java.lang.Thread.run(Thread.java:1583) ~[na:na]
Question:
How do I go about defining/declaring the PersistentEntity for type class ca.demo.db1.model.recomposition.RFruit?