001/* 
002 * JKNIV, utils - Helper utilities for jdk code.
003 * 
004 * Copyright (C) 2017, the original author or authors.
005 *
006 * This library is free software; you can redistribute it and/or
007 * modify it under the terms of the GNU Lesser General Public
008 * License as published by the Free Software Foundation; either
009 * version 2.1 of the License.
010 * 
011 * This library is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014 * Lesser General Public License for more details.
015 * 
016 * You should have received a copy of the GNU Lesser General Public
017 * License along with this library; if not, write to the Free Software Foundation, Inc., 
018 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
019 */
020package net.sf.jkniv.reflect.beans;
021
022import java.lang.reflect.Field;
023import java.lang.reflect.Method;
024import java.util.Map;
025
026import net.sf.jkniv.exception.HandleableException;
027import net.sf.jkniv.exception.HandlerException;
028import net.sf.jkniv.reflect.ReflectionException;
029
030/**
031 * 
032 * @author Alisson Gomes
033 * @since 0.6.0
034 */
035public class PropertyAccess
036{
037    private static final Capitalize CAPITAL_SETTER = CapitalNameFactory.getInstanceOfSetter();
038    private static final Capitalize CAPITAL_GETTER = CapitalNameFactory.getInstanceOfGetter();
039    
040    private String                  fieldName;
041    private String                  writerMethodName;
042    private String                  readMethodName;
043    private Class<?>                targetClass;
044    private boolean                 nestedField;
045    private Field                   field;
046    private Method                  writerMethod;
047    private Method                  readMethod;
048    
049    public PropertyAccess(String fieldName)
050    {
051        this(fieldName, null);
052    }
053
054    public PropertyAccess(String fieldName, String readMethodName, String writerMethodName)
055    {
056        this.fieldName = fieldName;
057        this.readMethodName = readMethodName;
058        this.writerMethodName = writerMethodName;
059    }
060    
061    public PropertyAccess(String fieldName, Class<?> targetClass)
062    {
063        this.fieldName = fieldName;
064        int index = fieldName.lastIndexOf(".");
065        if (index > 0)
066        {
067            this.nestedField = true;
068            this.writerMethodName = CAPITAL_SETTER.does(fieldName.substring(index+1));
069            this.readMethodName = CAPITAL_GETTER.does(fieldName.substring(index+1));
070        }
071        else
072        {
073            this.writerMethodName = CAPITAL_SETTER.does(fieldName);
074            this.readMethodName = CAPITAL_GETTER.does(fieldName);
075        }
076        resolve(targetClass);
077    }
078    
079    public String getFieldName()
080    {
081        return this.fieldName;
082    }
083    
084    public Field getField()
085    {
086        return this.field;
087    }
088    
089    public Method getWriterMethod()
090    {
091        return this.writerMethod;
092    }
093    
094    public Method getReadMethod()
095    {
096        return this.readMethod;
097    }
098    
099    public String getWriterMethodName()
100    {
101        return writerMethodName;
102    }
103    
104    public String getReadMethodName()
105    {
106        return readMethodName;
107    }
108    
109    public Class<?> getTargetClass()
110    {
111        return this.targetClass;
112    }
113    
114    private void setTargetClass(Class<?> targetClass)
115    {
116        if (this.targetClass != null)
117            throw new ReflectionException("Cannot re-define a new target class for PropertyAccess");
118        
119        this.targetClass = targetClass;
120    }
121    
122    public boolean isNestedField()
123    {
124        return nestedField;
125    }
126    
127    public boolean hasField()
128    {
129        return (this.field != null);
130    }
131
132    public boolean hasReadMethod()
133    {
134        return (this.readMethod != null);
135    }
136    
137    public boolean hasWriterMethod()
138    {
139        return (this.writerMethod != null);
140    }
141    
142    public void resolve(Class<?> targetClass)
143    {
144        setTargetClass(targetClass);
145        if (targetClass != null &&
146            !Map.class.isAssignableFrom(targetClass))
147        {
148            HandleableException handle = new HandlerException();
149            handle.mute(NoSuchMethodException.class)
150                  .mute(NoSuchFieldException.class)
151                  .logInfoOff();
152            
153            ObjectProxy<?> proxy = ObjectProxyFactory.of(this.targetClass);
154            proxy.with(handle);
155            this.field = proxy.getDeclaredField(this.fieldName);
156            this.readMethod = new MethodReflect(handle).getMethod(this.fieldName, this.targetClass);
157            this.writerMethod = new MethodReflect(handle).getMethod(this.fieldName, this.targetClass, CapitalNameFactory.getInstanceOfSetter());
158        }
159    }
160    
161    @Override
162    public String toString()
163    {
164        return "PropertyAccess [fieldName=" + fieldName + ", readMethod=" + readMethod + ", writerMethod="
165                + writerMethod + ", targetClass=" + targetClass + "]";
166    }
167    
168}