View Javadoc
1   /*
2    *  Copyright 2013 Christopher Pheby
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   */
16  package org.jadira.reflection.access.invokedynamic;
17  
18  import java.lang.invoke.CallSite;
19  import java.lang.invoke.MethodHandle;
20  import java.lang.invoke.MethodType;
21  import java.lang.reflect.Field;
22  
23  import org.dynalang.dynalink.DefaultBootstrapper;
24  import org.jadira.reflection.access.api.FieldAccess;
25  
26  /**
27   * FieldAccess implementation using an InvokeDynamic based strategy (using ASM and Dynalang)
28   * @param <C> The Class containing the Field to be accessed
29   */
30  public class InvokeDynamicFieldAccess<C> implements FieldAccess<C> {
31  
32      private String fieldName;
33  	
34  	private Class<C> declaringClass;
35  	private Class<?> fieldClass;
36  	private Field field;	
37  
38  	CallSite getCallSite;
39  	CallSite setCallSite;
40  	
41  	MethodHandle setMh;
42  	MethodHandle getMh;
43  	
44  	@SuppressWarnings("unchecked")
45  	private InvokeDynamicFieldAccess(InvokeDynamicClassAccess<C> classAccess, Field f) {
46  		
47  		this.declaringClass = (Class<C>) f.getDeclaringClass();
48  		
49  		this.fieldClass = f.getType();
50  		
51  		this.fieldName = f.getName();
52  		
53  		this.field = f;
54  		
55  		setCallSite = DefaultBootstrapper.publicBootstrap(null, "dyn:setProp:" + fieldName, MethodType.methodType(void.class, Object.class, fieldClass));
56  		getCallSite = DefaultBootstrapper.publicBootstrap(null, "dyn:getProp:" + fieldName, MethodType.methodType(fieldClass, Object.class));
57  		
58  		setMh = setCallSite.dynamicInvoker();
59  	    getMh = getCallSite.dynamicInvoker();
60  	}
61  	
62  	@Override
63  	public Class<C> declaringClass() {
64  		return declaringClass;
65  	}
66  
67  	@Override
68  	public Class<?> fieldClass() {
69  		return fieldClass;
70  	}
71  
72  	@Override
73  	public Field field() {
74  		return field;
75  	}
76  	
77  	/**
78  	 * Get a new instance that can access the given Field
79  	 * @param classAccess The InvokeDynamicClassAccess instance to be delegated to
80  	 * @param f Field to be accessed
81  	 * @param <C> The type of class being accessed
82  	 * @return New InvokeDynamicFieldAccess instance
83  	 */
84  	public static final <C> InvokeDynamicFieldAccess<C> get(InvokeDynamicClassAccess<C> classAccess, Field f) {
85  		return new InvokeDynamicFieldAccess<C>(classAccess, f);
86  	}
87  
88  	@Override
89  	public Object getValue(C parent) {
90          try {
91              return getMh.invokeExact(parent);
92          } catch (Throwable e) {
93              throw new IllegalStateException("Problem accessing {" + field.getName() + "} of object {"
94                      + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
95          }
96  	}
97  
98  	@Override
99  	public void putValue(C parent, Object newFieldValue) {
100 	    try {
101             setMh.invokeExact(parent, newFieldValue);
102         } catch (Throwable e) {
103             throw new IllegalStateException("Problem accessing {" + field.getName() + "} of object {"
104                     + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
105         }
106 	}
107 
108 	@Override
109 	public boolean getBooleanValue(C parent) {
110         try {
111             return (boolean) getMh.invokeExact(parent);
112         } catch (Throwable e) {
113             throw new IllegalStateException("Problem accessing {" + field.getName() + "} of object {"
114                     + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
115         }
116 	}
117 
118 	@Override
119 	public byte getByteValue(C parent) {
120         try {
121             return (byte) getMh.invokeExact(parent);
122         } catch (Throwable e) {
123             throw new IllegalStateException("Problem accessing {" + field.getName() + "} of object {"
124                     + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
125         }
126 	}
127 
128 	@Override
129 	public char getCharValue(C parent) {
130         try {
131             return (char) getMh.invokeExact(parent);
132         } catch (Throwable e) {
133             throw new IllegalStateException("Problem accessing {" + field.getName() + "} of object {"
134                     + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
135         }
136 	}
137 
138 	@Override
139 	public short getShortValue(C parent) {
140         try {
141             return (short) getMh.invokeExact(parent);
142         } catch (Throwable e) {
143             throw new IllegalStateException("Problem accessing {" + field.getName() + "} of object {"
144                     + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
145         }
146 	}
147 
148 	@Override
149 	public int getIntValue(C parent) {
150         try {
151             return (int) getMh.invokeExact(parent);
152         } catch (Throwable e) {
153             throw new IllegalStateException("Problem accessing {" + field.getName() + "} of object {"
154                     + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
155         }
156 	}
157 
158 	@Override
159 	public long getLongValue(C parent) {
160         try {
161             return (long) getMh.invokeExact(parent);
162         } catch (Throwable e) {
163             throw new IllegalStateException("Problem accessing {" + field.getName() + "} of object {"
164                     + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
165         }
166 	}
167 
168 	@Override
169 	public float getFloatValue(C parent) {
170         try {
171             return (float) getMh.invokeExact(parent);
172         } catch (Throwable e) {
173             throw new IllegalStateException("Problem accessing {" + field.getName() + "} of object {"
174                     + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
175         }
176 	}
177 
178 	@Override
179 	public double getDoubleValue(C parent) {
180         try {
181             return (double) getMh.invokeExact(parent);
182         } catch (Throwable e) {
183             throw new IllegalStateException("Problem accessing {" + field.getName() + "} of object {"
184                     + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
185         }
186 	}
187 
188 	@Override
189 	public void putBooleanValue(C parent, boolean newFieldValue) {
190 	    try {
191             setMh.invokeExact(parent, newFieldValue);
192         } catch (Throwable e) {
193             throw new IllegalStateException("Problem accessing {" + field.getName() + "} of object {"
194                     + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
195         }
196 	}
197 
198 	@Override
199 	public void putByteValue(C parent, byte newFieldValue) {
200 	    try {
201             setMh.invokeExact(parent, newFieldValue);
202         } catch (Throwable e) {
203             throw new IllegalStateException("Problem accessing {" + field.getName() + "} of object {"
204                     + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
205         }
206 	}
207 
208 	@Override
209 	public void putCharValue(C parent, char newFieldValue) {
210 	    try {
211             setMh.invokeExact(parent, newFieldValue);
212         } catch (Throwable e) {
213             throw new IllegalStateException("Problem accessing {" + field.getName() + "} of object {"
214                     + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
215         }
216 	}
217 
218 	@Override
219 	public void putShortValue(C parent, short newFieldValue) {
220 	    try {
221             setMh.invokeExact(parent, newFieldValue);
222         } catch (Throwable e) {
223             throw new IllegalStateException("Problem accessing {" + field.getName() + "} of object {"
224                     + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
225         }
226 	}
227 
228 	@Override
229 	public void putIntValue(C parent, int newFieldValue) {
230 	    try {
231             setMh.invokeExact(parent, newFieldValue);
232         } catch (Throwable e) {
233             throw new IllegalStateException("Problem accessing {" + field.getName() + "} of object {"
234                     + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
235         }
236 	}
237 
238 	@Override
239 	public void putLongValue(C parent, long newFieldValue) {
240 	    try {
241             setMh.invokeExact(parent, newFieldValue);
242         } catch (Throwable e) {
243             throw new IllegalStateException("Problem accessing {" + field.getName() + "} of object {"
244                     + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
245         }
246 	}
247 
248 	@Override
249 	public void putFloatValue(C parent, float newFieldValue) {
250 	    try {
251             setMh.invokeExact(parent, newFieldValue);
252         } catch (Throwable e) {
253             throw new IllegalStateException("Problem accessing {" + field.getName() + "} of object {"
254                     + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
255         }
256 	}
257 
258 	@Override
259 	public void putDoubleValue(C parent, double newFieldValue) {
260 	    try {
261             setMh.invokeExact(parent, newFieldValue);
262         } catch (Throwable e) {
263             throw new IllegalStateException("Problem accessing {" + field.getName() + "} of object {"
264                     + System.identityHashCode(parent) + "}: " + e.getMessage(), e);
265         }
266 	}
267 }