001/* 002 * Copyright 2013 Christopher Pheby 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.jadira.reflection.access.invokedynamic; 017 018import java.lang.invoke.CallSite; 019import java.lang.invoke.MethodHandle; 020import java.lang.invoke.MethodType; 021import java.lang.reflect.Field; 022 023import org.dynalang.dynalink.DefaultBootstrapper; 024import org.jadira.reflection.access.api.FieldAccess; 025 026/** 027 * FieldAccess implementation using an InvokeDynamic based strategy (using ASM and Dynalang) 028 * @param <C> The Class containing the Field to be accessed 029 */ 030public class InvokeDynamicFieldAccess<C> implements FieldAccess<C> { 031 032 private String fieldName; 033 034 private Class<C> declaringClass; 035 private Class<?> fieldClass; 036 private Field field; 037 038 CallSite getCallSite; 039 CallSite setCallSite; 040 041 MethodHandle setMh; 042 MethodHandle getMh; 043 044 @SuppressWarnings("unchecked") 045 private InvokeDynamicFieldAccess(InvokeDynamicClassAccess<C> classAccess, Field f) { 046 047 this.declaringClass = (Class<C>) f.getDeclaringClass(); 048 049 this.fieldClass = f.getType(); 050 051 this.fieldName = f.getName(); 052 053 this.field = f; 054 055 setCallSite = DefaultBootstrapper.publicBootstrap(null, "dyn:setProp:" + fieldName, MethodType.methodType(void.class, Object.class, fieldClass)); 056 getCallSite = DefaultBootstrapper.publicBootstrap(null, "dyn:getProp:" + fieldName, MethodType.methodType(fieldClass, Object.class)); 057 058 setMh = setCallSite.dynamicInvoker(); 059 getMh = getCallSite.dynamicInvoker(); 060 } 061 062 @Override 063 public Class<C> declaringClass() { 064 return declaringClass; 065 } 066 067 @Override 068 public Class<?> fieldClass() { 069 return fieldClass; 070 } 071 072 @Override 073 public Field field() { 074 return field; 075 } 076 077 /** 078 * Get a new instance that can access the given Field 079 * @param classAccess The InvokeDynamicClassAccess instance to be delegated to 080 * @param f Field to be accessed 081 * @param <C> The type of class being accessed 082 * @return New InvokeDynamicFieldAccess instance 083 */ 084 public static final <C> InvokeDynamicFieldAccess<C> get(InvokeDynamicClassAccess<C> classAccess, Field f) { 085 return new InvokeDynamicFieldAccess<C>(classAccess, f); 086 } 087 088 @Override 089 public Object getValue(C parent) { 090 try { 091 return getMh.invokeExact(parent); 092 } catch (Throwable e) { 093 throw new IllegalStateException("Problem accessing {" + field.getName() + "} of object {" 094 + System.identityHashCode(parent) + "}: " + e.getMessage(), e); 095 } 096 } 097 098 @Override 099 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}