/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package groovy.sql; import groovy.lang.GroovyObject; import groovy.lang.GroovySystem; import groovy.lang.MetaClass; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.sql.ResultSet; import org.codehaus.groovy.runtime.InvokerHelper; /** * GroovyResultSetProxy is used to create a proxy for GroovyResultSet. * Due to the version incompatibility between java 6 and older versions * methods with additional logic were moved into an extension class. When * getting properties or calling methods, the runtime will try to first * execute these on the extension and then on the ResultSet itself. * This way it is possible to replace and add methods. To overload methods * from ResultSet all methods have to be implemented on the extension * class. * * @author Jochen Theodorou */ public final class GroovyResultSetProxy implements InvocationHandler { private final GroovyResultSetExtension extension; /** * Creates a new proxy instance. * This will create the extension automatically using * GroovyResultSetExtension * * @param set the result set to delegate to * @see GroovyResultSetExtension */ public GroovyResultSetProxy(ResultSet set) { extension = new GroovyResultSetExtension(set); } /** * Creates a new proxy instance with a custom extension. * * @param ext the extension * @see GroovyResultSetExtension */ public GroovyResultSetProxy(GroovyResultSetExtension ext) { extension = ext; } /** * Invokes a method for the GroovyResultSet. * This will try to invoke the given method first on the extension * and then on the result set given as proxy parameter. * * @param proxy the result set * @param method the method name of this method will be used * to make a call on the extension. If this fails the call will be * done on the proxy instead * @param args for the call * @see ResultSet * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[]) */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String name = method.getName(); if (method.getDeclaringClass() == GroovyObject.class) { if (name.equals("getMetaClass")) { return getMetaClass(); } else if (name.equals("setMetaClass")) { return setMetaClass((MetaClass) args[0]); } } return InvokerHelper.invokeMethod(extension, method.getName(), args); } private MetaClass metaClass; private MetaClass setMetaClass(MetaClass mc) { metaClass = mc; return mc; } /** * This class is introduced as a workaround for GROOVY-6187, which failed * because if you use a metaclass from an interface, methods defined on * Object cannot be called. */ private abstract static class DummyResultSet implements GroovyResultSet {} private MetaClass getMetaClass() { if (metaClass == null) { metaClass = GroovySystem.getMetaClassRegistry().getMetaClass(DummyResultSet.class); } return metaClass; } /** * Gets a proxy instance that can be used as GroovyResultSet. * * @return the proxy */ public GroovyResultSet getImpl() { return (GroovyResultSet) Proxy.newProxyInstance( this.getClass().getClassLoader(), new Class[]{GroovyResultSet.class}, this ); } }