<commit_before>/*
 * 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 com.nway.spring.jdbc.bean;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.springframework.beans.BeanUtils;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.util.ClassUtils;

import com.nway.spring.classwork.DynamicBeanClassLoader;
import com.nway.spring.classwork.DynamicObjectException;
import com.nway.spring.jdbc.annotation.Column;

/**
 * <p>
 * <code>BeanProcessor</code> matches column names to bean property names and converts
 * <code>ResultSet</code> columns into objects for those bean properties. Subclasses should override
 * the methods in the processing chain to customize behavior.
 * </p>
 *
 * <p>
 * This class is thread-safe.
 * </p>
 *
 * apache-dbutilsԶ̬bean,޸˴󲿷ַʵ
 * <p>
 *
 * @since DbUtils 1.1
 */
class AsmBeanProcessor implements BeanProcessor {

	private static final Map<String, DbBeanFactory> DBBEANFACTORY_CACHE = new HashMap<String, DbBeanFactory>(10000);

    /**
     * Special array value used by <code>mapColumnsToProperties</code> that indicates there is no
     * bean property that matches a column from a <code>ResultSet</code>.
     */
    private static final int PROPERTY_NOT_FOUND = -1;
    
    private static final int PROPERTY_TYPE_OTHER = 0;
    private static final int PROPERTY_TYPE_BOOLEAN = 1;
    private static final int PROPERTY_TYPE_BYTE = 2;
    private static final int PROPERTY_TYPE_SHORT = 3;
    private static final int PROPERTY_TYPE_INTEGER = 4;
    private static final int PROPERTY_TYPE_LONG = 5;
    private static final int PROPERTY_TYPE_FLOAT = 6;
    private static final int PROPERTY_TYPE_DOUBLE = 7;
    private static final int PROPERTY_TYPE_DATE = 8;
    
    /**
     * Convert a <code>ResultSet</code> into a <code>List</code> of JavaBeans. This implementation
     * uses reflection and <code>BeanInfo</code> classes to match column names to bean property
     * names. Properties are matched to columns based on several factors: <br/>
     * <ol>
     * <li>
     * The class has a writable property with the same name as a column. The name comparison is case
     * insensitive.</li>
     *
     * <li>
     * The column type can be converted to the property's set method parameter type with a
     * ResultSet.get* method. If the conversion fails (ie. the property was an int and the column
     * was a Timestamp) an SQLException is thrown.</li>
     * </ol>
     *
     * <p>
     * Primitive bean properties are set to their defaults when SQL NULL is returned from the
     * <code>ResultSet</code>. Numeric fields are set to 0 and booleans are set to false. Object
     * bean properties are set to <code>null</code> when SQL NULL is returned. This is the same
     * behavior as the <code>ResultSet</code> get* methods.
     * </p>
     *
     * @param <T> The type of bean to create
     * @param rs ResultSet that supplies the bean data
     * @param type Class from which to create the bean instance
     * @throws SQLException if a database access error occurs
     * @return the newly created List of beans
     */
    public <T> List<T> toBeanList(ResultSet rs, Class<T> type, String cacheKey) throws SQLException {

        if (!rs.next()) {
        	
            return Collections.emptyList();
        }
        
        final List<T> results = new ArrayList<T>();

        //String cacheKey = //DynamicClassUtils.makeCacheKey(rs, type.getName());
		
        do {
        	
            results.add(toBean(rs, type, cacheKey));
        }
        while (rs.next());

        return results;
    }
    
    /**
     * ɶ̬beanݺbeanϲ
     * <p>
     *
     * <b>ĬʹASMɶ̬beanҪjavassistʽɶ̬bean뽫ʵлΪ{@link
     * this#createBeanByJavassist(ResultSet, Class, String)}</b>
     *
     * @param <T>
     * @param rs {@link ResultSet}
     * @param type bean
     * @param querying sqlѯϢ
     * @return ݵbean
     *
     * @throws SQLException
     */
    public <T> T toBean(ResultSet rs, Class<T> type) throws SQLException {
    	
    	return toBean(rs, type, null);
    }

	public <T> T toBean(ResultSet rs, Class<T> type, String cacheKey) throws SQLException {


		if (cacheKey == null) {

			cacheKey = DynamicClassUtils.makeCacheKey(rs, type.getName());
		} 

		/*
		 * ͬߵӦЧʣήϵͳ
		 * ֻ߳ͬеĳһѯһʼʹʱŻǰβѯظ嶯̬ͬDbBeanFactory
		 * typeΪͬ߳ͬϵͳӰ
		 */
//		synchronized (type) {

			return createBeanByASM(rs, type, cacheKey);
//		}

	}

    /**
     * Creates a new object and initializes its fields from the ResultSet.
     *
     * @param <T> The type of bean to create
     * @param rs The result set.
     * @param type The bean type (the return type of the object).
     * @param props The property descriptors.
     * @param columnToProperty The column indices in the result set.
     * @return An initialized object.
     * @throws SQLException if a database error occurs.
     */
    private <T> T createBeanByASM(ResultSet rs, Class<T> mappedClass, String key) throws SQLException {

        DbBeanFactory dynamicRse = DBBEANFACTORY_CACHE.get(key);
        
        // ֱӷ
        if (dynamicRse != null) {

            return dynamicRse.createBean(rs, mappedClass);
        }

        T bean = this.newInstance(mappedClass);

        ResultSetMetaData rsmd = rs.getMetaData();

        MethodVisitor mv = null;

        final ClassWriter cw = new ClassWriter(0);

        PropertyDescriptor[] props = BeanUtils.getPropertyDescriptors(mappedClass);

        int[] columnToProperty = this.mapColumnsToProperties(rsmd, props);

        String beanName = mappedClass.getName().replace('.', '/');
        
        String processorName = DynamicClassUtils.getBeanProcessorName(mappedClass);
        
        String internalProcessorName = processorName.replace('.', '/');

        Object[] labelArr = prepScript(cw, mv, internalProcessorName, beanName);

        mv = (MethodVisitor) labelArr[1];

        Label firstLabel = null;
        PropertyDescriptor desc = null;

        for (int i = 1; i < columnToProperty.length; i++) {

            if (columnToProperty[i] == PROPERTY_NOT_FOUND) {<commit_msg>为了性能做了一点点改动<commit_after>/*
 * 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 com.nway.spring.jdbc.bean;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.springframework.beans.BeanUtils;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.util.ClassUtils;

import com.nway.spring.classwork.DynamicBeanClassLoader;
import com.nway.spring.classwork.DynamicObjectException;
import com.nway.spring.jdbc.annotation.Column;

/**
 * <p>
 * <code>BeanProcessor</code> matches column names to bean property names and converts
 * <code>ResultSet</code> columns into objects for those bean properties. Subclasses should override
 * the methods in the processing chain to customize behavior.
 * </p>
 *
 * <p>
 * This class is thread-safe.
 * </p>
 *
 * apache-dbutilsԶ̬bean,޸˴󲿷ַʵ
 * <p>
 *
 * @since DbUtils 1.1
 */
class AsmBeanProcessor implements BeanProcessor {

	private static final Map<String, DbBeanFactory> DBBEANFACTORY_CACHE = new HashMap<String, DbBeanFactory>(10000);

    /**
     * Special array value used by <code>mapColumnsToProperties</code> that indicates there is no
     * bean property that matches a column from a <code>ResultSet</code>.
     */
    private static final int PROPERTY_NOT_FOUND = -1;
    
    private static final int PROPERTY_TYPE_OTHER = 0;
    private static final int PROPERTY_TYPE_BOOLEAN = 1;
    private static final int PROPERTY_TYPE_BYTE = 2;
    private static final int PROPERTY_TYPE_SHORT = 3;
    private static final int PROPERTY_TYPE_INTEGER = 4;
    private static final int PROPERTY_TYPE_LONG = 5;
    private static final int PROPERTY_TYPE_FLOAT = 6;
    private static final int PROPERTY_TYPE_DOUBLE = 7;
    private static final int PROPERTY_TYPE_DATE = 8;
    
    /**
     * Convert a <code>ResultSet</code> into a <code>List</code> of JavaBeans. This implementation
     * uses reflection and <code>BeanInfo</code> classes to match column names to bean property
     * names. Properties are matched to columns based on several factors: <br/>
     * <ol>
     * <li>
     * The class has a writable property with the same name as a column. The name comparison is case
     * insensitive.</li>
     *
     * <li>
     * The column type can be converted to the property's set method parameter type with a
     * ResultSet.get* method. If the conversion fails (ie. the property was an int and the column
     * was a Timestamp) an SQLException is thrown.</li>
     * </ol>
     *
     * <p>
     * Primitive bean properties are set to their defaults when SQL NULL is returned from the
     * <code>ResultSet</code>. Numeric fields are set to 0 and booleans are set to false. Object
     * bean properties are set to <code>null</code> when SQL NULL is returned. This is the same
     * behavior as the <code>ResultSet</code> get* methods.
     * </p>
     *
     * @param <T> The type of bean to create
     * @param rs ResultSet that supplies the bean data
     * @param type Class from which to create the bean instance
     * @throws SQLException if a database access error occurs
     * @return the newly created List of beans
     */
    public <T> List<T> toBeanList(ResultSet rs, Class<T> type, String cacheKey) throws SQLException {

        if (!rs.next()) {
        	
            return Collections.emptyList();
        }
        
        final List<T> results = new ArrayList<T>();
        
        DbBeanFactory dynamicRse = DBBEANFACTORY_CACHE.get(cacheKey);
        
		// ֱӷ
		if (dynamicRse != null) {

			do {

				results.add(dynamicRse.createBean(rs, type));
			} 
			while (rs.next());

		} 
		else {

			results.add(toBean(rs, type, cacheKey));
		}

        return results;
    }
    
    /**
     * ɶ̬beanݺbeanϲ
     * <p>
     *
     * <b>ĬʹASMɶ̬beanҪjavassistʽɶ̬bean뽫ʵлΪ{@link
     * this#createBeanByJavassist(ResultSet, Class, String)}</b>
     *
     * @param <T>
     * @param rs {@link ResultSet}
     * @param type bean
     * @param querying sqlѯϢ
     * @return ݵbean
     *
     * @throws SQLException
     */
	public <T> T toBean(ResultSet rs, Class<T> type, String cacheKey) throws SQLException {

		DbBeanFactory dynamicRse = DBBEANFACTORY_CACHE.get(cacheKey);
        
        // ֱӷ
        if (dynamicRse != null) {

            return dynamicRse.createBean(rs, type);
        }

		/*
		 * ͬߵӦЧʣήϵͳ
		 * ֻ߳ͬеĳһѯһʼʹʱŻǰβѯظ嶯̬ͬDbBeanFactory
		 * typeΪͬ߳ͬϵͳӰ
		 */
//		synchronized (type) {

			return createBeanByASM(rs, type, cacheKey);
//		}

	}

    /**
     * Creates a new object and initializes its fields from the ResultSet.
     *
     * @param <T> The type of bean to create
     * @param rs The result set.
     * @param type The bean type (the return type of the object).
     * @param props The property descriptors.
     * @param columnToProperty The column indices in the result set.
     * @return An initialized object.
     * @throws SQLException if a database error occurs.
     */
    private <T> T createBeanByASM(ResultSet rs, Class<T> mappedClass, String key) throws SQLException {

        T bean = this.newInstance(mappedClass);

        ResultSetMetaData rsmd = rs.getMetaData();

        MethodVisitor mv = null;

        final ClassWriter cw = new ClassWriter(0);

        PropertyDescriptor[] props = BeanUtils.getPropertyDescriptors(mappedClass);

        int[] columnToProperty = this.mapColumnsToProperties(rsmd, props);

        String beanName = mappedClass.getName().replace('.', '/');
        
        String processorName = DynamicClassUtils.getBeanProcessorName(mappedClass);
        
        String internalProcessorName = processorName.replace('.', '/');

        Object[] labelArr = prepScript(cw, mv, internalProcessorName, beanName);

        mv = (MethodVisitor) labelArr[1];

        Label firstLabel = null;
        PropertyDescriptor desc = null;

        for (int i = 1; i < columnToProperty.length; i++) {

            if (columnToProperty[i] == PROPERTY_NOT_FOUND) {
{'fraction_non_alphanumeric': 0.09415160470070785, 'fraction_numerical': 0.0034361899525805787, 'mean_word_length': 3.0377358490566038, 'pattern_counts': {'":': 0, '<': 109, '<?xml version=': 0, '>': 107, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1216842', 'n_tokens_mistral': 4469, 'n_tokens_neox': 4324, 'n_words': 1419}