/* * Copyright 2011-2013 the original author or authors. * * Licensed 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 kr.debop4j.core.reflect; import com.google.common.collect.Lists; import kr.debop4j.core.Guard; import kr.debop4j.core.tools.StringTool; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import java.util.List; /** * 동적으로 객체의 속성, 메소드에 접근할 수 있는 접근자입니다. * * @author 배성혁 ( sunghyouk.bae@gmail.com ) * @since 13. 1. 21 */ @Slf4j public class DynamicAccessor<T> { @Getter private final Class<T> targetType; private final ConstructorAccess<T> ctorAccessor; private final FieldAccess fieldAccessor; private final MethodAccess methodAccessor; private final List<String> fieldNames; private final List<String> methodNames; /** * Instantiates a new Dynamic accessor. * * @param targetType the target type */ public DynamicAccessor(Class<T> targetType) { Guard.shouldNotBeNull(targetType, "targetType"); if (log.isDebugEnabled()) log.debug("수형 [{}]에 대한 DynamicAccessor 를 생성합니다...", targetType); this.targetType = targetType; this.ctorAccessor = ConstructorAccess.get(this.targetType); this.fieldAccessor = FieldAccess.get(this.targetType); this.methodAccessor = MethodAccess.get(this.targetType); this.fieldNames = Lists.newArrayList(fieldAccessor.getFieldNames()); this.methodNames = Lists.newArrayList(methodAccessor.getMethodNames()); if (log.isDebugEnabled()) log.debug("수형 [{}]애 대한 DynamicAccessor를 생성했습니다.", targetType); } /** * New instance. * * @return the t */ @SuppressWarnings("unchecked") public <T> T newInstance() { return (T) ctorAccessor.newInstance(); } /** * New instance. * * @param enclosingInstance the enclosing instance * @return the t */ @SuppressWarnings("unchecked") public <T> T newInstance(Object enclosingInstance) { return (T) ctorAccessor.newInstance(enclosingInstance); } /** * Gets field names. * * @return the field names */ public List<String> getFieldNames() { return fieldNames; } /** * Gets method names. * * @return the method names */ public List<String> getMethodNames() { return methodNames; } /** * Gets field. * * @param instance the instance * @param fieldName the field name * @return the field */ public Object getField(Object instance, String fieldName) { return fieldAccessor.get(instance, fieldName); } /** * Sets field. * * @param instance the instance * @param fieldName the field name * @param nv the nv */ public void setField(Object instance, String fieldName, Object nv) { fieldAccessor.set(instance, fieldName, nv); } /** * Sets field boolean. * * @param instance the instance * @param fieldName the field name * @param nv the nv */ public void setFieldBoolean(Object instance, String fieldName, boolean nv) { fieldAccessor.setBoolean(instance, fieldAccessor.getIndex(fieldName), nv); } /** * Sets field byte. * * @param instance the instance * @param fieldName the field name * @param nv the nv */ public void setFieldByte(Object instance, String fieldName, byte nv) { fieldAccessor.setByte(instance, fieldAccessor.getIndex(fieldName), nv); } /** * Sets field char. * * @param instance the instance * @param fieldName the field name * @param nv the nv */ public void setFieldChar(Object instance, String fieldName, char nv) { fieldAccessor.setChar(instance, fieldAccessor.getIndex(fieldName), nv); } /** * Sets field double. * * @param instance the instance * @param fieldName the field name * @param nv the nv */ public void setFieldDouble(Object instance, String fieldName, double nv) { fieldAccessor.setDouble(instance, fieldAccessor.getIndex(fieldName), nv); } /** * Sets field float. * * @param instance the instance * @param fieldName the field name * @param nv the nv */ public void setFieldFloat(Object instance, String fieldName, float nv) { fieldAccessor.setFloat(instance, fieldAccessor.getIndex(fieldName), nv); } /** * Sets field int. * * @param instance the instance * @param fieldName the field name * @param nv the nv */ public void setFieldInt(Object instance, String fieldName, int nv) { fieldAccessor.setInt(instance, fieldAccessor.getIndex(fieldName), nv); } /** * Sets field long. * * @param instance the instance * @param fieldName the field name * @param nv the nv */ public void setFieldLong(Object instance, String fieldName, long nv) { fieldAccessor.setLong(instance, fieldAccessor.getIndex(fieldName), nv); } /** * Sets field short. * * @param instance the instance * @param fieldName the field name * @param nv the nv */ public void setFieldShort(Object instance, String fieldName, short nv) { fieldAccessor.setShort(instance, fieldAccessor.getIndex(fieldName), nv); } /** * Gets property. * * @param instance the instance * @param fieldName the field name * @return the property */ public Object getProperty(Object instance, String fieldName) { String methodName = (methodNames.contains(fieldName)) ? fieldName : "get" + getPropertyName(fieldName); return invoke(instance, methodName); } /** * Sets property. * * @param instance the instance * @param fieldName the field name * @param nv the nv */ public void setProperty(Object instance, String fieldName, Object nv) { String methodName = (methodNames.contains(fieldName)) ? fieldName : "set" + getPropertyName(fieldName); invoke(instance, methodName, nv); } /** * Invoke object. * * @param instance the instance * @param methodName the method name * @param args the args * @return the object */ public Object invoke(Object instance, String methodName, Object... args) { return methodAccessor.invoke(instance, methodName, args); } /** * Try get field. * * @param instance the instance * @param fieldName the field name * @param defaultValue the default value * @return the t */ @SuppressWarnings("unchecked") public <T> T tryGetField(Object instance, String fieldName, T defaultValue) { log.trace("필드값을 추출합니다. instance=[{}], propertyName=[{}], defaultValue=[{}]", instance, fieldName, defaultValue); try { return (T) getField(instance, fieldName); } catch (Exception ignored) { log.warn("필드값 조회에 실패했습니다. 기본값을 반환합니다. filedNamee=[{}], defaultValue=[{}]", fieldName, defaultValue); return defaultValue; } } /** * Try get property. * * @param instance the instance * @param propertyName the property name * @param defaultValue the default value * @return the t */ @SuppressWarnings("unchecked") public <T> T tryGetProperty(Object instance, String propertyName, T defaultValue) { log.trace("속성값을 추출합니다. instance=[{}], propertyName=[{}], defaultValue=[{}]", instance, propertyName, defaultValue); try { return (T) getProperty(instance, propertyName); } catch (Exception ignored) { log.warn("속성값 조회에 실패했습니다. 기본값을 반환합니다. propertyName=[{}], defaultValue=[{}]", propertyName, defaultValue); return defaultValue; } } /** * Try invoke. * * @param instance the instance * @param methodName the method name * @param defaultValue the default value * @param args the args * @return the t */ @SuppressWarnings("unchecked") public T tryInvoke(Object instance, String methodName, T defaultValue, Object... args) { log.trace("메소드를 호출합니다. instance=[{}], methodName=[{}], defaultValue=[{}], args=[{}]", instance, methodName, defaultValue, StringTool.listToString(args)); try { return (T) invoke(instance, methodName, args); } catch (Exception ignored) { log.warn("메소드 실행에 실패했습니다. 기본값을 반환합니다. methodName=[{}], defaultValue=[{}], args=[{}]", methodName, defaultValue, StringTool.listToString(args)); return defaultValue; } } private static String getPropertyName(String fieldName) { if (StringTool.isEmpty(fieldName)) return ""; return fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); } }