001/* 002 * Copyright 2012-2018 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 * http://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.boot.jdbc; 018 019import java.sql.Wrapper; 020 021import javax.sql.DataSource; 022 023import org.springframework.aop.framework.AopProxyUtils; 024import org.springframework.aop.support.AopUtils; 025import org.springframework.jdbc.datasource.DelegatingDataSource; 026import org.springframework.util.ClassUtils; 027 028/** 029 * Unwraps a {@link DataSource} that may have been proxied or wrapped in a custom 030 * {@link Wrapper} such as {@link DelegatingDataSource}. 031 * 032 * @author Tadaya Tsuyukubo 033 * @author Stephane Nicoll 034 * @since 2.0.7 035 */ 036public final class DataSourceUnwrapper { 037 038 private static final boolean DELEGATING_DATA_SOURCE_PRESENT = ClassUtils.isPresent( 039 "org.springframework.jdbc.datasource.DelegatingDataSource", 040 DataSourceUnwrapper.class.getClassLoader()); 041 042 private DataSourceUnwrapper() { 043 } 044 045 /** 046 * Return an object that implements the given {@code target} type, unwrapping delegate 047 * or proxy if necessary. 048 * @param dataSource the datasource to handle 049 * @param target the type that the result must implement 050 * @param <T> the target type 051 * @return an object that implements the target type or {@code null} 052 */ 053 public static <T> T unwrap(DataSource dataSource, Class<T> target) { 054 if (target.isInstance(dataSource)) { 055 return target.cast(dataSource); 056 } 057 T unwrapped = safeUnwrap(dataSource, target); 058 if (unwrapped != null) { 059 return unwrapped; 060 } 061 if (DELEGATING_DATA_SOURCE_PRESENT) { 062 DataSource targetDataSource = DelegatingDataSourceUnwrapper 063 .getTargetDataSource(dataSource); 064 if (targetDataSource != null) { 065 return unwrap(targetDataSource, target); 066 } 067 } 068 if (AopUtils.isAopProxy(dataSource)) { 069 Object proxyTarget = AopProxyUtils.getSingletonTarget(dataSource); 070 if (proxyTarget instanceof DataSource) { 071 return unwrap((DataSource) proxyTarget, target); 072 } 073 } 074 return null; 075 } 076 077 private static <S> S safeUnwrap(Wrapper wrapper, Class<S> target) { 078 try { 079 return wrapper.unwrap(target); 080 } 081 catch (Exception ex) { 082 return null; 083 } 084 } 085 086 private static class DelegatingDataSourceUnwrapper { 087 088 private static DataSource getTargetDataSource(DataSource dataSource) { 089 if (dataSource instanceof DelegatingDataSource) { 090 return ((DelegatingDataSource) dataSource).getTargetDataSource(); 091 } 092 return null; 093 } 094 095 } 096 097}