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