All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gu.sql2java.BaseRow Maven / Gradle / Ivy

There is a newer version: 5.3.2
Show newest version
package gu.sql2java;

import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.Map.Entry;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.ObjectSerializer;
import com.alibaba.fastjson.serializer.SerializeConfig;
import com.gitee.l0km.beanfilter.CodecPhase;
import com.gitee.l0km.beanfilter.CodecScope;
import com.gitee.l0km.beanfilter.ICombinedFilter;
import com.gitee.l0km.beanfilter.InterceptorContext;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.base.Throwables;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Maps.EntryTransformer;
import com.google.common.collect.Sets;
import com.google.common.primitives.Ints;
import gu.sql2java.exception.UnsupportTypeException;

import static com.google.common.base.Preconditions.*;
import static gu.sql2java.BaseTypeColumnCodec.BASE_CODEC;
import static gu.sql2java.BaseTypeColumnCodec.isBaseColumnType;
import static gu.sql2java.utils.DeepCloneUtils.cloneFields;
import static gu.sql2java.utils.BaseTypeTransformer.asUnsignedLongChecked;
import static gu.sql2java.utils.BaseTypeTransformer.INTERGRAL_CLASSES;
import static gu.sql2java.utils.ColumnTransformer.COLUMN_TRANSFORMER;

/**
 * abstract implementation of {@link BaseBean}
 * @author guyadong
 *
 */
public abstract class BaseRow implements BaseBean,Comparable, Cloneable {

	protected final RowMetaData metaData;
	private volatile Map mapView;
	protected BaseRow(RowMetaData metaData) {
		this.metaData = checkNotNull(metaData,"metaData is null");
	}
	protected BaseRow() {
		this.metaData = checkNotNull(RowMetaData.getMetaData(getClass()),"metaData is null");
	}
	@Override
	public final boolean isInitialized(String column) {
		return isInitialized(metaData.columnIDOf(column));
	}
	
	@Override
	public boolean beModified() {
		for(int i=0; i 0) {
    		for(int i=0; i < columnIDs.length; ++i){
    			if(isModified(columnIDs[i])){
    				return true;
    			}
    		}
    	}
        return false;
    }
    @Override
    public boolean isModified(String... columns){
    	if(null != columns && columns.length > 0) {
    		for(int i=0; i < columns.length; ++i){
    			if(isModified(columns[i])){
    				return true;
    			}
    		}
    	}
    	return false;
    }

    @Override
    public boolean isModified(String column){        
        return isModified(metaData.columnIDOf(column));
    }
    @Override
    public boolean isModifiedNested(String nestedName){
        if(null == nestedName){
            return false;
        }
        if(isModified(nestedName)){
            return true;
        }
        String prefix = metaData.tablename + ".";
        if(nestedName.startsWith(prefix)){
            /** remove table name */
            nestedName = nestedName.substring(prefix.length());
        }
        int firstDot = nestedName.indexOf('.');
        if(firstDot > 0){
            /** 0-firstDot is column name */
            return isModified(nestedName.substring(0, firstDot));
        } if(firstDot == 0){
            /** column name is empty */
            return false;
        }else {
            /**  only column name */
            return isModified(nestedName);
        }
    }

    @Override
	public int[] modifiedColumnIDs(){
    	List list = Lists.newArrayListWithCapacity(metaData.columnCount);
    	for(int columnID = 0; columnID < metaData.columnCount;++columnID){
    		if(isModified(columnID)){
    			list.add(columnID);	
    		}
    	}
    	return Ints.toArray(list);
    }
    @Override
	public String[] modifiedColumns(){
    	return Iterables.toArray(metaData.columnNamesOf(modifiedColumnIDs()),String.class);
    }
    @Override
	public int modifiedColumnCount(){
    	return modifiedColumnIDs().length;
    }
	@Override
	public void modified(int[] columnIDs) {
        if(null != columnIDs){
            for(int columnID : columnIDs){
                modified(columnID);
            }
        }
	}
	
	@Override
	public void modified(int columnID,int ...columnIDs) {
        modified(columnID);
        modified(columnIDs);
	}
	
	@Override
	public void modified(String column) {
		modified(metaData.columnIDOf(column));
	}
	
	@Override
	public void modified(String[] columns) {
        if(null != columns){
            for(String column : columns){
                modified(metaData.columnIDOf(column));
            }
        }
	}
	
	@Override
	public void modified(String column,String... columns) {
        modified(column);
        modified(columns);
	}

	@Override
	public void resetModified(int[] columnIDs) {
		if(null != columnIDs){
			for(int columnID:columnIDs){
				resetModified(columnID);
			}
		}
	}

    @Override
    public void resetModified(int columnID, int... columnIDs) {
        resetModified(columnID);
        resetModified(columnIDs);
    }
    @Override
    public void resetModified(String column) {
        resetModified(new int[]{metaData.columnIDOf(column)});
    }
    @Override
    public void resetModified(String column, String... columns) {
        resetModified(column);
        resetModified(columns);
    }
    @Override
    public void resetModified(String[] columns) {
       if(null != columns){
            for(String column:columns){
                resetModified(column);
            }
       }
    }
    @Override
	public void resetModifiedIfEqual() {
		if (!isNew()) {
			/** exist record from database */
			BaseBean old = metaData.getManager().loadByPrimaryKeyChecked(primaryValues()).clone();
			for (int columnID = 0; columnID < metaData.columnCount; ++columnID) {
				if (isModified(columnID) && Objects.deepEquals(old.getValue(columnID), getValue(columnID))) {
					resetModified(columnID);
				}
			}
		}
	}
    @Override
    public void resetPrimaryKeysModified()
    {
    	for(int pkIds:metaData.primaryKeyIds) {
    		resetModified(pkIds);
    	}
    }
    @Override
    public void resetModifiedExceptPrimaryKeys()
    {
    	for(int columnID=0; columnID T getValue(String column) {
		return getValue(metaData.columnIDOf(column));
	}

	@Override
	public final  T getValueChecked(int columnID) {
		T value = getValue(columnID);
		return Preconditions.checkNotNull(value,"value of columnid %s IS NULL", columnID);
	}
	@Override
	public final  T getValueChecked(String column) {
		T value = getValue(column);
		return Preconditions.checkNotNull(value,"value of column %s IS NULL", column);
	}
	@Override
	public final void setValue(String column, Object value) {
		setValue(metaData.columnIDOf(column),value);
	}
    @Override
    public final boolean setValueIfNonNull(String column, Object value) 
    {
    	return setValueIf(value != null,column,value);
    }
    
    @Override
    public final boolean setValueIfNonEqual(String column, Object value) 
    {
       return setValueIf(!Objects.equals(value, getValue(column)),column,value);
    }
    @Override
    public final boolean setValueIf(boolean expression,String column, Object value) 
    {
        if(expression){
            setValue(column,value);
        }
        return expression;
    }
    
    @SuppressWarnings("unchecked")
    @Override
    public  T getValue(int columnID)
    {
    	try {
			return (T) metaData.getterMethods.get(columnID).invoke(this);
		} catch (IndexOutOfBoundsException e) {
			return null;
		}catch (Exception e) {
			Throwables.throwIfUnchecked(e);
			throw new RuntimeException(e);
		}
    }
    @SuppressWarnings("unchecked")
	public  T getOriginValue(int columnID)
    {
    	try {
    		Class fieldType = metaData.fieldTypeOf(columnID);
    		Method getter = metaData.getterMethods.get(columnID);
    		if(getter.getReturnType().isAssignableFrom(fieldType)) {
    			return (T)getter.invoke(this);
    		}else {
    			Method reader = metaData.readMethods.get(columnID);
    			checkState(null != reader,"NOT DEFINED read method for %s",metaData.columnNameOf(columnID));
    			return (T) reader.invoke(this);
    		}
    	} catch (IndexOutOfBoundsException e) {
    		return null;
    	}catch (Exception e) {
    		Throwables.throwIfUnchecked(e);
    		throw new RuntimeException(e);
    	}
    }
    @Override
	@SuppressWarnings("unchecked")
	public  T getJdbcValue(int columnID)
    {
    	try {
    		Class jdbcType = metaData.jdbcTypeOf(columnID);
    		Method getter = metaData.getterMethods.get(columnID);
    		if(getter.getReturnType().isAssignableFrom(jdbcType)) {
    			return (T)getter.invoke(this);
    		}    		
    		Method reader = metaData.readMethods.get(columnID);
    		if(null != reader) {
    			if(reader.getReturnType().isAssignableFrom(jdbcType)) {
    				return (T) reader.invoke(this);
    			}
    			if(isBaseColumnType(reader.getReturnType())) {
    				return (T) BASE_CODEC.serialize(reader.invoke(this), jdbcType);
    			}
    		}
    		ColumnCodec codec = metaData.columnCodecOf(columnID);
    		if(null != codec) {
    			return (T) codec.serialize(getOriginValue(columnID), jdbcType);
    		}
    		throw new IllegalStateException(String.format("CAN NOT GET  VALUE OF %d AS %s",columnID,jdbcType));
    	} catch (IndexOutOfBoundsException e) {
    		return null;
    	}catch (Exception e) {
    		Throwables.throwIfUnchecked(e);
    		throw new RuntimeException(e);
    	}
    }
    
    private  void setValue(Method setMethod,T value) throws IllegalArgumentException
	{
		try {
			setMethod.invoke(this, value);
		} catch ( IllegalArgumentException e) {
			if(isBaseColumnType(value)) {
				Class expectType = setMethod.getParameterTypes()[0];
				if(isBaseColumnType(expectType)) {
					try {
						setValue(setMethod,BASE_CODEC.deserialize(value, expectType));
						return;
					} catch (UnsupportTypeException e2) {
						// DO NOTHING
					}
				}
			}
			throw e;
		}catch (Exception e) {
			Throwables.throwIfUnchecked(e);
			throw new RuntimeException(e);
		}
	}
	@Override
    public  void setValue(int columnID,T value)
    {
    	try {
    		setValue(metaData.setterMethods.get(columnID), value);
		} catch (IndexOutOfBoundsException e) {
			return ;
		}catch ( IllegalArgumentException e) {
			Method writeMethod = metaData.writeMethods.get(columnID);
			if(null != writeMethod) {
				setValue(writeMethod, value);
				return;
			}
		    throw e;
        }
    }
    @Override
    public final  boolean setValueIfNonNull(int columnID,T value)
    {
        return setValueIf(value != null,columnID,value);
    }
    @Override
    public final  boolean setValueIfNonEqual(int columnID,T value)
    {
        return setValueIf(!Objects.equals(value, getValue(columnID)),columnID,value);
    }
    @Override
    public final  boolean setValueIf(boolean expression,int columnID,T value)
    {
        if(expression){
            setValue(columnID,value);
        }
        return expression;
    }
    
	@Override
	public final boolean testBitValue(int columnID,Number mask, boolean bitOr) {
    	long m = asUnsignedLongChecked(mask);
    	if(m == 0L) {
    		return false;
    	}
		long v = getBitValueAsLong(columnID, m);
		return bitOr ? (v != 0L) : (v == m);
	}
	@Override
	public final boolean testBitValue(String column,Number mask, boolean bitOr) {
		return testBitValue(metaData.columnIDOf(column), mask, bitOr);
	}
	@SuppressWarnings({ "unchecked" })
	private long getBitValueAsLong(int columnID,Number mask) {
		Object o = getValue(columnID);
    	long m = asUnsignedLongChecked(mask);
		long v = 0L;
		if(null != o	) {
			if(!INTERGRAL_CLASSES.contains(o.getClass())) {
				throw new UnsupportedOperationException(
						"UNSUPPORTED bit operation for column '"+metaData.columnNameOf(columnID)+"'");
			}
			v =  COLUMN_TRANSFORMER.to(o,(Class)o.getClass(),Long.class)&m;
		}
		return v;
	}
	@Override
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public final T getBitValue(int columnID,Number mask) {
		Class type = metaData.columnTypeOf(columnID);
		long v = null == type ? 0L : getBitValueAsLong(columnID,mask);
		return (T) COLUMN_TRANSFORMER.to(v,Long.class, type);
	}
	@Override
	public final T getBitValue(String column,Number mask) {
		return getBitValue(metaData.columnIDOf(column), mask);
	}
	@Override
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public final void setBitValue(int columnID,Number mask,boolean bitSet) {
		Class type = metaData.columnTypeOf(columnID);
		if(null != type) {
			if(!INTERGRAL_CLASSES.contains(type)) {
				throw new UnsupportedOperationException(
						"UNSUPPORTED bit operation for column '"+metaData.columnNameOf(columnID)+"'");
			}
			long m = asUnsignedLongChecked(mask);
			Object o = getValue(columnID);
			long v = null == o ? 0L : COLUMN_TRANSFORMER.to(o,type,Long.class);
			if(bitSet) {
				v |= m;
			}else {
				v &= ~m;
			}
			setValue(columnID,COLUMN_TRANSFORMER.to(v,Long.class, type));
		}
	}
	@Override
	public final void setBitValue(String column,Number mask,boolean bitSet) {
		setBitValue(metaData.columnIDOf(column),mask,bitSet);
	}
    @Override
	public final boolean setBitValueIfNonNull(String column, Number mask,boolean bitSet) 
    {
    	return setBitValueIf(mask != null && null != getValue(column),column,mask,bitSet);
    }
    @Override
	public final boolean setBitValueIf(boolean expression,String column, Number mask,boolean bitSet) 
    {
        if(expression){
        	setBitValue(column,mask,bitSet);
        }
        return expression;
    }
	@Override
    public Object[] primaryValues()
    {
        Object[] values = new Object[metaData.primaryKeyCount];
        for(int i = 0; i < values.length; ++i) {
            values[i] = getValue(metaData.primaryKeyIds[i]);
        }
        return values;
    }

    @Override
    public  T primaryValue()
    {
        if(metaData.primaryKeyCount != 1) {
            throw new UnsupportedOperationException();
        }
        return getValue(metaData.primaryKeyIds[0]);
    }
    
    @Override
    public Object[] asValueArray(int...columnIds)
    {
		if(null == columnIds || columnIds.length == 0){
			columnIds = metaData.defaultColumnIdList;
		}
        Object[] v = new Object[columnIds.length];
        for(int i=0; i< v.length; ++i){
        	v[i] = getValue(columnIds[i]);
        }
        return v;
    }
	@Override
	public Map asNameValueMap(){
		// double check 
		if(mapView == null){
			synchronized (this) {
				if(mapView == null){
					mapView = new RowMapView(this);
				}
			}
		}
		return mapView;
	}
	@Override
	public Map asNameValueMap(boolean ignoreNull,String ...ignoreColumns){
		return asNameValueMap(ignoreNull,false,false,null != ignoreColumns ? Arrays.asList(ignoreColumns) : Collections.emptySet());
	}
	@Override
	public Map asNameValueMap(boolean ignoreNull,IterableignoreColumns){
		return asNameValueMap(ignoreNull,false,false,ignoreColumns);
	}
	@Override
	public Map asNameValueMap(boolean ignoreNull,boolean include,String ...includeColumns){
		return asNameValueMap(ignoreNull,false, include,null != includeColumns ? Arrays.asList(includeColumns) : Collections.emptySet());
	}
	@Override
	public Map asNameValueMap(boolean ignoreNull,final boolean include,Iterablecolumns){
		return asNameValueMap(ignoreNull, false, include, columns);
	}
	@Override
	public Map asNameValueMap(boolean ignoreNull,boolean serialize,boolean include,String ...includeColumns){
		return asNameValueMap(ignoreNull, serialize,include,null != includeColumns ? Arrays.asList(includeColumns) : Collections.emptySet());
	}
	@Override
	public Map asNameValueMap(boolean ignoreNull,final boolean serialize,final boolean include,Iterablecolumns){
		Map map = asFilterableNameValueMap();
		if(ignoreNull){
			map = Maps.filterValues(map, Predicates.notNull());
		}
		if(serialize) {
			
			map = Maps.transformEntries(map, new EntryTransformer() {
				
				@Override
				public Object transformEntry(String key, Object value) {
					ObjectSerializer serializer = metaData.jsonSerializerOf(metaData.columnIDOf(key));
					if(null != serializer) {
						SerializeConfig serializeConfig = new SerializeConfig();
						serializeConfig.put(metaData.fieldTypeOf(metaData.columnIDOf(key)), serializer);
						return JSON.parse( JSON.toJSONString(value, serializeConfig));
					}
					return value;
				}
			});
		}
		if(null != columns){
			final Set names = Sets.filter(Sets.newHashSet(columns),Predicates.notNull());
			map = Maps.filterKeys(map, new Predicate() {
				@Override
				public boolean apply(String input) {
					return include ? names.contains(input) : !names.contains(input);
				}
			});
		}
		return Maps.newLinkedHashMap(map);
	}
	
	@Override
	public Map asFilterableNameValueMap(){
		Map map = Maps.newHashMap();
		Set includeNames = metaData.columnNamesWith(ColumnVisibility.JSON);
		ICombinedFilter combinedFilter = InterceptorContext.getCurrentFilterContainer()
				.getFilter(CodecPhase.SERIALIZATION, CodecScope.FASTJSON);
		for(Entry entry:asNameValueMap().entrySet()) {
			String columnName = entry.getKey();
			Object value = entry.getValue();
			if(includeNames.contains(columnName)) {
				if(combinedFilter.isEmpty()) {
					 map.put(columnName, value);
				}else if (combinedFilter.getFieldFilterOrDefault().permit(metaData.beanType, columnName)) {
					value = combinedFilter.getValueFilterOrDefault().process(metaData.beanType, columnName, value);
					map.put(columnName, value);
				}
			}
		}
		return map;
	}
	@Override
    public  B copy(B bean)
    {
        return copy(bean,new int[0]);
    }

    @SuppressWarnings("unchecked")
    @Override
    public  B copy(B bean, int... fieldList)
    {   
    	if(bean != null && bean != this){
    		for (int columnId:metaData.validColumnIDsOrAll(fieldList)) {
    		    // valid column id only 
    		    if( bean.isInitialized(columnId) && !Objects.deepEquals(bean.getValue(columnId), getValue(columnId))){
    		        setValue(columnId, bean.getValue(columnId));
    		    }
    		}
    	}
        return (B)this;
    }

    @Override
    public  B copy(B bean, String... fieldList)
    {
        return copy(bean, null, fieldList);
    }
    @SuppressWarnings("unchecked")
    @Override
	public  B copy(B bean, Predicate fieldFilter,int... fieldList)
    {
        int[] columnIds = filterColumnIDs(fieldFilter,fieldList);
        if (null == columnIds || 0 == columnIds.length){
            return (B) this; 
        }
        return copy(bean, columnIds);
    }
    @SuppressWarnings("unchecked")
    @Override
    public  B copy(B bean, Predicate fieldFilter,String... fieldList)
    {
        int[] columnIds = filterColumnIDs(fieldFilter,fieldList);
        if (null == columnIds || 0 == columnIds.length){
            return (B) this; 
        }
        return copy(bean, columnIds);
    }
    @Override
	@SuppressWarnings("unchecked")
	public  B copyIfNonEqual() {
		if (!isNew()) {
			/** exist record from database */
			BaseBean old = metaData.getManager().loadByPrimaryKeyChecked(primaryValues()).clone();
			for (int columnID = 0; columnID < metaData.columnCount; ++columnID) {
				if (isModified(columnID)) {
					if(!Objects.deepEquals(old.getValue(columnID), getValue(columnID))) {
						old.setValue(columnID, getValue(columnID));
					}
				}
			}
			return (B) old;
		}
		return (B) this;
	}

	@SuppressWarnings("unchecked")
	@Override
	public  B copy(F from,Map columnsMap){
        for(Map.Entry entry : checkNotNull(columnsMap,"columnsMap is null").entrySet()){
        	setValue(entry.getValue(), null == from ? null : from.getValue(entry.getKey()));
        }
    	return (B) this;
    }
    
    @SuppressWarnings("rawtypes")
	@Override
	public  B copy(Map values){
    	return copy(values,null,true);
    }
    @SuppressWarnings({ "unchecked", "rawtypes" })
    @Override
    public  B copy(Map values,Function keyTransformer, boolean ignoreUnmap){
    	if(null != values){
			Set includeNames = metaData.columnNamesWith(ColumnVisibility.JSON);
			ICombinedFilter combinedFilter = InterceptorContext.getCurrentFilterContainer()
					.getFilter(CodecPhase.DESERIALIZATION, CodecScope.FASTJSON);
    		for(Object o : values.entrySet()){
    			/** column id or name */
    			Object column = ((Entry) o).getKey();
    			/** value for column  */
    			Object value = ((Entry) o).getValue();
    			if(null != keyTransformer) {
    				Object transformed = keyTransformer.apply(column);
    				if(null != transformed) {
    					/** use transformed object as column index or id */
    					column = transformed;
    				}else if(ignoreUnmap) {
    					/** ignore the key  */
    					continue;
    				}
    			}
				String columnName;
				int columnID = -1;
				if (column instanceof Number) {
					columnID = ((Number) column).intValue();
					columnName = metaData.columnNameOf(columnID);
				} else if (column instanceof String) {
					columnName = (String) column;
				} else {
					/** ignore the key */
					continue;
				}
				if (includeNames.contains(columnName)) {
					if (combinedFilter.isEmpty()) {
						if (columnID >= 0) {
							setValue(columnID, value);
						} else {
							setValue(columnName, value);
						}
					} else if (combinedFilter.getFieldFilterOrDefault().permit(metaData.beanType, columnName)) {
						value = combinedFilter.getValueFilterOrDefault().process(metaData.beanType, columnName, value);
						if (columnID >= 0) {
							setValue(columnID, value);
						} else {
							setValue(columnName, value);
						}
					}
				}
    		}
    	}
    	return (B) this;
    }
    @Override
    @SuppressWarnings("unchecked")
    public  B copyJson(Mapvalues){
    	if(null != values){
    		for(Entry entry : values.entrySet()){
    			setValue(entry.getKey(), entry.getValue());
    		}
    	}
    	return (B) this;
    }
    
    @Override
    public boolean equalColumn(Object object,int columnId)
    {   
        if(!metaData.beanType.isInstance(object)){
            return false;
        }        
        BaseBean bean = (BaseBean)object; 
        if(null != bean){
            if(bean != this){
                if(metaData.isValidColumnID(columnId)){
                    // valid column id only 
                    if( bean.isInitialized(columnId) && !Objects.deepEquals(bean.getValue(columnId), getValue(columnId))){
                        return false;
                    }
                }
            }
            return true;
        }
        return false;
    }
    @Override
    public boolean equalColumn(Object object, int... fieldList)
    {   
        if(metaData.beanType.isInstance(object)){
            BaseBean bean = (BaseBean)object;
            if(bean != this && null != fieldList){
                for (int columnId:fieldList) {
                    // valid column id only 
                    if(metaData.isValidColumnID(columnId)){
                        if( bean.isInitialized(columnId) && !Objects.deepEquals(bean.getValue(columnId), getValue(columnId))){
                            return false;
                        }
                    }
                }
            }
            return true;
        }
        return false;
    }
    @Override
    public boolean equalColumn(Object object, Predicate fieldFilter,int... fieldList)
    {
        return equalColumn(object, filterColumnIDs(fieldFilter,fieldList));
    }
    @Override
    public boolean equalColumn(Object object, Predicate fieldFilter,String... fieldList)
    {
        return equalColumn(object, filterColumnIDs(fieldFilter,fieldList));
    }
    private int[] filterColumnIDs(Predicate fieldFilter,int... fieldList){
        if(null != fieldList){
            if(null != fieldFilter){
                Iterable columnIDs = Iterables.filter(Ints.asList(fieldList),fieldFilter);
                return Ints.toArray(Lists.newArrayList(columnIDs));
            }else {
                return fieldList;
            }
        }
        return null;
    }
    private int[] filterColumnIDs(Predicate fieldFilter,String... fieldList)
    {
        if(null != fieldList){
            Iterable filtered = Iterables.filter(Arrays.asList(fieldList),Predicates.notNull());
            if(null != fieldFilter){
                filtered = Iterables.filter(filtered,fieldFilter);
            }
            Iterable columnIDs = Iterables.transform(filtered, metaData.COLUMNID_FUN);
            return Ints.toArray(Lists.newArrayList(columnIDs));
        }
        return null;
    }

    @Override
	public final String tableName() {
		return metaData.tablename;
	}
    private static final StringBuilder append(StringBuilder buffer,boolean full,byte[] value){
        if(full || null == value){
            buffer.append(ArraySupport.toHex(value));
        }else{
            buffer.append(value.length).append(" bytes");
        }
        return buffer;
    }
    private static int stringLimit = 64;
    private static final int MINIMUM_LIMIT = 16;
    private static final StringBuilder append(StringBuilder buffer,boolean full,String value){
        if(full || null == value || value.length() <= stringLimit){
            buffer.append(value);
        }else{
            buffer.append(value.substring(0,stringLimit - 8)).append(" ...").append(value.substring(stringLimit-4,stringLimit));
        }
        return buffer;
    }
    private static final StringBuilder append(StringBuilder buffer,boolean full,Object value){
    	if(value instanceof String){
    		return append(buffer, full, (String)value);
    	}
    	if(value instanceof byte[]){
    		return append(buffer, full, (byte[])value);
    	}
        return buffer.append(value);
    }
    public static final void setStringLimit(int limit){
        checkArgument(limit >= MINIMUM_LIMIT, "INVALID limit %s,minimum value %s",limit,MINIMUM_LIMIT);
        stringLimit = limit;
    }
	@Override
	public String toString(boolean notNull, boolean fullIfStringOrBytes) {
        StringBuilder builder = new StringBuilder(this.getClass().getName()).append("@").append(Integer.toHexString(this.hashCode())).append("[");
        int count = 0;
        for(int i = 0; i < metaData.columnCount; ++i){
        	Object value = getValue(i);
        	if( !notNull || null != value){
            	if(count > 0){
            		builder.append(",");
            	}
        		builder.append(metaData.columnNameOf(i)).append("=");
        		append(builder,fullIfStringOrBytes,value);
        		++count;
        	}
        }
        builder.append("]");        
		return builder.toString();
	}
	@Override
	public boolean equals(Object object) {
		if(!metaData.beanType.isInstance(object)){
			return false;
		}
		BaseBean bean = (BaseBean)object;
		EqualsBuilder equalsBuilder = new EqualsBuilder();
		for(int i=0; i 0 ? metaData.primaryKeyIds : metaData.defaultColumnIdList;
		for(int i=0; i limit){
	                        setValue(columnID, new String(bytes, 0, limit));
	                    }
	                }
	            }else if(value instanceof byte[]) {
	                byte[] bytes = (byte[])value;
	                if(bytes.length > limit){
	                    setValue(columnID, Arrays.copyOf(bytes,limit));
	                }
	            }else if(value instanceof ByteBuffer) {
	                byte[] bytes = Sql2javaSupport.getBytesInBuffer((ByteBuffer) value);
	                if(bytes.length > limit){
                        setValue(columnID, ByteBuffer.wrap(Arrays.copyOf(bytes,limit)));
                    }
	            }
	        }
	    }
	}
	/**
     * truncate String,binary field 
     * @param column column name or field name
     * @since 3.17.7
     */
	public void truncate(String column) {
	    truncate(metaData.columnIDOf(column));
	}
}