001/* 002 GRANITE DATA SERVICES 003 Copyright (C) 2011 GRANITE DATA SERVICES S.A.S. 004 005 This file is part of Granite Data Services. 006 007 Granite Data Services is free software; you can redistribute it and/or modify 008 it under the terms of the GNU Library General Public License as published by 009 the Free Software Foundation; either version 2 of the License, or (at your 010 option) any later version. 011 012 Granite Data Services is distributed in the hope that it will be useful, but 013 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 014 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License 015 for more details. 016 017 You should have received a copy of the GNU Library General Public License 018 along with this library; if not, see <http://www.gnu.org/licenses/>. 019*/ 020 021package org.granite.tide.spring.data; 022 023import java.beans.BeanInfo; 024import java.beans.Introspector; 025import java.beans.PropertyDescriptor; 026import java.util.ArrayList; 027import java.util.List; 028 029import javax.persistence.criteria.CriteriaBuilder; 030import javax.persistence.criteria.CriteriaQuery; 031import javax.persistence.criteria.Predicate; 032import javax.persistence.criteria.Root; 033 034import org.springframework.data.jpa.domain.Specification; 035 036public class FilterBeanSpecification<T> implements Specification<T> { 037 038 private Object filter; 039 040 private FilterBeanSpecification(Object filter) { 041 this.filter = filter; 042 } 043 044 public static <T> FilterBeanSpecification<T> byBean(Object filter) { 045 return new FilterBeanSpecification<T>(filter); 046 } 047 048 public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder) { 049 List<Predicate> predicates = new ArrayList<Predicate>(); 050 051 // Query by bean filter 052 PropertyDescriptor[] pds = null; 053 try { 054 BeanInfo info = Introspector.getBeanInfo(filter.getClass()); 055 pds = info.getPropertyDescriptors(); 056 } 057 catch (Exception e) { 058 throw new RuntimeException("Could not introspect filter bean", e); 059 } 060 061 for (PropertyDescriptor pd : pds) { 062 if (!pd.getReadMethod().isAnnotationPresent(FilterMapping.class)) 063 continue; 064 065 FilterMapping mapping = pd.getReadMethod().getAnnotation(FilterMapping.class); 066 if (root.get(mapping.value()) == null) 067 throw new RuntimeException("Invalid filter mapping, path: " + mapping.value()); 068 069 Object value = null; 070 try { 071 value = pd.getReadMethod().invoke(filter); 072 } 073 catch (Exception e) { 074 throw new RuntimeException("Could not get filter property " + pd.getName(), e); 075 } 076 077 Predicate predicate = FilterSpecUtil.buildPredicate(root, builder, pd.getReadMethod().getReturnType(), mapping.value(), value); 078 if (predicate != null) 079 predicates.add(predicate); 080 } 081 082 if (predicates.size() > 0) 083 return builder.and(predicates.toArray(new Predicate[predicates.size()])); 084 085 return null; 086 } 087}