001/* 002 * Copyright 2002-2017 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.dao.support; 018 019import java.util.Collection; 020 021import org.springframework.dao.DataAccessException; 022import org.springframework.dao.EmptyResultDataAccessException; 023import org.springframework.dao.IncorrectResultSizeDataAccessException; 024import org.springframework.dao.TypeMismatchDataAccessException; 025import org.springframework.util.Assert; 026import org.springframework.util.CollectionUtils; 027import org.springframework.util.NumberUtils; 028 029/** 030 * Miscellaneous utility methods for DAO implementations. 031 * Useful with any data access technology. 032 * 033 * @author Juergen Hoeller 034 * @since 1.0.2 035 */ 036public abstract class DataAccessUtils { 037 038 /** 039 * Return a single result object from the given Collection. 040 * <p>Returns {@code null} if 0 result objects found; 041 * throws an exception if more than 1 element found. 042 * @param results the result Collection (can be {@code null}) 043 * @return the single result object, or {@code null} if none 044 * @throws IncorrectResultSizeDataAccessException if more than one 045 * element has been found in the given Collection 046 */ 047 public static <T> T singleResult(Collection<T> results) throws IncorrectResultSizeDataAccessException { 048 if (CollectionUtils.isEmpty(results)) { 049 return null; 050 } 051 if (results.size() > 1) { 052 throw new IncorrectResultSizeDataAccessException(1, results.size()); 053 } 054 return results.iterator().next(); 055 } 056 057 /** 058 * Return a single result object from the given Collection. 059 * <p>Throws an exception if 0 or more than 1 element found. 060 * @param results the result Collection (can be {@code null}) 061 * @return the single result object 062 * @throws IncorrectResultSizeDataAccessException if more than one 063 * element has been found in the given Collection 064 * @throws EmptyResultDataAccessException if no element at all 065 * has been found in the given Collection 066 */ 067 public static <T> T requiredSingleResult(Collection<T> results) throws IncorrectResultSizeDataAccessException { 068 if (CollectionUtils.isEmpty(results)) { 069 throw new EmptyResultDataAccessException(1); 070 } 071 if (results.size() > 1) { 072 throw new IncorrectResultSizeDataAccessException(1, results.size()); 073 } 074 return results.iterator().next(); 075 } 076 077 /** 078 * Return a unique result object from the given Collection. 079 * <p>Returns {@code null} if 0 result objects found; 080 * throws an exception if more than 1 instance found. 081 * @param results the result Collection (can be {@code null}) 082 * @return the unique result object, or {@code null} if none 083 * @throws IncorrectResultSizeDataAccessException if more than one 084 * result object has been found in the given Collection 085 * @see org.springframework.util.CollectionUtils#hasUniqueObject 086 */ 087 public static <T> T uniqueResult(Collection<T> results) throws IncorrectResultSizeDataAccessException { 088 if (CollectionUtils.isEmpty(results)) { 089 return null; 090 } 091 if (!CollectionUtils.hasUniqueObject(results)) { 092 throw new IncorrectResultSizeDataAccessException(1, results.size()); 093 } 094 return results.iterator().next(); 095 } 096 097 /** 098 * Return a unique result object from the given Collection. 099 * <p>Throws an exception if 0 or more than 1 instance found. 100 * @param results the result Collection (can be {@code null}) 101 * @return the unique result object 102 * @throws IncorrectResultSizeDataAccessException if more than one 103 * result object has been found in the given Collection 104 * @throws EmptyResultDataAccessException if no result object at all 105 * has been found in the given Collection 106 * @see org.springframework.util.CollectionUtils#hasUniqueObject 107 */ 108 public static <T> T requiredUniqueResult(Collection<T> results) throws IncorrectResultSizeDataAccessException { 109 if (CollectionUtils.isEmpty(results)) { 110 throw new EmptyResultDataAccessException(1); 111 } 112 if (!CollectionUtils.hasUniqueObject(results)) { 113 throw new IncorrectResultSizeDataAccessException(1, results.size()); 114 } 115 return results.iterator().next(); 116 } 117 118 /** 119 * Return a unique result object from the given Collection. 120 * Throws an exception if 0 or more than 1 result objects found, 121 * of if the unique result object is not convertible to the 122 * specified required type. 123 * @param results the result Collection (can be {@code null}) 124 * @return the unique result object 125 * @throws IncorrectResultSizeDataAccessException if more than one 126 * result object has been found in the given Collection 127 * @throws EmptyResultDataAccessException if no result object 128 * at all has been found in the given Collection 129 * @throws TypeMismatchDataAccessException if the unique object does 130 * not match the specified required type 131 */ 132 @SuppressWarnings("unchecked") 133 public static <T> T objectResult(Collection<?> results, Class<T> requiredType) 134 throws IncorrectResultSizeDataAccessException, TypeMismatchDataAccessException { 135 136 Object result = requiredUniqueResult(results); 137 if (requiredType != null && !requiredType.isInstance(result)) { 138 if (String.class == requiredType) { 139 result = result.toString(); 140 } 141 else if (Number.class.isAssignableFrom(requiredType) && Number.class.isInstance(result)) { 142 try { 143 result = NumberUtils.convertNumberToTargetClass(((Number) result), (Class<? extends Number>) requiredType); 144 } 145 catch (IllegalArgumentException ex) { 146 throw new TypeMismatchDataAccessException(ex.getMessage()); 147 } 148 } 149 else { 150 throw new TypeMismatchDataAccessException( 151 "Result object is of type [" + result.getClass().getName() + 152 "] and could not be converted to required type [" + requiredType.getName() + "]"); 153 } 154 } 155 return (T) result; 156 } 157 158 /** 159 * Return a unique int result from the given Collection. 160 * Throws an exception if 0 or more than 1 result objects found, 161 * of if the unique result object is not convertible to an int. 162 * @param results the result Collection (can be {@code null}) 163 * @return the unique int result 164 * @throws IncorrectResultSizeDataAccessException if more than one 165 * result object has been found in the given Collection 166 * @throws EmptyResultDataAccessException if no result object 167 * at all has been found in the given Collection 168 * @throws TypeMismatchDataAccessException if the unique object 169 * in the collection is not convertible to an int 170 */ 171 public static int intResult(Collection<?> results) 172 throws IncorrectResultSizeDataAccessException, TypeMismatchDataAccessException { 173 174 return objectResult(results, Number.class).intValue(); 175 } 176 177 /** 178 * Return a unique long result from the given Collection. 179 * Throws an exception if 0 or more than 1 result objects found, 180 * of if the unique result object is not convertible to a long. 181 * @param results the result Collection (can be {@code null}) 182 * @return the unique long result 183 * @throws IncorrectResultSizeDataAccessException if more than one 184 * result object has been found in the given Collection 185 * @throws EmptyResultDataAccessException if no result object 186 * at all has been found in the given Collection 187 * @throws TypeMismatchDataAccessException if the unique object 188 * in the collection is not convertible to a long 189 */ 190 public static long longResult(Collection<?> results) 191 throws IncorrectResultSizeDataAccessException, TypeMismatchDataAccessException { 192 193 return objectResult(results, Number.class).longValue(); 194 } 195 196 197 /** 198 * Return a translated exception if this is appropriate, 199 * otherwise return the given exception as-is. 200 * @param rawException an exception that we may wish to translate 201 * @param pet PersistenceExceptionTranslator to use to perform the translation 202 * @return a translated persistence exception if translation is possible, 203 * or the raw exception if it is not 204 */ 205 public static RuntimeException translateIfNecessary( 206 RuntimeException rawException, PersistenceExceptionTranslator pet) { 207 208 Assert.notNull(pet, "PersistenceExceptionTranslator must not be null"); 209 DataAccessException dex = pet.translateExceptionIfPossible(rawException); 210 return (dex != null ? dex : rawException); 211 } 212 213}