如何在Spring数据jpa中使用BeanGenerator创建动态投影?

问题描述 投票:0回答:1

根据此文档,我们可以将基于类的投影传递给jpa api:https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections.dtos

因此,我正在尝试使用BeanGenerator创建动态的jpa投影,但似乎无法正常工作...有人知道如何在spring数据jpa中生成动态投影吗?

     final Map<String, Class<?>> properties =
                new HashMap<String, Class<?>>();
        properties.put("name", String.class);
        properties.put("phone", String.class);

    final Class<?> beanClass = PojoGenerator.generate("com.logicbig.example.EmployeeName", properties);
       List list3 = employeeRepository.findByDept("IT", beanClass);



import javassist.*;

import java.io.Serializable;
import java.util.Map;
import java.util.Map.Entry;

/**
 * copy from https://blog.javaforge.net/post/31913732423/howto-create-java-pojo-at-runtime-with-javassist
 *
 * @author blog.javaforge.net
 */
public class PojoGenerator {

    public static Class generate(String className, Map<String, Class<?>> properties) throws NotFoundException,
        CannotCompileException {

        ClassPool pool = ClassPool.getDefault();
        CtClass declaringClass = pool.makeClass(className);

        // add this to define a super class to extend
        // cc.setSuperclass(resolveCtClass(MySuperClass.class));

        // add this to define an interface to implement
        declaringClass.addInterface(resolveCtClass(Serializable.class));


        for (Entry<String, Class<?>> entry : properties.entrySet()) {
            String fieldName = entry.getKey();
            Class<?> fieldClass = entry.getValue();


            declaringClass.addField(new CtField(resolveCtClass(fieldClass), fieldName, declaringClass));

            // add getter
            declaringClass.addMethod(generateGetter(declaringClass, fieldName, fieldClass));

            // add setter
            declaringClass.addMethod(generateSetter(declaringClass, fieldName, fieldClass));


        }

        // add constructor
        generateConstructor(declaringClass, properties);

        return declaringClass.toClass();
    }

    private static CtMethod generateGetter(CtClass declaringClass, String fieldName, Class fieldClass)
        throws CannotCompileException {

        String getterName = "get" + fieldName.substring(0, 1).toUpperCase()
            + fieldName.substring(1);

        StringBuffer sb = new StringBuffer();
        sb.append("public ").append(fieldClass.getName()).append(" ")
            .append(getterName).append("(){").append("return this.")
            .append(fieldName).append(";").append("}");
        return CtMethod.make(sb.toString(), declaringClass);
    }

    private static CtMethod generateSetter(CtClass declaringClass, String fieldName, Class fieldClass)
        throws CannotCompileException {

        String setterName = "set" + fieldName.substring(0, 1).toUpperCase()
            + fieldName.substring(1);

        StringBuffer sb = new StringBuffer();
        sb.append("public void ").append(setterName).append("(")
            .append(fieldClass.getName()).append(" ").append(fieldName)
            .append(")").append("{").append("this.").append(fieldName)
            .append("=").append(fieldName).append(";").append("}");
        return CtMethod.make(sb.toString(), declaringClass);
    }

    private static void generateConstructor(CtClass declaringClass, Map<String, Class<?>> properties)
        throws CannotCompileException {


        String constructorMethodName = declaringClass.getSimpleName();
        StringBuffer constructorMethod = new StringBuffer();
        StringBuffer constructorBody = new StringBuffer();

        constructorMethod.append("public ").append(constructorMethodName).append("(");
        for (Entry<String, Class<?>> entry : properties.entrySet()) {
            String fieldName = entry.getKey();
            Class<?> fieldClass = entry.getValue();

            // add constructor
            constructorMethod.append(fieldClass.getName()).append(" ").append(fieldName).append(",");
            constructorBody.append("this.").append(fieldName)
                .append("=").append(fieldName).append(";");
        }
        constructorMethod.deleteCharAt(constructorMethod.lastIndexOf(","));
        constructorMethod.append(") {");
        constructorMethod.append(constructorBody);
        constructorMethod.append("}");

        System.out.println(constructorMethod);
        CtConstructor constructor = CtNewConstructor.make(constructorMethod.toString(), declaringClass);
        declaringClass.addConstructor(constructor);

        CtConstructor defaultConstructor = CtNewConstructor.make("public " + constructorMethodName + "() {}", declaringClass);
        declaringClass.addConstructor(defaultConstructor);
    }

    private static CtClass resolveCtClass(Class clazz) throws NotFoundException {
        ClassPool pool = ClassPool.getDefault();
        return pool.get(clazz.getName());
    }
}
====== finding beanClass for IT dept =====
13:50:12.495 [main] DEBUG org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler - Creating new EntityManager for shared EntityManager invocation
13:50:12.495 [main] DEBUG org.hibernate.query.criteria.internal.CriteriaQueryImpl - Rendered criteria query -> select generatedAlias0 from Employee as generatedAlias0 where generatedAlias0.dept=:param0
13:50:12.496 [main] DEBUG org.hibernate.hql.internal.ast.QueryTranslatorImpl - parse() - HQL: select generatedAlias0 from com.logicbig.example.Employee as generatedAlias0 where generatedAlias0.dept=:param0
13:50:12.497 [main] DEBUG org.hibernate.hql.internal.ast.ErrorTracker - throwQueryException() : no errors
13:50:12.498 [main] DEBUG org.hibernate.hql.internal.ast.QueryTranslatorImpl - --- HQL AST ---
 \-[QUERY] Node: 'query'
    +-[SELECT_FROM] Node: 'SELECT_FROM'
    |  +-[FROM] Node: 'from'
    |  |  \-[RANGE] Node: 'RANGE'
    |  |     +-[DOT] Node: '.'
    |  |     |  +-[DOT] Node: '.'
    |  |     |  |  +-[DOT] Node: '.'
    |  |     |  |  |  +-[IDENT] Node: 'com'
    |  |     |  |  |  \-[IDENT] Node: 'logicbig'
    |  |     |  |  \-[IDENT] Node: 'example'
    |  |     |  \-[IDENT] Node: 'Employee'
    |  |     \-[ALIAS] Node: 'generatedAlias0'
    |  \-[SELECT] Node: 'select'
    |     \-[IDENT] Node: 'generatedAlias0'
    \-[WHERE] Node: 'where'
       \-[EQ] Node: '='
          +-[DOT] Node: '.'
          |  +-[IDENT] Node: 'generatedAlias0'
          |  \-[IDENT] Node: 'dept'
          \-[COLON] Node: ':'
             \-[IDENT] Node: 'param0'

13:50:12.498 [main] DEBUG org.hibernate.hql.internal.antlr.HqlSqlBaseWalker - select << begin [level=1, statement=select]
13:50:12.499 [main] DEBUG org.hibernate.hql.internal.ast.tree.FromElement - FromClause{level=1} : com.logicbig.example.Employee (generatedAlias0) -> employee0_
13:50:12.499 [main] DEBUG org.hibernate.hql.internal.ast.tree.FromReferenceNode - Resolved : generatedAlias0 -> employee0_.id
13:50:12.500 [main] DEBUG org.hibernate.hql.internal.ast.tree.FromReferenceNode - Resolved : generatedAlias0 -> employee0_.id
13:50:12.500 [main] DEBUG org.hibernate.hql.internal.ast.tree.DotNode - getDataType() : dept -> org.hibernate.type.StringType@6b63d445
13:50:12.500 [main] DEBUG org.hibernate.hql.internal.ast.tree.FromReferenceNode - Resolved : generatedAlias0.dept -> employee0_.dept
13:50:12.500 [main] DEBUG org.hibernate.hql.internal.antlr.HqlSqlBaseWalker - select : finishing up [level=1, statement=select]
13:50:12.500 [main] DEBUG org.hibernate.hql.internal.ast.HqlSqlWalker - processQuery() :  ( SELECT ( {select clause} employee0_.id ) ( FromClause{level=1} Employee employee0_ ) ( where ( = ( employee0_.dept employee0_.id dept ) ? ) ) )
13:50:12.509 [main] DEBUG org.hibernate.hql.internal.ast.util.JoinProcessor - Using FROM fragment [Employee employee0_]
13:50:12.509 [main] DEBUG org.hibernate.hql.internal.antlr.HqlSqlBaseWalker - select >> end [level=1, statement=select]
13:50:12.510 [main] DEBUG org.hibernate.hql.internal.ast.QueryTranslatorImpl - --- SQL AST ---
 \-[SELECT] QueryNode: 'SELECT'  querySpaces (Employee)
    +-[SELECT_CLAUSE] SelectClause: '{select clause}'
    |  +-[ALIAS_REF] IdentNode: 'employee0_.id as id1_0_' {alias=generatedAlias0, className=com.logicbig.example.Employee, tableAlias=employee0_}
    |  \-[SQL_TOKEN] SqlFragment: 'employee0_.dept as dept2_0_, employee0_.name as name3_0_, employee0_.phone as phone4_0_, employee0_.salary as salary5_0_'
    +-[FROM] FromClause: 'from' FromClause{level=1, fromElementCounter=1, fromElements=1, fromElementByClassAlias=[generatedAlias0], fromElementByTableAlias=[employee0_], fromElementsByPath=[], collectionJoinFromElementsByPath=[], impliedElements=[]}
    |  \-[FROM_FRAGMENT] FromElement: 'Employee employee0_' FromElement{explicit,not a collection join,not a fetch join,fetch non-lazy properties,classAlias=generatedAlias0,role=null,tableName=Employee,tableAlias=employee0_,origin=null,columns={,className=com.logicbig.example.Employee}}
    \-[WHERE] SqlNode: 'where'
       \-[EQ] BinaryLogicOperatorNode: '='
          +-[DOT] DotNode: 'employee0_.dept' {propertyName=dept,dereferenceType=PRIMITIVE,getPropertyPath=dept,path=generatedAlias0.dept,tableAlias=employee0_,className=com.logicbig.example.Employee,classAlias=generatedAlias0}
          |  +-[ALIAS_REF] IdentNode: 'employee0_.id' {alias=generatedAlias0, className=com.logicbig.example.Employee, tableAlias=employee0_}
          |  \-[IDENT] IdentNode: 'dept' {originalText=dept}
          \-[NAMED_PARAM] ParameterNode: '?' {name=param0, expectedType=org.hibernate.type.StringType@6b63d445}

13:50:12.510 [main] DEBUG org.hibernate.hql.internal.ast.ErrorTracker - throwQueryException() : no errors
13:50:12.510 [main] DEBUG org.hibernate.hql.internal.ast.QueryTranslatorImpl - HQL: select generatedAlias0 from com.logicbig.example.Employee as generatedAlias0 where generatedAlias0.dept=:param0
13:50:12.510 [main] DEBUG org.hibernate.hql.internal.ast.QueryTranslatorImpl - SQL: select employee0_.id as id1_0_, employee0_.dept as dept2_0_, employee0_.name as name3_0_, employee0_.phone as phone4_0_, employee0_.salary as salary5_0_ from Employee employee0_ where employee0_.dept=?
13:50:12.510 [main] DEBUG org.hibernate.hql.internal.ast.ErrorTracker - throwQueryException() : no errors
13:50:12.511 [main] DEBUG org.hibernate.SQL - select employee0_.id as id1_0_, employee0_.dept as dept2_0_, employee0_.name as name3_0_, employee0_.phone as phone4_0_, employee0_.salary as salary5_0_ from Employee employee0_ where employee0_.dept=?
13:50:12.512 [main] DEBUG org.hibernate.loader.Loader - Result set row: 0
13:50:12.515 [main] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[com.logicbig.example.Employee#2]
13:50:12.520 [main] DEBUG org.hibernate.loader.Loader - Result set row: 1
13:50:12.521 [main] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[com.logicbig.example.Employee#5]
13:50:12.521 [main] DEBUG org.hibernate.loader.Loader - Result set row: 2
13:50:12.521 [main] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[com.logicbig.example.Employee#6]
13:50:12.521 [main] DEBUG org.hibernate.engine.internal.TwoPhaseLoad - Resolving associations for [com.logicbig.example.Employee#2]
13:50:12.522 [main] DEBUG org.hibernate.engine.internal.TwoPhaseLoad - Done materializing entity [com.logicbig.example.Employee#2]
13:50:12.522 [main] DEBUG org.hibernate.engine.internal.TwoPhaseLoad - Resolving associations for [com.logicbig.example.Employee#5]
13:50:12.522 [main] DEBUG org.hibernate.engine.internal.TwoPhaseLoad - Done materializing entity [com.logicbig.example.Employee#5]
13:50:12.522 [main] DEBUG org.hibernate.engine.internal.TwoPhaseLoad - Resolving associations for [com.logicbig.example.Employee#6]
13:50:12.522 [main] DEBUG org.hibernate.engine.internal.TwoPhaseLoad - Done materializing entity [com.logicbig.example.Employee#6]
13:50:12.522 [main] DEBUG org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl - Initiating JDBC connection release from afterTransaction
13:50:12.523 [main] DEBUG org.springframework.orm.jpa.EntityManagerFactoryUtils - Closing JPA EntityManager
Exception in thread "main" org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [com.logicbig.example.Employee] to type [com.logicbig.example.EmployeeName]
    at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:321)
    at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:194)
    at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:174)
    at org.springframework.data.repository.query.ResultProcessor$ProjectingConverter.convert(ResultProcessor.java:293)
    at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.lambda$and$0(ResultProcessor.java:213)
    at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.convert(ResultProcessor.java:224)
    at org.springframework.data.repository.query.ResultProcessor.processResult(ResultProcessor.java:152)
    at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:141)
    at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:125)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:590)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:578)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:135)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
    at com.sun.proxy.$Proxy34.findByDept(Unknown Source)
    at com.logicbig.example.ExampleClient.run(ExampleClient.java:74)
    at com.logicbig.example.ExampleMain.main(ExampleMain.java:12)
13:50:26.941 [pool-1-thread-1] DEBUG org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl - Connection pool now considered primed; min-size will be maintained


hibernate jpa dynamic spring-data-jpa projection
1个回答
0
投票

假设BeanGenerator生成典型的Java Bean,则该类可能缺少具有所有必填字段的构造函数:

如果商店通过限制要加载的字段来优化查询执行,则要加载的字段由公开的构造函数的参数名称确定。

引号来自https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections.dtos

© www.soinside.com 2019 - 2024. All rights reserved.