From 59b4637f0dfc46957d9d051971419ed5de7ad16b Mon Sep 17 00:00:00 2001 From: stormning Date: Thu, 3 Nov 2016 09:38:12 +0800 Subject: [PATCH] =?UTF-8?q?=E6=AD=A4=E7=89=88=E6=9C=AC=E5=81=9A=E4=B8=80?= =?UTF-8?q?=E4=BA=9B=E4=BC=98=E5=8C=96=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- .../jpa/AbstractTemplateBasedJpaQuery.java | 149 +++--- .../spring/jpa/BeanTransformerAdapter.java | 487 +++++++++--------- .../com/slyak/spring/jpa/ContextHolder.java | 16 +- .../com/slyak/spring/jpa/EntityAssembler.java | 26 +- .../slyak/spring/jpa/EntityAssemblerMany.java | 100 ++-- .../slyak/spring/jpa/EntityAssemblerOne.java | 128 ++--- .../spring/jpa/FreemarkerSqlTemplates.java | 206 ++++---- .../spring/jpa/FreemarkerTemplateQuery.java | 216 ++++---- .../spring/jpa/GenericJpaRepository.java | 16 +- .../jpa/GenericJpaRepositoryFactory.java | 196 +++---- .../jpa/GenericJpaRepositoryFactoryBean.java | 25 +- .../spring/jpa/GenericJpaRepositoryImpl.java | 203 ++++---- .../com/slyak/spring/jpa/QueryBuilder.java | 197 +++---- .../com/slyak/spring/jpa/QueryTemplate.java | 2 +- .../spring/jpa/QueryTemplateContext.java | 2 +- .../slyak/spring/jpa/SmartTransformer.java | 41 +- .../java/com/slyak/spring/jpa/Status.java | 4 +- .../com/slyak/spring/jpa/TemplateQuery.java | 6 +- .../slyak/spring/jpa/TemplateQueryObject.java | 6 +- .../java/com/slyak/util/AopTargetUtils.java | 91 ++-- .../com/slyak/spring/jpa/templatequery.xsd | 31 +- .../java/com/slyak/spring/jpa/AppConfig.java | 62 +-- .../java/com/slyak/spring/jpa/JpaTest.java | 78 +-- .../java/com/slyak/spring/jpa/Sample.java | 36 +- .../java/com/slyak/spring/jpa/SampleDTO.java | 30 +- .../com/slyak/spring/jpa/SampleQuery.java | 20 +- .../slyak/spring/jpa/SampleRepository.java | 18 +- .../resources/com/slyak/spring/jpa/Sample.xml | 6 +- 29 files changed, 1228 insertions(+), 1172 deletions(-) diff --git a/pom.xml b/pom.xml index 5b6d779..1d50ec9 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 spring-data-jpa-extra - 1.2.0.RELEASE + 2.0.0-SNAPSHOT jar ${project.groupId}:${project.artifactId} spring-data-jpa dynamic query support like mybatis and much easier than mybatis. diff --git a/src/main/java/com/slyak/spring/jpa/AbstractTemplateBasedJpaQuery.java b/src/main/java/com/slyak/spring/jpa/AbstractTemplateBasedJpaQuery.java index 1b17cf1..27d30c3 100644 --- a/src/main/java/com/slyak/spring/jpa/AbstractTemplateBasedJpaQuery.java +++ b/src/main/java/com/slyak/spring/jpa/AbstractTemplateBasedJpaQuery.java @@ -1,7 +1,6 @@ package com.slyak.spring.jpa; import org.springframework.data.jpa.repository.query.*; -import org.springframework.data.repository.query.Parameter; import org.springframework.data.repository.query.ParameterAccessor; import org.springframework.data.repository.query.ParametersParameterAccessor; import org.springframework.util.ReflectionUtils; @@ -17,77 +16,79 @@ */ public class AbstractTemplateBasedJpaQuery extends AbstractJpaQuery { - private JpaQueryMethod method; - - private QueryTemplate query; - - private QueryTemplate countQuery; - - /** - * Creates a new {@link AbstractJpaQuery} from the given {@link JpaQueryMethod}. - * - * @param method - * @param em - */ - public AbstractTemplateBasedJpaQuery(JpaQueryMethod method, EntityManager em, QueryTemplateContext context) { - super(method, em); - this.method = method; - this.query = context.lookup(getQueryMethod().getNamedQueryName()); - String cq = executeMethod("getCountQuery"); - this.countQuery = cq == null ? null : context.lookup(cq); - } - - @Override - protected Query doCreateQuery(Object[] values) { - ParameterAccessor accessor = new ParametersParameterAccessor(getQueryMethod().getParameters(), values); - String sortedQueryString = QueryUtils.applySorting(query.getQueryString(), accessor.getSort(), QueryUtils.detectAlias(query.getQueryString())); - - Query query = createJpaQuery(sortedQueryString); - - return createBinder(values).bindAndPrepare(query); - } - - @Override - protected Query doCreateCountQuery(Object[] values) { - String queryString = countQuery.getQueryString(); - EntityManager em = getEntityManager(); - boolean isNativeQuery = executeMethod("nativeQuery"); - return createBinder(values).bind(isNativeQuery ? em.createNativeQuery(queryString) : em.createQuery(queryString, Long.class)); - } - - public Query createJpaQuery(String queryString) { - return getEntityManager().createQuery(queryString); - } - - @Override - protected ParameterBinder createBinder(Object[] values) { - return new TemplateQueryParameterBinder(getQueryMethod().getParameters(), values); - } - - @SuppressWarnings("unchecked") - private T executeMethod(String methodName) { - Method countQueryMethod = ReflectionUtils.findMethod(JpaQueryMethod.class, methodName); - ReflectionUtils.makeAccessible(countQueryMethod); - return (T) ReflectionUtils.invokeMethod(countQueryMethod, method); - } - - private static class TemplateQueryParameterBinder extends ParameterBinder { - - private Object[] values; - - private JpaParameters parameters; - - /** - * Creates a new {@link ParameterBinder}. - * - * @param parameters must not be {@literal null}. - * @param values must not be {@literal null}. - */ - public TemplateQueryParameterBinder(JpaParameters parameters, Object[] values) { - super(parameters, values); - this.values = values; - this.parameters = parameters; - } - - } + private JpaQueryMethod method; + + private QueryTemplate query; + + private QueryTemplate countQuery; + + /** + * Creates a new {@link AbstractJpaQuery} from the given {@link JpaQueryMethod}. + * + * @param method + * @param em + */ + public AbstractTemplateBasedJpaQuery(JpaQueryMethod method, EntityManager em, QueryTemplateContext context) { + super(method, em); + this.method = method; + this.query = context.lookup(getQueryMethod().getNamedQueryName()); + String cq = executeMethod("getCountQuery"); + this.countQuery = cq == null ? null : context.lookup(cq); + } + + @Override + protected Query doCreateQuery(Object[] values) { + ParameterAccessor accessor = new ParametersParameterAccessor(getQueryMethod().getParameters(), values); + String sortedQueryString = QueryUtils.applySorting(query.getQueryString(), accessor.getSort(), + QueryUtils.detectAlias(query.getQueryString())); + + Query query = createJpaQuery(sortedQueryString); + + return createBinder(values).bindAndPrepare(query); + } + + @Override + protected Query doCreateCountQuery(Object[] values) { + String queryString = countQuery.getQueryString(); + EntityManager em = getEntityManager(); + boolean isNativeQuery = executeMethod("nativeQuery"); + return createBinder(values) + .bind(isNativeQuery ? em.createNativeQuery(queryString) : em.createQuery(queryString, Long.class)); + } + + public Query createJpaQuery(String queryString) { + return getEntityManager().createQuery(queryString); + } + + @Override + protected ParameterBinder createBinder(Object[] values) { + return new TemplateQueryParameterBinder(getQueryMethod().getParameters(), values); + } + + @SuppressWarnings("unchecked") + private T executeMethod(String methodName) { + Method countQueryMethod = ReflectionUtils.findMethod(JpaQueryMethod.class, methodName); + ReflectionUtils.makeAccessible(countQueryMethod); + return (T) ReflectionUtils.invokeMethod(countQueryMethod, method); + } + + private static class TemplateQueryParameterBinder extends ParameterBinder { + + private Object[] values; + + private JpaParameters parameters; + + /** + * Creates a new {@link ParameterBinder}. + * + * @param parameters must not be {@literal null}. + * @param values must not be {@literal null}. + */ + public TemplateQueryParameterBinder(JpaParameters parameters, Object[] values) { + super(parameters, values); + this.values = values; + this.parameters = parameters; + } + + } } diff --git a/src/main/java/com/slyak/spring/jpa/BeanTransformerAdapter.java b/src/main/java/com/slyak/spring/jpa/BeanTransformerAdapter.java index 60e59ae..b3171f0 100644 --- a/src/main/java/com/slyak/spring/jpa/BeanTransformerAdapter.java +++ b/src/main/java/com/slyak/spring/jpa/BeanTransformerAdapter.java @@ -27,264 +27,275 @@ */ public class BeanTransformerAdapter implements ResultTransformer { - private static DefaultConversionService conversionService; + private static DefaultConversionService conversionService; - static { - BeanTransformerAdapter.conversionService = new DefaultConversionService(); - Collection> convertersToRegister = JodaTimeConverters.getConvertersToRegister(); - for (Converter converter : convertersToRegister) { - BeanTransformerAdapter.conversionService.addConverter(converter); - } - } + static { + BeanTransformerAdapter.conversionService = new DefaultConversionService(); + Collection> convertersToRegister = JodaTimeConverters.getConvertersToRegister(); + for (Converter converter : convertersToRegister) { + BeanTransformerAdapter.conversionService.addConverter(converter); + } + } - /** - * Logger available to subclasses - */ - protected final Log logger = LogFactory.getLog(getClass()); - /** - * The class we are mapping to - */ - private Class mappedClass; - /** - * Whether we're strictly validating - */ - private boolean checkFullyPopulated = false; - /** - * Whether we're defaulting primitives when mapping a null value - */ - private boolean primitivesDefaultedForNullValue = false; - /** - * Map of the fields we provide mapping for - */ - private Map mappedFields; - /** - * Set of bean properties we provide mapping for - */ - private Set mappedProperties; + /** + * Logger available to subclasses + */ + protected final Log logger = LogFactory.getLog(getClass()); - /** - * Create a new BeanPropertyRowMapper for bean-style configuration. - * - * @see #setMappedClass - * @see #setCheckFullyPopulated - */ - public BeanTransformerAdapter() { + /** + * The class we are mapping to + */ + private Class mappedClass; - } + /** + * Whether we're strictly validating + */ + private boolean checkFullyPopulated = false; - /** - * Create a new BeanPropertyRowMapper, accepting unpopulated properties - * in the target bean. - *

Consider using the {@link #newInstance} factory method instead, - * which allows for specifying the mapped type once only. - * - * @param mappedClass the class that each row should be mapped to - */ - public BeanTransformerAdapter(Class mappedClass) { - initialize(mappedClass); - } + /** + * Whether we're defaulting primitives when mapping a null value + */ + private boolean primitivesDefaultedForNullValue = false; - /** - * Create a new BeanPropertyRowMapper. - * - * @param mappedClass the class that each row should be mapped to - * @param checkFullyPopulated whether we're strictly validating that - * all bean properties have been mapped from corresponding database fields - */ - public BeanTransformerAdapter(Class mappedClass, boolean checkFullyPopulated) { - initialize(mappedClass); - this.checkFullyPopulated = checkFullyPopulated; - } + /** + * Map of the fields we provide mapping for + */ + private Map mappedFields; - /** - * Static factory method to create a new BeanPropertyRowMapper - * (with the mapped class specified only once). - * - * @param mappedClass the class that each row should be mapped to - */ - public static BeanPropertyRowMapper newInstance(Class mappedClass) { - BeanPropertyRowMapper newInstance = new BeanPropertyRowMapper(); - newInstance.setMappedClass(mappedClass); - return newInstance; - } + /** + * Set of bean properties we provide mapping for + */ + private Set mappedProperties; - /** - * Initialize the mapping metadata for the given class. - * - * @param mappedClass the mapped class. - */ - protected void initialize(Class mappedClass) { - this.mappedClass = mappedClass; - this.mappedFields = new HashMap(); - this.mappedProperties = new HashSet(); - PropertyDescriptor[] pds = BeanUtils.getPropertyDescriptors(mappedClass); - for (PropertyDescriptor pd : pds) { - if (pd.getWriteMethod() != null) { - this.mappedFields.put(pd.getName().toLowerCase(), pd); - String underscoredName = underscoreName(pd.getName()); - if (!pd.getName().toLowerCase().equals(underscoredName)) { - this.mappedFields.put(underscoredName, pd); - } - this.mappedProperties.add(pd.getName()); - } - } - } + /** + * Create a new BeanPropertyRowMapper for bean-style configuration. + * + * @see #setMappedClass + * @see #setCheckFullyPopulated + */ + public BeanTransformerAdapter() { - /** - * Convert a name in camelCase to an underscored name in lower case. - * Any upper case letters are converted to lower case with a preceding underscore. - * - * @param name the string containing original name - * @return the converted name - */ - private String underscoreName(String name) { - if (!StringUtils.hasLength(name)) { - return ""; - } - StringBuilder result = new StringBuilder(); - result.append(name.substring(0, 1).toLowerCase()); - for (int i = 1; i < name.length(); i++) { - String s = name.substring(i, i + 1); - String slc = s.toLowerCase(); - if (!s.equals(slc)) { - result.append("_").append(slc); - } else { - result.append(s); - } - } - return result.toString(); - } + } - /** - * Get the class that we are mapping to. - */ - public final Class getMappedClass() { - return this.mappedClass; - } + /** + * Create a new BeanPropertyRowMapper, accepting unpopulated properties + * in the target bean. + *

Consider using the {@link #newInstance} factory method instead, + * which allows for specifying the mapped type once only. + * + * @param mappedClass the class that each row should be mapped to + */ + public BeanTransformerAdapter(Class mappedClass) { + initialize(mappedClass); + } - /** - * Set the class that each row should be mapped to. - */ - public void setMappedClass(Class mappedClass) { - if (this.mappedClass == null) { - initialize(mappedClass); - } else { - if (!this.mappedClass.equals(mappedClass)) { - throw new InvalidDataAccessApiUsageException("The mapped class can not be reassigned to map to " - + mappedClass + " since it is already providing mapping for " + this.mappedClass); - } - } - } + /** + * Create a new BeanPropertyRowMapper. + * + * @param mappedClass the class that each row should be mapped to + * @param checkFullyPopulated whether we're strictly validating that + * all bean properties have been mapped from corresponding database fields + */ + public BeanTransformerAdapter(Class mappedClass, boolean checkFullyPopulated) { + initialize(mappedClass); + this.checkFullyPopulated = checkFullyPopulated; + } - /** - * Return whether we're strictly validating that all bean properties have been - * mapped from corresponding database fields. - */ - public boolean isCheckFullyPopulated() { - return this.checkFullyPopulated; - } + /** + * Static factory method to create a new BeanPropertyRowMapper + * (with the mapped class specified only once). + * + * @param mappedClass the class that each row should be mapped to + */ + public static BeanPropertyRowMapper newInstance(Class mappedClass) { + BeanPropertyRowMapper newInstance = new BeanPropertyRowMapper(); + newInstance.setMappedClass(mappedClass); + return newInstance; + } - /** - * Set whether we're strictly validating that all bean properties have been - * mapped from corresponding database fields. - *

Default is {@code false}, accepting unpopulated properties in the - * target bean. - */ - public void setCheckFullyPopulated(boolean checkFullyPopulated) { - this.checkFullyPopulated = checkFullyPopulated; - } + /** + * Initialize the mapping metadata for the given class. + * + * @param mappedClass the mapped class. + */ + protected void initialize(Class mappedClass) { + this.mappedClass = mappedClass; + this.mappedFields = new HashMap(); + this.mappedProperties = new HashSet(); + PropertyDescriptor[] pds = BeanUtils.getPropertyDescriptors(mappedClass); + for (PropertyDescriptor pd : pds) { + if (pd.getWriteMethod() != null) { + this.mappedFields.put(pd.getName().toLowerCase(), pd); + String underscoredName = underscoreName(pd.getName()); + if (!pd.getName().toLowerCase().equals(underscoredName)) { + this.mappedFields.put(underscoredName, pd); + } + this.mappedProperties.add(pd.getName()); + } + } + } - /** - * Return whether we're defaulting Java primitives in the case of mapping a null value - * from corresponding database fields. - */ - public boolean isPrimitivesDefaultedForNullValue() { - return primitivesDefaultedForNullValue; - } + /** + * Convert a name in camelCase to an underscored name in lower case. + * Any upper case letters are converted to lower case with a preceding underscore. + * + * @param name the string containing original name + * @return the converted name + */ + private String underscoreName(String name) { + if (!StringUtils.hasLength(name)) { + return ""; + } + StringBuilder result = new StringBuilder(); + result.append(name.substring(0, 1).toLowerCase()); + for (int i = 1; i < name.length(); i++) { + String s = name.substring(i, i + 1); + String slc = s.toLowerCase(); + if (!s.equals(slc)) { + result.append("_").append(slc); + } + else { + result.append(s); + } + } + return result.toString(); + } - /** - * Set whether we're defaulting Java primitives in the case of mapping a null value - * from corresponding database fields. - *

Default is {@code false}, throwing an exception when nulls are mapped to Java primitives. - */ - public void setPrimitivesDefaultedForNullValue(boolean primitivesDefaultedForNullValue) { - this.primitivesDefaultedForNullValue = primitivesDefaultedForNullValue; - } + /** + * Get the class that we are mapping to. + */ + public final Class getMappedClass() { + return this.mappedClass; + } - /** - * Initialize the given BeanWrapper to be used for row mapping. - * To be called for each row. - *

The default implementation is empty. Can be overridden in subclasses. - * - * @param bw the BeanWrapper to initialize - */ - protected void initBeanWrapper(BeanWrapper bw) { - bw.setConversionService(conversionService); - } + /** + * Set the class that each row should be mapped to. + */ + public void setMappedClass(Class mappedClass) { + if (this.mappedClass == null) { + initialize(mappedClass); + } + else { + if (!this.mappedClass.equals(mappedClass)) { + throw new InvalidDataAccessApiUsageException("The mapped class can not be reassigned to map to " + + mappedClass + " since it is already providing mapping for " + this.mappedClass); + } + } + } - /** - * Retrieve a JDBC object value for the specified column. - *

The default implementation calls - * {@link JdbcUtils#getResultSetValue(java.sql.ResultSet, int, Class)}. - * Subclasses may override this to check specific value types upfront, - * or to post-process values return from {@code getResultSetValue}. - * - * @param rs is the ResultSet holding the data - * @param index is the column index - * @param pd the bean property that each result object is expected to match - * (or {@code null} if none specified) - * @return the Object value - * @throws SQLException in case of extraction failure - * @see org.springframework.jdbc.support.JdbcUtils#getResultSetValue(java.sql.ResultSet, int, Class) - */ - protected Object getColumnValue(ResultSet rs, int index, PropertyDescriptor pd) throws SQLException { - return JdbcUtils.getResultSetValue(rs, index, pd.getPropertyType()); - } + /** + * Return whether we're strictly validating that all bean properties have been + * mapped from corresponding database fields. + */ + public boolean isCheckFullyPopulated() { + return this.checkFullyPopulated; + } - @Override - public Object transformTuple(Object[] tuple, String[] aliases) { - T mappedObject = BeanUtils.instantiate(this.mappedClass); - BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(mappedObject); - initBeanWrapper(bw); + /** + * Set whether we're strictly validating that all bean properties have been + * mapped from corresponding database fields. + *

Default is {@code false}, accepting unpopulated properties in the + * target bean. + */ + public void setCheckFullyPopulated(boolean checkFullyPopulated) { + this.checkFullyPopulated = checkFullyPopulated; + } - Set populatedProperties = (isCheckFullyPopulated() ? new HashSet() : null); - for (int i = 0; i < aliases.length; i++) { - String column = aliases[i]; - PropertyDescriptor pd = this.mappedFields.get(column.replaceAll(" ", "").toLowerCase()); - if (pd != null) { - try { - Object value = tuple[i]; - try { - bw.setPropertyValue(pd.getName(), value); - } catch (TypeMismatchException e) { - if (value == null && primitivesDefaultedForNullValue) { - logger.debug("Intercepted TypeMismatchException for column " + column + " and column '" - + column + "' with value " + value + " when setting property '" + pd.getName() + "' of type " + pd.getPropertyType() - + " on object: " + mappedObject); - } else { - throw e; - } - } - if (populatedProperties != null) { - populatedProperties.add(pd.getName()); - } - } catch (NotWritablePropertyException ex) { - throw new DataRetrievalFailureException("Unable to map column " + column - + " to property " + pd.getName(), ex); - } - } - } + /** + * Return whether we're defaulting Java primitives in the case of mapping a null value + * from corresponding database fields. + */ + public boolean isPrimitivesDefaultedForNullValue() { + return primitivesDefaultedForNullValue; + } - if (populatedProperties != null && !populatedProperties.equals(this.mappedProperties)) { - throw new InvalidDataAccessApiUsageException("Given ResultSet does not contain all fields " - + "necessary to populate object of class [" + this.mappedClass + "]: " + this.mappedProperties); - } + /** + * Set whether we're defaulting Java primitives in the case of mapping a null value + * from corresponding database fields. + *

Default is {@code false}, throwing an exception when nulls are mapped to Java primitives. + */ + public void setPrimitivesDefaultedForNullValue(boolean primitivesDefaultedForNullValue) { + this.primitivesDefaultedForNullValue = primitivesDefaultedForNullValue; + } - return mappedObject; - } + /** + * Initialize the given BeanWrapper to be used for row mapping. + * To be called for each row. + *

The default implementation is empty. Can be overridden in subclasses. + * + * @param bw the BeanWrapper to initialize + */ + protected void initBeanWrapper(BeanWrapper bw) { + bw.setConversionService(conversionService); + } - @Override - public List transformList(List list) { - return list; - } + /** + * Retrieve a JDBC object value for the specified column. + *

The default implementation calls + * {@link JdbcUtils#getResultSetValue(java.sql.ResultSet, int, Class)}. + * Subclasses may override this to check specific value types upfront, + * or to post-process values return from {@code getResultSetValue}. + * + * @param rs is the ResultSet holding the data + * @param index is the column index + * @param pd the bean property that each result object is expected to match + * (or {@code null} if none specified) + * @return the Object value + * @throws SQLException in case of extraction failure + * @see org.springframework.jdbc.support.JdbcUtils#getResultSetValue(java.sql.ResultSet, int, Class) + */ + protected Object getColumnValue(ResultSet rs, int index, PropertyDescriptor pd) throws SQLException { + return JdbcUtils.getResultSetValue(rs, index, pd.getPropertyType()); + } + + @Override + public Object transformTuple(Object[] tuple, String[] aliases) { + T mappedObject = BeanUtils.instantiate(this.mappedClass); + BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(mappedObject); + initBeanWrapper(bw); + + Set populatedProperties = (isCheckFullyPopulated() ? new HashSet() : null); + for (int i = 0; i < aliases.length; i++) { + String column = aliases[i]; + PropertyDescriptor pd = this.mappedFields.get(column.replaceAll(" ", "").toLowerCase()); + if (pd != null) { + try { + Object value = tuple[i]; + try { + bw.setPropertyValue(pd.getName(), value); + } + catch (TypeMismatchException e) { + if (value == null && primitivesDefaultedForNullValue) { + logger.debug("Intercepted TypeMismatchException for column " + column + " and column '" + + column + "' with value " + value + " when setting property '" + pd.getName() + + "' of type " + pd.getPropertyType() + + " on object: " + mappedObject); + } + else { + throw e; + } + } + if (populatedProperties != null) { + populatedProperties.add(pd.getName()); + } + } + catch (NotWritablePropertyException ex) { + throw new DataRetrievalFailureException("Unable to map column " + column + + " to property " + pd.getName(), ex); + } + } + } + + if (populatedProperties != null && !populatedProperties.equals(this.mappedProperties)) { + throw new InvalidDataAccessApiUsageException("Given ResultSet does not contain all fields " + + "necessary to populate object of class [" + this.mappedClass + "]: " + this.mappedProperties); + } + + return mappedObject; + } + + @Override + public List transformList(List list) { + return list; + } } diff --git a/src/main/java/com/slyak/spring/jpa/ContextHolder.java b/src/main/java/com/slyak/spring/jpa/ContextHolder.java index 6ef41ef..be6025f 100644 --- a/src/main/java/com/slyak/spring/jpa/ContextHolder.java +++ b/src/main/java/com/slyak/spring/jpa/ContextHolder.java @@ -6,19 +6,19 @@ /** * . - *

+ *

* * @author stormning * @version V1.0, 16/3/15. */ class ContextHolder { - public static ApplicationContext appContext; + public static ApplicationContext appContext; - public static Collection getBeansOfType(Class clazz) { - return appContext.getBeansOfType(clazz).values(); - } + public static Collection getBeansOfType(Class clazz) { + return appContext.getBeansOfType(clazz).values(); + } - public static T getBean(Class clazz) { - return appContext.getBean(clazz); - } + public static T getBean(Class clazz) { + return appContext.getBean(clazz); + } } diff --git a/src/main/java/com/slyak/spring/jpa/EntityAssembler.java b/src/main/java/com/slyak/spring/jpa/EntityAssembler.java index f569e1d..e19ab7d 100644 --- a/src/main/java/com/slyak/spring/jpa/EntityAssembler.java +++ b/src/main/java/com/slyak/spring/jpa/EntityAssembler.java @@ -5,7 +5,7 @@ /** * 对象组装器. - *

+ *

* * @author stormning * @version V1.0, 2015/8/19. @@ -13,17 +13,17 @@ @Order(Ordered.HIGHEST_PRECEDENCE) public interface EntityAssembler { - /** - * 组装 - * - * @param bean bean - */ - void assemble(T bean); + /** + * 组装 + * + * @param bean bean + */ + void assemble(T bean); - /** - * 批量组装 - * - * @param beans beans - */ - void massemble(Iterable beans); + /** + * 批量组装 + * + * @param beans beans + */ + void massemble(Iterable beans); } diff --git a/src/main/java/com/slyak/spring/jpa/EntityAssemblerMany.java b/src/main/java/com/slyak/spring/jpa/EntityAssemblerMany.java index 1fcff48..d0627e1 100644 --- a/src/main/java/com/slyak/spring/jpa/EntityAssemblerMany.java +++ b/src/main/java/com/slyak/spring/jpa/EntityAssemblerMany.java @@ -6,68 +6,68 @@ /** * . - *

+ *

* * @author stormning * @version V1.0, 2015/8/22. */ public abstract class EntityAssemblerMany implements EntityAssembler { - @Override - public void assemble(T bean) { - if (bean == null) { - return; - } - setValue(bean, safeGetValue(getKeys(bean))); - } + @Override + public void assemble(T bean) { + if (bean == null) { + return; + } + setValue(bean, safeGetValue(getKeys(bean))); + } - @Override - public void massemble(Iterable beans) { - if (beans == null || !beans.iterator().hasNext()) { - return; - } - Set keys = new HashSet(); - for (T bean : beans) { - if (bean != null) { - List ks = getKeys(bean); - if (!CollectionUtils.isEmpty(ks)) { - for (K k : ks) { - keys.add(k); - } - } - } - } + @Override + public void massemble(Iterable beans) { + if (beans == null || !beans.iterator().hasNext()) { + return; + } + Set keys = new HashSet(); + for (T bean : beans) { + if (bean != null) { + List ks = getKeys(bean); + if (!CollectionUtils.isEmpty(ks)) { + for (K k : ks) { + keys.add(k); + } + } + } + } - if (!CollectionUtils.isEmpty(keys)) { - Map valueMap = mgetValue(keys); + if (!CollectionUtils.isEmpty(keys)) { + Map valueMap = mgetValue(keys); - for (T bean : beans) { - if (bean != null) { - List ks = getKeys(bean); - if (!CollectionUtils.isEmpty(ks)) { - List values = new ArrayList(); - for (K k : ks) { - values.add(valueMap.get(k)); - } - setValue(bean, values); - } - } - } - } - } + for (T bean : beans) { + if (bean != null) { + List ks = getKeys(bean); + if (!CollectionUtils.isEmpty(ks)) { + List values = new ArrayList(); + for (K k : ks) { + values.add(valueMap.get(k)); + } + setValue(bean, values); + } + } + } + } + } - protected abstract void setValue(T bean, List value); + protected abstract void setValue(T bean, List value); - private List safeGetValue(List keys) { - if (CollectionUtils.isEmpty(keys)) { - return Collections.emptyList(); - } - return getValue(keys); - } + private List safeGetValue(List keys) { + if (CollectionUtils.isEmpty(keys)) { + return Collections.emptyList(); + } + return getValue(keys); + } - protected abstract List getValue(List keys); + protected abstract List getValue(List keys); - protected abstract List getKeys(T bean); + protected abstract List getKeys(T bean); - protected abstract Map mgetValue(Collection keys); + protected abstract Map mgetValue(Collection keys); } diff --git a/src/main/java/com/slyak/spring/jpa/EntityAssemblerOne.java b/src/main/java/com/slyak/spring/jpa/EntityAssemblerOne.java index 7ffda37..b4e4f0a 100644 --- a/src/main/java/com/slyak/spring/jpa/EntityAssemblerOne.java +++ b/src/main/java/com/slyak/spring/jpa/EntityAssemblerOne.java @@ -9,78 +9,78 @@ /** * 单对象组装器. - *

+ *

*/ public abstract class EntityAssemblerOne implements EntityAssembler { - @Override - public void assemble(T bean) { - if (bean == null) { - return; - } - K key = getKey(bean); - if (key != null) { - setValue(bean, getValue(key)); - } - } + @Override + public void assemble(T bean) { + if (bean == null) { + return; + } + K key = getKey(bean); + if (key != null) { + setValue(bean, getValue(key)); + } + } - @Override - public void massemble(Iterable beans) { - if (beans == null) { - return; - } + @Override + public void massemble(Iterable beans) { + if (beans == null) { + return; + } - List keys = new ArrayList(32); - for (T bean : beans) { - K k = getKey(bean); - if (bean != null && k != null) { - keys.add(k); - } - } - if (keys.isEmpty()) { - return; - } + List keys = new ArrayList(32); + for (T bean : beans) { + K k = getKey(bean); + if (bean != null && k != null) { + keys.add(k); + } + } + if (keys.isEmpty()) { + return; + } - if (!CollectionUtils.isEmpty(keys)) { - Map map = mgetValue(keys); - for (T bean : beans) { - K k = getKey(bean); - if (bean != null && k != null) { - setValue(bean, map.get(k)); - } - } - } - } + if (!CollectionUtils.isEmpty(keys)) { + Map map = mgetValue(keys); + for (T bean : beans) { + K k = getKey(bean); + if (bean != null && k != null) { + setValue(bean, map.get(k)); + } + } + } + } - /** - * 从原对象中提取键 - * - * @param bean 原对象 - * @return 键 - */ - protected abstract K getKey(T bean); + /** + * 从原对象中提取键 + * + * @param bean 原对象 + * @return 键 + */ + protected abstract K getKey(T bean); - /** - * 设置原对象目标值 - * - * @param bean 原对象 - * @param value 目标值 - */ - protected abstract void setValue(T bean, V value); + /** + * 设置原对象目标值 + * + * @param bean 原对象 + * @param value 目标值 + */ + protected abstract void setValue(T bean, V value); - /** - * 根据键获取目标值 - * - * @param key 键 - * @return 目标值 - */ - protected abstract V getValue(K key); + /** + * 根据键获取目标值 + * + * @param key 键 + * @return 目标值 + */ + protected abstract V getValue(K key); - /** - * 批量获取值 - * - * @param keys 键列表 - * @return 目标值map - */ - protected abstract Map mgetValue(Collection keys); + /** + * 批量获取值 + * + * @param keys 键列表 + * @return 目标值map + */ + protected abstract Map mgetValue(Collection keys); } diff --git a/src/main/java/com/slyak/spring/jpa/FreemarkerSqlTemplates.java b/src/main/java/com/slyak/spring/jpa/FreemarkerSqlTemplates.java index 58ad589..dbfd90f 100644 --- a/src/main/java/com/slyak/spring/jpa/FreemarkerSqlTemplates.java +++ b/src/main/java/com/slyak/spring/jpa/FreemarkerSqlTemplates.java @@ -43,98 +43,116 @@ */ public class FreemarkerSqlTemplates implements ResourceLoaderAware, InitializingBean { - private static Configuration cfg = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS); - private static StringTemplateLoader sqlTemplateLoader = new StringTemplateLoader(); - - static { - cfg.setTemplateLoader(sqlTemplateLoader); - } - - protected final Log logger = LogFactory.getLog(getClass()); - @PersistenceContext - private EntityManager em; - private DocumentLoader documentLoader = new DefaultDocumentLoader(); - private EntityResolver entityResolver; - private ErrorHandler errorHandler = new SimpleSaxErrorHandler(logger); - private Map lastModifiedCache = new ConcurrentHashMap(); - private Map sqlResources = new ConcurrentHashMap(); - private String encoding = "UTF-8"; - private String templateLocation = "classpath:/sqls"; - private String templateBasePackage = "**"; - private ResourceLoader resourceLoader; - - public String process(String entityName, String methodName, Map model) { - reloadIfPossible(entityName); - try { - StringWriter writer = new StringWriter(); - cfg.getTemplate(getTemplateKey(entityName, methodName), encoding).process(model, writer); - return writer.toString(); - } catch (Exception e) { - logger.error("process template error. Entity name: " + entityName + " methodName:" + methodName, e); - return StringUtils.EMPTY; - } - } - - private String getTemplateKey(String entityName, String methodName) { - return entityName + ":" + methodName; - } - - private void reloadIfPossible(String entityName) { - try { - Long lastModified = lastModifiedCache.get(entityName); - Resource resource = sqlResources.get(entityName); - long newLastModified = resource.lastModified(); - if (lastModified == null || newLastModified > lastModified) { - InputSource inputSource = new InputSource(resource.getInputStream()); - inputSource.setEncoding(encoding); - Document doc = documentLoader.loadDocument(inputSource, entityResolver, errorHandler, XmlValidationModeDetector.VALIDATION_XSD, false); - List sqes = DomUtils.getChildElementsByTagName(doc.getDocumentElement(), "sql"); - for (Element sqle : sqes) { - sqlTemplateLoader.putTemplate(getTemplateKey(entityName, sqle.getAttribute("name")), sqle.getTextContent()); - } - lastModifiedCache.put(entityName, newLastModified); - } - } catch (Exception e) { - logger.error(e); - } - } - - @Override - public void setResourceLoader(ResourceLoader resourceLoader) { - this.resourceLoader = resourceLoader; - this.entityResolver = new ResourceEntityResolver(resourceLoader); - } - - @Override - public void afterPropertiesSet() throws Exception { - Set names = new HashSet(); - Set> entities = em.getMetamodel().getEntities(); - for (EntityType entity : entities) { - names.add(entity.getName()); - } - if (!names.isEmpty()) { - String pattern; - if (StringUtils.isNotBlank(templateBasePackage)) { - pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(templateBasePackage) + "/**/*.xml"; - } else { - pattern = templateLocation.contains("xml") ? templateLocation : templateLocation + "/**/*.xml"; - } - PathMatchingResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(resourceLoader); - Resource[] resources = resourcePatternResolver.getResources(pattern); - for (Resource resource : resources) { - String resourceName = resource.getFilename().replace(".xml", ""); - if (names.contains(resourceName)) { - sqlResources.put(resourceName, resource); - } - } - } - } - - public void setTemplateLocation(String templateLocation) { - this.templateLocation = templateLocation; - } - - public void setTemplateBasePackage(String templateBasePackage) { - this.templateBasePackage = templateBasePackage; - } + private static Configuration cfg = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS); + + private static StringTemplateLoader sqlTemplateLoader = new StringTemplateLoader(); + + static { + cfg.setTemplateLoader(sqlTemplateLoader); + } + + protected final Log logger = LogFactory.getLog(getClass()); + + @PersistenceContext + private EntityManager em; + + private DocumentLoader documentLoader = new DefaultDocumentLoader(); + + private EntityResolver entityResolver; + + private ErrorHandler errorHandler = new SimpleSaxErrorHandler(logger); + + private Map lastModifiedCache = new ConcurrentHashMap(); + + private Map sqlResources = new ConcurrentHashMap(); + + private String encoding = "UTF-8"; + + private String templateLocation = "classpath:/sqls"; + + private String templateBasePackage = "**"; + + private ResourceLoader resourceLoader; + + public String process(String entityName, String methodName, Map model) { + reloadIfPossible(entityName); + try { + StringWriter writer = new StringWriter(); + cfg.getTemplate(getTemplateKey(entityName, methodName), encoding).process(model, writer); + return writer.toString(); + } + catch (Exception e) { + logger.error("process template error. Entity name: " + entityName + " methodName:" + methodName, e); + return StringUtils.EMPTY; + } + } + + private String getTemplateKey(String entityName, String methodName) { + return entityName + ":" + methodName; + } + + private void reloadIfPossible(String entityName) { + try { + Long lastModified = lastModifiedCache.get(entityName); + Resource resource = sqlResources.get(entityName); + long newLastModified = resource.lastModified(); + if (lastModified == null || newLastModified > lastModified) { + InputSource inputSource = new InputSource(resource.getInputStream()); + inputSource.setEncoding(encoding); + Document doc = documentLoader.loadDocument(inputSource, entityResolver, errorHandler, + XmlValidationModeDetector.VALIDATION_XSD, false); + List sqes = DomUtils.getChildElementsByTagName(doc.getDocumentElement(), "sql"); + for (Element sqle : sqes) { + sqlTemplateLoader + .putTemplate(getTemplateKey(entityName, sqle.getAttribute("name")), sqle.getTextContent()); + } + lastModifiedCache.put(entityName, newLastModified); + } + } + catch (Exception e) { + logger.error(e); + } + } + + @Override + public void setResourceLoader(ResourceLoader resourceLoader) { + this.resourceLoader = resourceLoader; + this.entityResolver = new ResourceEntityResolver(resourceLoader); + } + + @Override + public void afterPropertiesSet() throws Exception { + Set names = new HashSet(); + Set> entities = em.getMetamodel().getEntities(); + for (EntityType entity : entities) { + names.add(entity.getName()); + } + if (!names.isEmpty()) { + String pattern; + if (StringUtils.isNotBlank(templateBasePackage)) { + pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + + ClassUtils.convertClassNameToResourcePath(templateBasePackage) + "/**/*.xml"; + } + else { + pattern = templateLocation.contains("xml") ? templateLocation : templateLocation + "/**/*.xml"; + } + PathMatchingResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver( + resourceLoader); + Resource[] resources = resourcePatternResolver.getResources(pattern); + for (Resource resource : resources) { + String resourceName = resource.getFilename().replace(".xml", ""); + if (names.contains(resourceName)) { + sqlResources.put(resourceName, resource); + } + } + } + } + + public void setTemplateLocation(String templateLocation) { + this.templateLocation = templateLocation; + } + + public void setTemplateBasePackage(String templateBasePackage) { + this.templateBasePackage = templateBasePackage; + } } diff --git a/src/main/java/com/slyak/spring/jpa/FreemarkerTemplateQuery.java b/src/main/java/com/slyak/spring/jpa/FreemarkerTemplateQuery.java index f4f06fa..73b80e0 100644 --- a/src/main/java/com/slyak/spring/jpa/FreemarkerTemplateQuery.java +++ b/src/main/java/com/slyak/spring/jpa/FreemarkerTemplateQuery.java @@ -30,110 +30,114 @@ */ public class FreemarkerTemplateQuery extends AbstractJpaQuery { - /** - * Creates a new {@link AbstractJpaQuery} from the given {@link JpaQueryMethod}. - * - * @param method - * @param em - */ - public FreemarkerTemplateQuery(JpaQueryMethod method, EntityManager em) { - super(method, em); - } - - @Override - protected Query doCreateQuery(Object[] values) { - String nativeQuery = getQuery(values); - JpaParameters parameters = getQueryMethod().getParameters(); - ParameterAccessor accessor = new ParametersParameterAccessor(parameters, values); - String sortedQueryString = QueryUtils.applySorting(nativeQuery, accessor.getSort(), QueryUtils.detectAlias(nativeQuery)); - Query query = bind(createJpaQuery(sortedQueryString), values); - if (parameters.hasPageableParameter()) { - Pageable pageable = (Pageable) (values[parameters.getPageableIndex()]); - if (pageable != null) { - query.setFirstResult(pageable.getOffset()); - query.setMaxResults(pageable.getPageSize()); - } - } - return query; - } - - private String getQuery(Object[] values) { - return getQueryFromTpl(values); - } - - private String getQueryFromTpl(Object[] values) { - return ContextHolder.getBean(FreemarkerSqlTemplates.class).process(getEntityName(), getMethodName(), getParams(values)); - } - - private Map getParams(Object[] values) { - JpaParameters parameters = getQueryMethod().getParameters(); - //gen model - Map params = new HashMap(); - for (int i = 0; i < parameters.getNumberOfParameters(); i++) { - Object value = values[i]; - Parameter parameter = parameters.getParameter(i); - if (value != null && canBindParameter(parameter)) { - if (!QueryBuilder.isValidValue(value)) { - continue; - } - Class clz = value.getClass(); - if (clz.isPrimitive() || String.class.isAssignableFrom(clz) || Number.class.isAssignableFrom(clz)) { - params.put(parameter.getName(), value); - } else { - params = QueryBuilder.toParams(value); - } - } - } - return params; - } - - public QueryImpl createJpaQuery(String queryString) { - Class objectType = getQueryMethod().getReturnedObjectType(); - - //must be hibernate QueryImpl - QueryImpl query; - - if (getQueryMethod().isQueryForEntity()) { - query = AopTargetUtils.getTarget(getEntityManager().createNativeQuery(queryString, objectType)); - } else { - query = AopTargetUtils.getTarget(getEntityManager().createNativeQuery(queryString)); - //find generic type - ClassTypeInformation ctif = ClassTypeInformation.from(objectType); - TypeInformation actualType = ctif.getActualType(); - Class genericType = actualType.getType(); - - if (genericType != null && genericType != Void.class) { - QueryBuilder.transform(query.getHibernateQuery(), genericType); - } - } - return query; - } - - - private String getEntityName() { - return getQueryMethod().getEntityInformation().getJavaType().getSimpleName(); - } - - private String getMethodName() { - return getQueryMethod().getName(); - } - - @Override - protected TypedQuery doCreateCountQuery(Object[] values) { - QueryImpl nativeQuery = AopTargetUtils.getTarget(getEntityManager().createNativeQuery(QueryBuilder.toCountQuery(getQuery(values)))); - return bind(nativeQuery, values); - } - - public QueryImpl bind(QueryImpl query, Object[] values) { - SQLQuery sqlQuery = (SQLQuery) query.getHibernateQuery(); - Map params = getParams(values); - if (!CollectionUtils.isEmpty(params)) { - QueryBuilder.setParams(sqlQuery, params); - } - return query; - } - - protected boolean canBindParameter(Parameter parameter) { - return parameter.isBindable(); - } + /** + * Creates a new {@link AbstractJpaQuery} from the given {@link JpaQueryMethod}. + * + * @param method + * @param em + */ + public FreemarkerTemplateQuery(JpaQueryMethod method, EntityManager em) { + super(method, em); + } + + @Override + protected Query doCreateQuery(Object[] values) { + String nativeQuery = getQuery(values); + JpaParameters parameters = getQueryMethod().getParameters(); + ParameterAccessor accessor = new ParametersParameterAccessor(parameters, values); + String sortedQueryString = QueryUtils + .applySorting(nativeQuery, accessor.getSort(), QueryUtils.detectAlias(nativeQuery)); + Query query = bind(createJpaQuery(sortedQueryString), values); + if (parameters.hasPageableParameter()) { + Pageable pageable = (Pageable) (values[parameters.getPageableIndex()]); + if (pageable != null) { + query.setFirstResult(pageable.getOffset()); + query.setMaxResults(pageable.getPageSize()); + } + } + return query; + } + + private String getQuery(Object[] values) { + return getQueryFromTpl(values); + } + + private String getQueryFromTpl(Object[] values) { + return ContextHolder.getBean(FreemarkerSqlTemplates.class) + .process(getEntityName(), getMethodName(), getParams(values)); + } + + private Map getParams(Object[] values) { + JpaParameters parameters = getQueryMethod().getParameters(); + //gen model + Map params = new HashMap(); + for (int i = 0; i < parameters.getNumberOfParameters(); i++) { + Object value = values[i]; + Parameter parameter = parameters.getParameter(i); + if (value != null && canBindParameter(parameter)) { + if (!QueryBuilder.isValidValue(value)) { + continue; + } + Class clz = value.getClass(); + if (clz.isPrimitive() || String.class.isAssignableFrom(clz) || Number.class.isAssignableFrom(clz)) { + params.put(parameter.getName(), value); + } + else { + params = QueryBuilder.toParams(value); + } + } + } + return params; + } + + public QueryImpl createJpaQuery(String queryString) { + Class objectType = getQueryMethod().getReturnedObjectType(); + + //must be hibernate QueryImpl + QueryImpl query; + + if (getQueryMethod().isQueryForEntity()) { + query = AopTargetUtils.getTarget(getEntityManager().createNativeQuery(queryString, objectType)); + } + else { + query = AopTargetUtils.getTarget(getEntityManager().createNativeQuery(queryString)); + //find generic type + ClassTypeInformation ctif = ClassTypeInformation.from(objectType); + TypeInformation actualType = ctif.getActualType(); + Class genericType = actualType.getType(); + + if (genericType != null && genericType != Void.class) { + QueryBuilder.transform(query.getHibernateQuery(), genericType); + } + } + return query; + } + + private String getEntityName() { + return getQueryMethod().getEntityInformation().getJavaType().getSimpleName(); + } + + private String getMethodName() { + return getQueryMethod().getName(); + } + + @Override + protected TypedQuery doCreateCountQuery(Object[] values) { + QueryImpl nativeQuery = AopTargetUtils + .getTarget(getEntityManager().createNativeQuery(QueryBuilder.toCountQuery(getQuery(values)))); + return bind(nativeQuery, values); + } + + public QueryImpl bind(QueryImpl query, Object[] values) { + SQLQuery sqlQuery = (SQLQuery) query.getHibernateQuery(); + Map params = getParams(values); + if (!CollectionUtils.isEmpty(params)) { + QueryBuilder.setParams(sqlQuery, params); + } + return query; + } + + protected boolean canBindParameter(Parameter parameter) { + return parameter.isBindable(); + } } diff --git a/src/main/java/com/slyak/spring/jpa/GenericJpaRepository.java b/src/main/java/com/slyak/spring/jpa/GenericJpaRepository.java index 2a9d224..fd06125 100644 --- a/src/main/java/com/slyak/spring/jpa/GenericJpaRepository.java +++ b/src/main/java/com/slyak/spring/jpa/GenericJpaRepository.java @@ -10,7 +10,7 @@ /** * . - *

+ *

* * @author stormning * @version V1.0, 2015/8/7 @@ -18,15 +18,15 @@ @NoRepositoryBean public interface GenericJpaRepository extends JpaRepository { - Map mget(Collection ids); + Map mget(Collection ids); - //for cache - Map mgetOneByOne(Collection ids); + //for cache + Map mgetOneByOne(Collection ids); - //for cache - List findAllOneByOne(Collection ids); + //for cache + List findAllOneByOne(Collection ids); - void toggleStatus(ID id); + void toggleStatus(ID id); - void fakeDelete(ID... id); + void fakeDelete(ID... id); } diff --git a/src/main/java/com/slyak/spring/jpa/GenericJpaRepositoryFactory.java b/src/main/java/com/slyak/spring/jpa/GenericJpaRepositoryFactory.java index fb2e1de..e1096c5 100644 --- a/src/main/java/com/slyak/spring/jpa/GenericJpaRepositoryFactory.java +++ b/src/main/java/com/slyak/spring/jpa/GenericJpaRepositoryFactory.java @@ -28,109 +28,115 @@ * @version V1.0, 2015/8/9. */ public class GenericJpaRepositoryFactory extends JpaRepositoryFactory { - private final EntityManager entityManager; - private final PersistenceProvider extractor; - private Map, List> assemblers = new ConcurrentHashMap, List>(); + private final EntityManager entityManager; - /** - * Creates a new {@link JpaRepositoryFactory}. - * - * @param entityManager must not be {@literal null} - */ - public GenericJpaRepositoryFactory(EntityManager entityManager) { - super(entityManager); - this.entityManager = entityManager; - this.extractor = PersistenceProvider.fromEntityManager(entityManager); + private final PersistenceProvider extractor; - final AssmblerInterceptor assmblerInterceptor = new AssmblerInterceptor(); - addRepositoryProxyPostProcessor(new RepositoryProxyPostProcessor() { - @Override - public void postProcess(ProxyFactory factory, RepositoryInformation repositoryInformation) { - factory.addAdvice(assmblerInterceptor); - } - }); - } + private Map, List> assemblers = new ConcurrentHashMap, List>(); - @Override - protected QueryLookupStrategy getQueryLookupStrategy(QueryLookupStrategy.Key key, EvaluationContextProvider evaluationContextProvider) { - return TemplateQueryLookupStrategy.create(entityManager, key, extractor, evaluationContextProvider); - } + /** + * Creates a new {@link JpaRepositoryFactory}. + * + * @param entityManager must not be {@literal null} + */ + public GenericJpaRepositoryFactory(EntityManager entityManager) { + super(entityManager); + this.entityManager = entityManager; + this.extractor = PersistenceProvider.fromEntityManager(entityManager); - private List getEntityAssemblers(Class clazz) { - if (assemblers.isEmpty()) { - Collection abs = ContextHolder.getBeansOfType(EntityAssembler.class); - if (abs.isEmpty()) { - return Collections.emptyList(); - } else { - for (EntityAssembler ab : abs) { - Class p0 = getGenericParameter0(ab.getClass()); - List ass = this.assemblers.get(p0); - if (ass == null) { - ass = new ArrayList(); - assemblers.put(p0, ass); - } - ass.add(ab); - } - for (List ess : assemblers.values()) { - Collections.sort(ess, new Comparator() { - @Override - public int compare(EntityAssembler o1, EntityAssembler o2) { - return OrderUtils.getOrder(o2.getClass()) - OrderUtils.getOrder(o1.getClass()); - } - }); - } - } - } - return assemblers.get(clazz); - } + final AssmblerInterceptor assmblerInterceptor = new AssmblerInterceptor(); + addRepositoryProxyPostProcessor(new RepositoryProxyPostProcessor() { + @Override + public void postProcess(ProxyFactory factory, RepositoryInformation repositoryInformation) { + factory.addAdvice(assmblerInterceptor); + } + }); + } - private void massemble(Iterable iterable) { - if (!iterable.iterator().hasNext()) { - return; - } + @Override + protected QueryLookupStrategy getQueryLookupStrategy(QueryLookupStrategy.Key key, + EvaluationContextProvider evaluationContextProvider) { + return TemplateQueryLookupStrategy.create(entityManager, key, extractor, evaluationContextProvider); + } - Object object = iterable.iterator().next(); - if (isEntityObject(object)) { - List entityAssemblers = getEntityAssemblers(object.getClass()); - if (!CollectionUtils.isEmpty(entityAssemblers)) { - for (EntityAssembler assembler : entityAssemblers) { - assembler.massemble(iterable); - } - } - } - } + private List getEntityAssemblers(Class clazz) { + if (assemblers.isEmpty()) { + Collection abs = ContextHolder.getBeansOfType(EntityAssembler.class); + if (abs.isEmpty()) { + return Collections.emptyList(); + } + else { + for (EntityAssembler ab : abs) { + Class p0 = getGenericParameter0(ab.getClass()); + List ass = this.assemblers.get(p0); + if (ass == null) { + ass = new ArrayList(); + assemblers.put(p0, ass); + } + ass.add(ab); + } + for (List ess : assemblers.values()) { + Collections.sort(ess, new Comparator() { + @Override + public int compare(EntityAssembler o1, EntityAssembler o2) { + return OrderUtils.getOrder(o2.getClass()) - OrderUtils.getOrder(o1.getClass()); + } + }); + } + } + } + return assemblers.get(clazz); + } - private boolean isEntityObject(Object object) { - return object != null && AnnotationUtils.findAnnotation(object.getClass(), Entity.class) != null; - } + private void massemble(Iterable iterable) { + if (!iterable.iterator().hasNext()) { + return; + } - private Class getGenericParameter0(Class clzz) { - return (Class) ((ParameterizedType) clzz.getGenericSuperclass()).getActualTypeArguments()[0]; - } + Object object = iterable.iterator().next(); + if (isEntityObject(object)) { + List entityAssemblers = getEntityAssemblers(object.getClass()); + if (!CollectionUtils.isEmpty(entityAssemblers)) { + for (EntityAssembler assembler : entityAssemblers) { + assembler.massemble(iterable); + } + } + } + } - public class AssmblerInterceptor implements MethodInterceptor, AfterAdvice { + private boolean isEntityObject(Object object) { + return object != null && AnnotationUtils.findAnnotation(object.getClass(), Entity.class) != null; + } - @Override - public Object invoke(MethodInvocation invocation) throws Throwable { - Object proceed = invocation.proceed(); - if (!"save".equals(invocation.getMethod().getName())) { - if (proceed != null) { - //EntityAssembler - if (proceed instanceof Iterable) { - massemble((Iterable) proceed); - } else if (proceed instanceof Map) { - massemble(((Map) proceed).values()); - } else if (isEntityObject(proceed)) { - List entityAssemblers = getEntityAssemblers(proceed.getClass()); - if (!CollectionUtils.isEmpty(entityAssemblers)) { - for (EntityAssembler assembler : entityAssemblers) { - assembler.assemble(proceed); - } - } - } - } - } - return proceed; - } - } + private Class getGenericParameter0(Class clzz) { + return (Class) ((ParameterizedType) clzz.getGenericSuperclass()).getActualTypeArguments()[0]; + } + + public class AssmblerInterceptor implements MethodInterceptor, AfterAdvice { + + @Override + public Object invoke(MethodInvocation invocation) throws Throwable { + Object proceed = invocation.proceed(); + if (!"save".equals(invocation.getMethod().getName())) { + if (proceed != null) { + //EntityAssembler + if (proceed instanceof Iterable) { + massemble((Iterable) proceed); + } + else if (proceed instanceof Map) { + massemble(((Map) proceed).values()); + } + else if (isEntityObject(proceed)) { + List entityAssemblers = getEntityAssemblers(proceed.getClass()); + if (!CollectionUtils.isEmpty(entityAssemblers)) { + for (EntityAssembler assembler : entityAssemblers) { + assembler.assemble(proceed); + } + } + } + } + } + return proceed; + } + } } diff --git a/src/main/java/com/slyak/spring/jpa/GenericJpaRepositoryFactoryBean.java b/src/main/java/com/slyak/spring/jpa/GenericJpaRepositoryFactoryBean.java index 0a15f2e..705cd8f 100644 --- a/src/main/java/com/slyak/spring/jpa/GenericJpaRepositoryFactoryBean.java +++ b/src/main/java/com/slyak/spring/jpa/GenericJpaRepositoryFactoryBean.java @@ -12,24 +12,23 @@ /** * . - *

+ *

* * @author stormning * @version V1.0, 2015/8/8. */ public class GenericJpaRepositoryFactoryBean, T, I extends Serializable> - extends JpaRepositoryFactoryBean implements ApplicationContextAware{ + extends JpaRepositoryFactoryBean implements ApplicationContextAware { + @Override + protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) { + RepositoryFactorySupport factorySupport = new GenericJpaRepositoryFactory(entityManager); + factorySupport.setRepositoryBaseClass(GenericJpaRepositoryImpl.class); + return factorySupport; + } - @Override - protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) { - RepositoryFactorySupport factorySupport = new GenericJpaRepositoryFactory(entityManager); - factorySupport.setRepositoryBaseClass(GenericJpaRepositoryImpl.class); - return factorySupport; - } - - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - ContextHolder.appContext = applicationContext; - } + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + ContextHolder.appContext = applicationContext; + } } diff --git a/src/main/java/com/slyak/spring/jpa/GenericJpaRepositoryImpl.java b/src/main/java/com/slyak/spring/jpa/GenericJpaRepositoryImpl.java index 502be55..d664091 100644 --- a/src/main/java/com/slyak/spring/jpa/GenericJpaRepositoryImpl.java +++ b/src/main/java/com/slyak/spring/jpa/GenericJpaRepositoryImpl.java @@ -19,105 +19,106 @@ * @version V1.0, 2015/8/7 */ public class GenericJpaRepositoryImpl - extends SimpleJpaRepository implements GenericJpaRepository, Serializable { - - private EntityManager em; - - private JpaEntityInformation eif; - - private boolean isStatusAble = false; - - private Method statusReadMethod; - - private Method statusWriteMethod; - - public GenericJpaRepositoryImpl(JpaEntityInformation eif, EntityManager em) { - super(eif, em); - this.em = em; - this.eif = eif; - PropertyDescriptor descriptor = findFieldPropertyDescriptor(eif.getJavaType(), Status.class); - isStatusAble = descriptor != null; - if (isStatusAble) { - statusReadMethod = descriptor.getReadMethod(); - statusWriteMethod = descriptor.getWriteMethod(); - } - } - - @Override - public Map mget(Collection ids) { - return toMap(findAll(ids)); - } - - @Override - public Map mgetOneByOne(Collection ids) { - return toMap(findAllOneByOne(ids)); - } - - @Override - public List findAllOneByOne(Collection ids) { - List results = new ArrayList(); - for (ID id : ids) { - T one = findOne(id); - if (one != null) { - results.add(one); - } - } - return results; - } - - private Map toMap(List list) { - Map result = new LinkedHashMap(); - for (T t : list) { - if (t != null) { - result.put(eif.getId(t), t); - } - } - return result; - } - - @Override - @Transactional - public void toggleStatus(ID id) { - if (isStatusAble && id != null) { - T target = findOne(id); - if (target != null) { - Status status = (Status) ReflectionUtils.invokeMethod(statusReadMethod, target); - if (status == Status.ENABLED || status == Status.DISABLED) { - ReflectionUtils.invokeMethod(statusWriteMethod, target, status == Status.DISABLED ? Status.ENABLED : Status.DISABLED); - save(target); - } - } - } - } - - @Override - @Transactional - public void fakeDelete(ID... ids) { - for (ID id : ids) { - changeStatus(id, Status.DELETED); - } - } - - private void changeStatus(ID id, Status status) { - if (isStatusAble && id != null) { - T target = findOne(id); - if (target != null) { - Status oldStatus = (Status) ReflectionUtils.invokeMethod(statusReadMethod, target); - if (oldStatus != status) { - ReflectionUtils.invokeMethod(statusWriteMethod, target, status); - save(target); - } - } - } - } - - private PropertyDescriptor findFieldPropertyDescriptor(Class target, Class fieldClass) { - PropertyDescriptor[] propertyDescriptors = org.springframework.beans.BeanUtils.getPropertyDescriptors(target); - for (PropertyDescriptor pd : propertyDescriptors) { - if (pd.getPropertyType() == fieldClass) { - return pd; - } - } - return null; - } + extends SimpleJpaRepository implements GenericJpaRepository, Serializable { + + private EntityManager em; + + private JpaEntityInformation eif; + + private boolean isStatusAble = false; + + private Method statusReadMethod; + + private Method statusWriteMethod; + + public GenericJpaRepositoryImpl(JpaEntityInformation eif, EntityManager em) { + super(eif, em); + this.em = em; + this.eif = eif; + PropertyDescriptor descriptor = findFieldPropertyDescriptor(eif.getJavaType(), Status.class); + isStatusAble = descriptor != null; + if (isStatusAble) { + statusReadMethod = descriptor.getReadMethod(); + statusWriteMethod = descriptor.getWriteMethod(); + } + } + + @Override + public Map mget(Collection ids) { + return toMap(findAll(ids)); + } + + @Override + public Map mgetOneByOne(Collection ids) { + return toMap(findAllOneByOne(ids)); + } + + @Override + public List findAllOneByOne(Collection ids) { + List results = new ArrayList(); + for (ID id : ids) { + T one = findOne(id); + if (one != null) { + results.add(one); + } + } + return results; + } + + private Map toMap(List list) { + Map result = new LinkedHashMap(); + for (T t : list) { + if (t != null) { + result.put(eif.getId(t), t); + } + } + return result; + } + + @Override + @Transactional + public void toggleStatus(ID id) { + if (isStatusAble && id != null) { + T target = findOne(id); + if (target != null) { + Status status = (Status) ReflectionUtils.invokeMethod(statusReadMethod, target); + if (status == Status.ENABLED || status == Status.DISABLED) { + ReflectionUtils.invokeMethod(statusWriteMethod, target, + status == Status.DISABLED ? Status.ENABLED : Status.DISABLED); + save(target); + } + } + } + } + + @Override + @Transactional + public void fakeDelete(ID... ids) { + for (ID id : ids) { + changeStatus(id, Status.DELETED); + } + } + + private void changeStatus(ID id, Status status) { + if (isStatusAble && id != null) { + T target = findOne(id); + if (target != null) { + Status oldStatus = (Status) ReflectionUtils.invokeMethod(statusReadMethod, target); + if (oldStatus != status) { + ReflectionUtils.invokeMethod(statusWriteMethod, target, status); + save(target); + } + } + } + } + + private PropertyDescriptor findFieldPropertyDescriptor(Class target, Class fieldClass) { + PropertyDescriptor[] propertyDescriptors = org.springframework.beans.BeanUtils.getPropertyDescriptors(target); + for (PropertyDescriptor pd : propertyDescriptors) { + if (pd.getPropertyType() == fieldClass) { + return pd; + } + } + return null; + } } diff --git a/src/main/java/com/slyak/spring/jpa/QueryBuilder.java b/src/main/java/com/slyak/spring/jpa/QueryBuilder.java index f999641..c9f8c43 100644 --- a/src/main/java/com/slyak/spring/jpa/QueryBuilder.java +++ b/src/main/java/com/slyak/spring/jpa/QueryBuilder.java @@ -24,105 +24,116 @@ */ public class QueryBuilder { - private static final Pattern ORDERBY_PATTERN_1 = Pattern.compile("order\\s+by.+?\\)", Pattern.DOTALL | Pattern.CASE_INSENSITIVE); + private static final Pattern ORDERBY_PATTERN_1 = Pattern + .compile("order\\s+by.+?\\)", Pattern.DOTALL | Pattern.CASE_INSENSITIVE); - public static Query transform(Query query, Class clazz) { - if (Map.class.isAssignableFrom(clazz)) { - return query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP); - } else if (Number.class.isAssignableFrom(clazz) || clazz.isPrimitive() || String.class.isAssignableFrom(clazz) || Date.class.isAssignableFrom(clazz)) { - return query.setResultTransformer(new SmartTransformer(clazz)); - } else { - return query.setResultTransformer(new BeanTransformerAdapter(clazz)); - } - } + public static Query transform(Query query, Class clazz) { + if (Map.class.isAssignableFrom(clazz)) { + return query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP); + } + else if (Number.class.isAssignableFrom(clazz) || clazz.isPrimitive() || String.class.isAssignableFrom(clazz) || + Date.class.isAssignableFrom(clazz)) { + return query.setResultTransformer(new SmartTransformer(clazz)); + } + else { + return query.setResultTransformer(new BeanTransformerAdapter(clazz)); + } + } - public static SQLQuery toSQLQuery(EntityManager em, String nativeQuery, Object beanOrMap) { - Session session = em.unwrap(Session.class); - SQLQuery query = session.createSQLQuery(nativeQuery); - setParams(query, beanOrMap); - return query; - } + public static SQLQuery toSQLQuery(EntityManager em, String nativeQuery, Object beanOrMap) { + Session session = em.unwrap(Session.class); + SQLQuery query = session.createSQLQuery(nativeQuery); + setParams(query, beanOrMap); + return query; + } - public static String toCountQuery(String query) { - return ORDERBY_PATTERN_1.matcher("select count(*) from (" + query + ") as ctmp").replaceAll(")"); - } + public static String toCountQuery(String query) { + return ORDERBY_PATTERN_1.matcher("select count(*) from (" + query + ") as ctmp").replaceAll(")"); + } - public static void setParams(SQLQuery query, Object beanOrMap) { - String[] nps = query.getNamedParameters(); - if (nps != null) { - Map params = toParams(beanOrMap); - for (String key : nps) { - Object arg = params.get(key); - if (arg == null) { - query.setParameter(key, null); - } else if (arg.getClass().isArray()) { - query.setParameterList(key, (Object[]) arg); - } else if (arg instanceof Collection) { - query.setParameterList(key, ((Collection) arg)); - } else if (arg.getClass().isEnum()) { - query.setParameter(key, ((Enum) arg).ordinal()); - } else { - query.setParameter(key, arg); - } - } - } - } + public static void setParams(SQLQuery query, Object beanOrMap) { + String[] nps = query.getNamedParameters(); + if (nps != null) { + Map params = toParams(beanOrMap); + for (String key : nps) { + Object arg = params.get(key); + if (arg == null) { + query.setParameter(key, null); + } + else if (arg.getClass().isArray()) { + query.setParameterList(key, (Object[]) arg); + } + else if (arg instanceof Collection) { + query.setParameterList(key, ((Collection) arg)); + } + else if (arg.getClass().isEnum()) { + query.setParameter(key, ((Enum) arg).ordinal()); + } + else { + query.setParameter(key, arg); + } + } + } + } - @SuppressWarnings("unchecked") - public static Map toParams(Object beanOrMap) { - Map params; - if (beanOrMap instanceof Map) { - params = (Map) beanOrMap; - } else { - params = toMap(beanOrMap); - } - if (!CollectionUtils.isEmpty(params)) { - Iterator keys = params.keySet().iterator(); - while (keys.hasNext()) { - String key = keys.next(); - if (!isValidValue(params.get(key))) { - keys.remove(); - } - } - } - return params; - } + @SuppressWarnings("unchecked") + public static Map toParams(Object beanOrMap) { + Map params; + if (beanOrMap instanceof Map) { + params = (Map) beanOrMap; + } + else { + params = toMap(beanOrMap); + } + if (!CollectionUtils.isEmpty(params)) { + Iterator keys = params.keySet().iterator(); + while (keys.hasNext()) { + String key = keys.next(); + if (!isValidValue(params.get(key))) { + keys.remove(); + } + } + } + return params; + } - public static boolean isValidValue(Object object) { - if (object == null) { - return false; - } - if (object instanceof Number && ((Number) object).longValue() == 0) { - return false; - } - return !(object instanceof Collection && CollectionUtils.isEmpty((Collection) object)); - } + public static boolean isValidValue(Object object) { + if (object == null) { + return false; + } + if (object instanceof Number && ((Number) object).longValue() == 0) { + return false; + } + return !(object instanceof Collection && CollectionUtils.isEmpty((Collection) object)); + } - public static Map toMap(Object bean) { - if (bean == null) { - return Collections.emptyMap(); - } - try { - Map description = new HashMap(); - if (bean instanceof DynaBean) { - DynaProperty[] descriptors = ((DynaBean) bean).getDynaClass().getDynaProperties(); - for (int i = 0; i < descriptors.length; i++) { - String name = descriptors[i].getName(); - description.put(name, BeanUtils.getProperty(bean, name)); - } - } else { - PropertyDescriptor[] descriptors = PropertyUtils.getPropertyDescriptors(bean); - for (int i = 0; i < descriptors.length; i++) { - String name = descriptors[i].getName(); - if (PropertyUtils.getReadMethod(descriptors[i]) != null) { - description.put(name, PropertyUtils.getNestedProperty(bean, name)); - } - } - } - return description; - } catch (Exception e) { - return Collections.emptyMap(); - } - } + public static Map toMap(Object bean) { + if (bean == null) { + return Collections.emptyMap(); + } + try { + Map description = new HashMap(); + if (bean instanceof DynaBean) { + DynaProperty[] descriptors = ((DynaBean) bean).getDynaClass().getDynaProperties(); + for (int i = 0; i < descriptors.length; i++) { + String name = descriptors[i].getName(); + description.put(name, BeanUtils.getProperty(bean, name)); + } + } + else { + PropertyDescriptor[] descriptors = PropertyUtils.getPropertyDescriptors(bean); + for (int i = 0; i < descriptors.length; i++) { + String name = descriptors[i].getName(); + if (PropertyUtils.getReadMethod(descriptors[i]) != null) { + description.put(name, PropertyUtils.getNestedProperty(bean, name)); + } + } + } + return description; + } + catch (Exception e) { + return Collections.emptyMap(); + } + } } diff --git a/src/main/java/com/slyak/spring/jpa/QueryTemplate.java b/src/main/java/com/slyak/spring/jpa/QueryTemplate.java index 78e1db5..9237036 100644 --- a/src/main/java/com/slyak/spring/jpa/QueryTemplate.java +++ b/src/main/java/com/slyak/spring/jpa/QueryTemplate.java @@ -6,5 +6,5 @@ * @author stormning on 16/6/5. */ public interface QueryTemplate { - String getQueryString(); + String getQueryString(); } diff --git a/src/main/java/com/slyak/spring/jpa/QueryTemplateContext.java b/src/main/java/com/slyak/spring/jpa/QueryTemplateContext.java index 9039d87..ed606d8 100644 --- a/src/main/java/com/slyak/spring/jpa/QueryTemplateContext.java +++ b/src/main/java/com/slyak/spring/jpa/QueryTemplateContext.java @@ -6,5 +6,5 @@ * @author stormning on 16/6/5. */ public interface QueryTemplateContext { - QueryTemplate lookup(String namedQueryName); + QueryTemplate lookup(String namedQueryName); } diff --git a/src/main/java/com/slyak/spring/jpa/SmartTransformer.java b/src/main/java/com/slyak/spring/jpa/SmartTransformer.java index 91582f9..c61d964 100644 --- a/src/main/java/com/slyak/spring/jpa/SmartTransformer.java +++ b/src/main/java/com/slyak/spring/jpa/SmartTransformer.java @@ -7,30 +7,31 @@ /** * . - *

+ *

* * @author stormning * @version V1.0, 2015/9/1. */ public class SmartTransformer extends BasicTransformerAdapter { - private static DefaultConversionService conversionService = new DefaultConversionService(); - private final Class clazz; - - public SmartTransformer(Class clazz) { - this.clazz = clazz; - } - - @Override - public Object transformTuple(Object[] tuple, String[] aliases) { - if (tuple != null && tuple.length > 0) { - return conversionService.convert(tuple[0], clazz); - } - return null; - } - - @Override - public List transformList(List list) { - return super.transformList(list); - } + private static DefaultConversionService conversionService = new DefaultConversionService(); + + private final Class clazz; + + public SmartTransformer(Class clazz) { + this.clazz = clazz; + } + + @Override + public Object transformTuple(Object[] tuple, String[] aliases) { + if (tuple != null && tuple.length > 0) { + return conversionService.convert(tuple[0], clazz); + } + return null; + } + + @Override + public List transformList(List list) { + return super.transformList(list); + } } diff --git a/src/main/java/com/slyak/spring/jpa/Status.java b/src/main/java/com/slyak/spring/jpa/Status.java index 9d9c3fc..433c5b5 100644 --- a/src/main/java/com/slyak/spring/jpa/Status.java +++ b/src/main/java/com/slyak/spring/jpa/Status.java @@ -2,11 +2,11 @@ /** * . - *

+ *

* * @author stormning * @version V1.0, 16/3/11. */ public enum Status { - ENABLED, DISABLED, DELETED + ENABLED, DISABLED, DELETED } diff --git a/src/main/java/com/slyak/spring/jpa/TemplateQuery.java b/src/main/java/com/slyak/spring/jpa/TemplateQuery.java index 3a7bc82..5092a98 100644 --- a/src/main/java/com/slyak/spring/jpa/TemplateQuery.java +++ b/src/main/java/com/slyak/spring/jpa/TemplateQuery.java @@ -6,15 +6,15 @@ /** * . - *

+ *

* * @author stormning * @version V1.0, 2015/8/9. */ @Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.METHOD}) +@Target({ ElementType.METHOD }) @QueryAnnotation @Documented public @interface TemplateQuery { - String value() default ""; + String value() default ""; } diff --git a/src/main/java/com/slyak/spring/jpa/TemplateQueryObject.java b/src/main/java/com/slyak/spring/jpa/TemplateQueryObject.java index 40eea32..997ddef 100644 --- a/src/main/java/com/slyak/spring/jpa/TemplateQueryObject.java +++ b/src/main/java/com/slyak/spring/jpa/TemplateQueryObject.java @@ -6,15 +6,15 @@ /** * . - *

+ *

* * @author stormning * @version V1.0, 2015/8/9. */ @Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.TYPE}) +@Target({ ElementType.TYPE }) @QueryAnnotation @Documented public @interface TemplateQueryObject { - String value() default ""; + String value() default ""; } diff --git a/src/main/java/com/slyak/util/AopTargetUtils.java b/src/main/java/com/slyak/util/AopTargetUtils.java index 0242816..4d38eb6 100644 --- a/src/main/java/com/slyak/util/AopTargetUtils.java +++ b/src/main/java/com/slyak/util/AopTargetUtils.java @@ -8,56 +8,59 @@ /** * . - *

+ *

* * @author stormning * @version V1.0, 16/3/17. */ public class AopTargetUtils { + /** + * 获取 目标对象 + * + * @param proxy 代理对象 + * @return 目标对象 + */ + @SuppressWarnings("unchecked") + public static T getTarget(Object proxy) { + if (Proxy.isProxyClass(proxy.getClass())) { + return getJdkDynamicProxyTargetObject(proxy); + } + else if (ClassUtils.isCglibProxy(proxy)) { + return getCglibProxyTargetObject(proxy); + } + else { + return (T) proxy; + } + } - /** - * 获取 目标对象 - * - * @param proxy 代理对象 - * @return 目标对象 - */ - @SuppressWarnings("unchecked") - public static T getTarget(Object proxy) { - if (Proxy.isProxyClass(proxy.getClass())) { - return getJdkDynamicProxyTargetObject(proxy); - } else if (ClassUtils.isCglibProxy(proxy)) { - return getCglibProxyTargetObject(proxy); - } else { - return (T) proxy; - } - } + @SuppressWarnings("unchecked") + private static T getCglibProxyTargetObject(Object proxy) { + try { + Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0"); + h.setAccessible(true); + Object dynamicAdvisedInterceptor = h.get(proxy); + Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised"); + advised.setAccessible(true); + return (T) (((AdvisedSupport) advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget()); + } + catch (Exception e) { + throw new RuntimeException(e); + } + } - @SuppressWarnings("unchecked") - private static T getCglibProxyTargetObject(Object proxy) { - try { - Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0"); - h.setAccessible(true); - Object dynamicAdvisedInterceptor = h.get(proxy); - Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised"); - advised.setAccessible(true); - return (T) (((AdvisedSupport) advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget()); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - @SuppressWarnings("unchecked") - private static T getJdkDynamicProxyTargetObject(Object proxy) { - try { - Field h = proxy.getClass().getSuperclass().getDeclaredField("h"); - h.setAccessible(true); - Object proxy_ = h.get(proxy); - Field f = proxy_.getClass().getDeclaredField("target"); - f.setAccessible(true); - return (T) f.get(proxy_); - } catch (Exception e) { - throw new RuntimeException(e); - } - } + @SuppressWarnings("unchecked") + private static T getJdkDynamicProxyTargetObject(Object proxy) { + try { + Field h = proxy.getClass().getSuperclass().getDeclaredField("h"); + h.setAccessible(true); + Object proxy_ = h.get(proxy); + Field f = proxy_.getClass().getDeclaredField("target"); + f.setAccessible(true); + return (T) f.get(proxy_); + } + catch (Exception e) { + throw new RuntimeException(e); + } + } } diff --git a/src/main/resources/com/slyak/spring/jpa/templatequery.xsd b/src/main/resources/com/slyak/spring/jpa/templatequery.xsd index 4b6f414..ee26397 100644 --- a/src/main/resources/com/slyak/spring/jpa/templatequery.xsd +++ b/src/main/resources/com/slyak/spring/jpa/templatequery.xsd @@ -1,17 +1,18 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/java/com/slyak/spring/jpa/AppConfig.java b/src/test/java/com/slyak/spring/jpa/AppConfig.java index cea0013..2ca8a6a 100644 --- a/src/test/java/com/slyak/spring/jpa/AppConfig.java +++ b/src/test/java/com/slyak/spring/jpa/AppConfig.java @@ -27,36 +27,36 @@ @EnableJpaRepositories(repositoryBaseClass = GenericJpaRepositoryImpl.class, repositoryFactoryBeanClass = GenericJpaRepositoryFactoryBean.class) class AppConfig { - @Bean - public DataSource dataSource() { - return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.DERBY).build(); - } - - @Bean - public JpaTransactionManager transactionManager(EntityManagerFactory emf) { - return new JpaTransactionManager(emf); - } - - @Bean - public JpaVendorAdapter jpaVendorAdapter() { - HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter(); - jpaVendorAdapter.setDatabase(Database.DERBY); - jpaVendorAdapter.setGenerateDdl(true); - return jpaVendorAdapter; - } - - @Bean - public LocalContainerEntityManagerFactoryBean entityManagerFactory() { - LocalContainerEntityManagerFactoryBean lemfb = new LocalContainerEntityManagerFactoryBean(); - lemfb.setDataSource(dataSource()); - lemfb.setJpaVendorAdapter(jpaVendorAdapter()); - lemfb.setPackagesToScan("com.slyak.spring.jpa"); - return lemfb; - } - - @Bean - public FreemarkerSqlTemplates freemarkerSqlTemplates() { - return new FreemarkerSqlTemplates(); - } + @Bean + public DataSource dataSource() { + return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.DERBY).build(); + } + + @Bean + public JpaTransactionManager transactionManager(EntityManagerFactory emf) { + return new JpaTransactionManager(emf); + } + + @Bean + public JpaVendorAdapter jpaVendorAdapter() { + HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter(); + jpaVendorAdapter.setDatabase(Database.DERBY); + jpaVendorAdapter.setGenerateDdl(true); + return jpaVendorAdapter; + } + + @Bean + public LocalContainerEntityManagerFactoryBean entityManagerFactory() { + LocalContainerEntityManagerFactoryBean lemfb = new LocalContainerEntityManagerFactoryBean(); + lemfb.setDataSource(dataSource()); + lemfb.setJpaVendorAdapter(jpaVendorAdapter()); + lemfb.setPackagesToScan("com.slyak.spring.jpa"); + return lemfb; + } + + @Bean + public FreemarkerSqlTemplates freemarkerSqlTemplates() { + return new FreemarkerSqlTemplates(); + } } diff --git a/src/test/java/com/slyak/spring/jpa/JpaTest.java b/src/test/java/com/slyak/spring/jpa/JpaTest.java index 7bbdecd..14bdb6c 100644 --- a/src/test/java/com/slyak/spring/jpa/JpaTest.java +++ b/src/test/java/com/slyak/spring/jpa/JpaTest.java @@ -14,7 +14,7 @@ /** * . - *

+ *

* * @author stormning * @version V1.0, 16/3/15. @@ -22,42 +22,42 @@ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = AppConfig.class) public class JpaTest { - @Autowired - private SampleRepository sampleRepository; - - @Before - public void addSomeSample() { - sampleRepository.deleteAll(); - for (int i = 0; i < 10; i++) { - Sample sample = new Sample(); - sample.setContent("hello world" + i); - sampleRepository.save(sample); - } - } - - @Test - public void findByTemplateQuery() { - Page samples = sampleRepository.findByContent("world", new PageRequest(1, 100)); - Assert.assertTrue(samples.getTotalElements() == 10); - } - - @Test - public void countByTemplateQuery() { - long count = sampleRepository.countContent("world"); - Assert.assertTrue(count == 10); - } - - @Test - public void findByTemplateQueryAndReturnDTOs() { - List dtos = sampleRepository.findDtos(); - Assert.assertTrue(dtos.size() == 10); - } - - @Test - public void findByTemplateQueryWithTemplateQueryObject() { - SampleQuery sq = new SampleQuery(); - sq.setContent("world"); - List samples = sampleRepository.findByTemplateQueryObject(sq,null); - Assert.assertTrue(samples.size() == 10); - } + @Autowired + private SampleRepository sampleRepository; + + @Before + public void addSomeSample() { + sampleRepository.deleteAll(); + for (int i = 0; i < 10; i++) { + Sample sample = new Sample(); + sample.setContent("hello world" + i); + sampleRepository.save(sample); + } + } + + @Test + public void findByTemplateQuery() { + Page samples = sampleRepository.findByContent("world", new PageRequest(1, 100)); + Assert.assertTrue(samples.getTotalElements() == 10); + } + + @Test + public void countByTemplateQuery() { + long count = sampleRepository.countContent("world"); + Assert.assertTrue(count == 10); + } + + @Test + public void findByTemplateQueryAndReturnDTOs() { + List dtos = sampleRepository.findDtos(); + Assert.assertTrue(dtos.size() == 10); + } + + @Test + public void findByTemplateQueryWithTemplateQueryObject() { + SampleQuery sq = new SampleQuery(); + sq.setContent("world"); + List samples = sampleRepository.findByTemplateQueryObject(sq, null); + Assert.assertTrue(samples.size() == 10); + } } diff --git a/src/test/java/com/slyak/spring/jpa/Sample.java b/src/test/java/com/slyak/spring/jpa/Sample.java index 557a172..451daeb 100644 --- a/src/test/java/com/slyak/spring/jpa/Sample.java +++ b/src/test/java/com/slyak/spring/jpa/Sample.java @@ -4,7 +4,7 @@ /** * . - *

+ *

* * @author stormning * @version V1.0, 16/3/15. @@ -12,26 +12,26 @@ @Entity @Table(name = "t_sample") public class Sample { - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - private long id; + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private long id; - @Column - private String content; + @Column + private String content; - public long getId() { - return id; - } + public long getId() { + return id; + } - public void setId(long id) { - this.id = id; - } + public void setId(long id) { + this.id = id; + } - public String getContent() { - return content; - } + public String getContent() { + return content; + } - public void setContent(String content) { - this.content = content; - } + public void setContent(String content) { + this.content = content; + } } diff --git a/src/test/java/com/slyak/spring/jpa/SampleDTO.java b/src/test/java/com/slyak/spring/jpa/SampleDTO.java index 9c4b039..470ac16 100644 --- a/src/test/java/com/slyak/spring/jpa/SampleDTO.java +++ b/src/test/java/com/slyak/spring/jpa/SampleDTO.java @@ -2,30 +2,30 @@ /** * . - *

+ *

* * @author stormning * @version V1.0, 16/3/15. */ public class SampleDTO { - private long id; + private long id; - private String contentShow; + private String contentShow; - public long getId() { - return id; - } + public long getId() { + return id; + } - public void setId(long id) { - this.id = id; - } + public void setId(long id) { + this.id = id; + } - public String getContentShow() { - return contentShow; - } + public String getContentShow() { + return contentShow; + } - public void setContentShow(String contentShow) { - this.contentShow = contentShow; - } + public void setContentShow(String contentShow) { + this.contentShow = contentShow; + } } diff --git a/src/test/java/com/slyak/spring/jpa/SampleQuery.java b/src/test/java/com/slyak/spring/jpa/SampleQuery.java index b4fe1c7..724c3fe 100644 --- a/src/test/java/com/slyak/spring/jpa/SampleQuery.java +++ b/src/test/java/com/slyak/spring/jpa/SampleQuery.java @@ -2,22 +2,22 @@ /** * . - *

+ *

* * @author stormning * @version V1.0, 16/3/15. */ public class SampleQuery { - private String content; + private String content; - public String getContent() { - return content; - } + public String getContent() { + return content; + } - public void setContent(String content) { - if (content != null) { - this.content = "%" + content + "%"; - } - } + public void setContent(String content) { + if (content != null) { + this.content = "%" + content + "%"; + } + } } diff --git a/src/test/java/com/slyak/spring/jpa/SampleRepository.java b/src/test/java/com/slyak/spring/jpa/SampleRepository.java index 0453b57..0589b00 100644 --- a/src/test/java/com/slyak/spring/jpa/SampleRepository.java +++ b/src/test/java/com/slyak/spring/jpa/SampleRepository.java @@ -7,22 +7,22 @@ /** * . - *

+ *

* * @author stormning * @version V1.0, 16/3/15. */ public interface SampleRepository extends GenericJpaRepository { - @TemplateQuery - Page findByContent(String content, Pageable pageable); + @TemplateQuery + Page findByContent(String content, Pageable pageable); - @TemplateQuery - List findByTemplateQueryObject(SampleQuery sampleQuery,Pageable pageable); + @TemplateQuery + List findByTemplateQueryObject(SampleQuery sampleQuery, Pageable pageable); - @TemplateQuery - Long countContent(String content); + @TemplateQuery + Long countContent(String content); - @TemplateQuery - List findDtos(); + @TemplateQuery + List findDtos(); } diff --git a/src/test/resources/com/slyak/spring/jpa/Sample.xml b/src/test/resources/com/slyak/spring/jpa/Sample.xml index a488137..dc8e824 100644 --- a/src/test/resources/com/slyak/spring/jpa/Sample.xml +++ b/src/test/resources/com/slyak/spring/jpa/Sample.xml @@ -1,7 +1,7 @@ - +