Pregunta

Estoy usando javax.persistence y Spring y yo tenemos una clase de entidad simple y una simple CrudRepository que funcionan bien hasta que intento agregar el mío propio findByXXX() método.

Mi clase de entidad es la siguiente:

@Entity
public class Node
{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column (name = "ID")
    private Integer mID;

    /** The node's activity. */
    @Column (name = "Activity", nullable = false, length = 200)
    private String mActivity;

    // ... other properties.

    public Integer getId() { return mID; }
    public void setId(Integer id) { mID = id; }
    public String getActivity() { return mActivity; }
    public void setActivity(String activity) { mActivity = activity; }
    ...
}

Notarás que estoy usando una convención de nomenclatura de un prefijo 'm' en las propiedades de la instancia.Esto funciona bien con mi repositorio hasta que agregue el mío propio. findByXXX() métodos.Entonces puedo guardar y recuperar un Node desde un almacén de datos utilizando los métodos CRUD estándar muy bien.

Cuando intento agregar mi propio método de consulta, así:

public interface NodeRepository extends CrudRepository<Node, Integer>
{
    public List<Node> findByActivity(String activity);
}

mi sistema se rompe.Específicamente, falla el cableado automático de mi repositorio (consulte el seguimiento de la pila al final de esta publicación).Más por suerte que por diseño, descubrí que si modificaba mi clase de nodo para ya no usar el prefijo 'm' en las propiedades, el problema desaparecía.Es decir, el siguiente código funciona:

@Entity
public class Node
{
    ...

    /** The node's activity. */
    @Column (name = "Activity", nullable = false, length = 200)
    private String activity;

    // ... other properties.

    public String getActivity() { return activity; }
    public void setActivity(final String activity) { this.activity = activity; }
    ...
}

Parecería que cuando Spring está construyendo el findByActivity() método que busca el Node bean por el nombre de la propiedad (por ejemplo. activity), en lugar de los métodos de propiedad (p. ej. getActivity(), setActivity()).

¿Alguien sabe si este es realmente el caso?Si es así, ¿hay alguna forma de evitarlo para poder mantener mi convención de nomenclatura?No estoy acostumbrado a ello, es algo a lo que estoy acostumbrado.

PD:Estoy usando Spring 3.2.x y Java 7

EDITADO para agregar seguimiento de pila: el programa se ejecuta desde dentro SpringJUnit4ClassRunner:

INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@32f2e8ca: defining beans [nodeRepository,org.springframework.data.repository.core.support.RepositoryInterfaceAwareBeanPostProcessor#0,org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor#0,dataSource,entityManagerFactory,transactionManager,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalPersistenceAnnotationProcessor,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy
Nov 18, 2013 6:59:10 PM org.springframework.test.context.TestContextManager prepareTestInstance
SEVERE: Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@57b3fe3c] to prepare test instance [com.example.persistence.JPAXMLCfgTest@69f8421f]
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.example.persistence.JPAXMLCfgTest': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.example.persistence.NodeRepository com.example.persistence.JPAXMLCfgTest.mRepo; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'nodeRepository': FactoryBean threw exception on object creation; nested exception is java.lang.NullPointerException
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:287)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1106)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:374)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:110)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75)
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:312)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:211)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:288)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:284)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
    at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:252)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141)
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
    at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
    at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
    at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.example.persistence.NodeRepository com.example.persistence.JPAXMLCfgTest.mRepo; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'nodeRepository': FactoryBean threw exception on object creation; nested exception is java.lang.NullPointerException
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:513)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:92)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:284)
    ... 32 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'nodeRepository': FactoryBean threw exception on object creation; nested exception is java.lang.NullPointerException
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:149)
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:102)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1442)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:248)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:871)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:813)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:730)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:485)
    ... 34 more
Caused by: java.lang.NullPointerException
    at org.springframework.data.jpa.repository.query.QueryUtils.isEntityPath(QueryUtils.java:462)
    at org.springframework.data.jpa.repository.query.QueryUtils.toExpressionRecursively(QueryUtils.java:445)
    at org.springframework.data.jpa.repository.query.JpaQueryCreator$PredicateBuilder.build(JpaQueryCreator.java:197)
    at org.springframework.data.jpa.repository.query.JpaQueryCreator.toPredicate(JpaQueryCreator.java:144)
    at org.springframework.data.jpa.repository.query.JpaQueryCreator.create(JpaQueryCreator.java:86)
    at org.springframework.data.jpa.repository.query.JpaQueryCreator.create(JpaQueryCreator.java:44)
    at org.springframework.data.repository.query.parser.AbstractQueryCreator.createCriteria(AbstractQueryCreator.java:109)
    at org.springframework.data.repository.query.parser.AbstractQueryCreator.createQuery(AbstractQueryCreator.java:88)
    at org.springframework.data.repository.query.parser.AbstractQueryCreator.createQuery(AbstractQueryCreator.java:73)
    at org.springframework.data.jpa.repository.query.PartTreeJpaQuery$QueryPreparer.<init>(PartTreeJpaQuery.java:98)
    at org.springframework.data.jpa.repository.query.PartTreeJpaQuery$CountQueryPreparer.<init>(PartTreeJpaQuery.java:166)
    at org.springframework.data.jpa.repository.query.PartTreeJpaQuery.<init>(PartTreeJpaQuery.java:60)
    at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:90)
    at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateIfNotFoundQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:162)
    at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$AbstractQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:68)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.<init>(RepositoryFactorySupport.java:290)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:158)
    at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.getObject(RepositoryFactoryBeanSupport.java:162)
    at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.getObject(RepositoryFactoryBeanSupport.java:44)
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:142)
    ... 42 more
¿Fue útil?

Solución

Vea aquí para la documación sobre cómo se resuelven las consultas.

http://docs.spring.io/spring-data/jpa/docs/1.4.2.release/reference/html/reposititories.html#reposititories.query-methods

tan corta de nombrar su método:

public List<Node> findByMActivity(String activity);

O moviendo sus asignaciones a los métodos en lugar de los campos, la única forma obvia que puedo ver es anotar realmente este método con @query o definir una consulta con nombre en otro lugar de la que se referiría este método.

@Query("my custom query")
public List<Node> findByActivity(String activity);

Para hacerlo de una manera más genérica, supongo que estaría mirando para anular o pasar un QueryResolver personalizado a:

org.springframework.data.jpa.repository.query.jpaqueryMethod

De todos modos, todo parece una gran cantidad de problemas para tener sus campos prefijados con un 'M'.

Otros consejos

Aunque me gusta la respuesta de @Alan Hay, otra opción es agregar una capa de "servicios" a su solución.He hecho esto en el pasado para crear una interfaz para las operaciones CRUD en mi capa de modelos.

Puede crear una clase de servicios con el nombre del método getter que desee, es decir. findByActivity, llamando a la clase de repositorio' findByMActivity(... método.

Esto también le permite tener una capa de modelos con todos los métodos CRUD disponibles, y el objeto de servicios solo usaría aquellas operaciones CRUD pertinentes a ese servicio en particular, es decir.Servicio de actividad.En esencia, puede crear múltiples interfaces para los mismos datos, dependiendo de las acciones que se realicen en esos datos.

Entonces su clase de capa de servicio puede tener cualquier nombre de método que tenga sentido para el usuario, es decir,findByActivity frente a findByMActivity.Martin Fowler describe la capa de servicios bien.

Es posible que su solución no requiera una capa adicional, pero puede ser una abstracción adicional que puede resolver problemas de interfaz como este, donde sería más costoso cambiar el nombre de una variable de dominio.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top