1 /* 2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.xml.internal.bind.v2.runtime.reflect.opt; 27 28 import java.lang.reflect.Field; 29 import java.lang.reflect.Method; 30 import java.lang.reflect.Modifier; 31 import java.util.logging.Level; 32 import java.util.logging.Logger; 33 34 import com.sun.xml.internal.bind.Util; 35 import com.sun.xml.internal.bind.v2.runtime.reflect.Accessor; 36 import com.sun.xml.internal.bind.v2.runtime.RuntimeUtil; 37 38 import static com.sun.xml.internal.bind.v2.bytecode.ClassTailor.toVMClassName; 39 import static com.sun.xml.internal.bind.v2.bytecode.ClassTailor.toVMTypeName; 40 41 /** 42 * @author Kohsuke Kawaguchi 43 */ 44 public abstract class OptimizedAccessorFactory { 45 private OptimizedAccessorFactory() {} // no instanciation please 46 47 private static final Logger logger = Util.getClassLogger(); 48 49 50 private static final String fieldTemplateName; 51 private static final String methodTemplateName; 52 53 static { 54 String s = FieldAccessor_Byte.class.getName(); 55 fieldTemplateName = s.substring(0,s.length()-"Byte".length()).replace('.','/'); 56 57 s = MethodAccessor_Byte.class.getName(); 58 methodTemplateName = s.substring(0,s.length()-"Byte".length()).replace('.','/'); 59 } 60 61 /** 62 * Gets the optimized {@link Accessor} that accesses the given getter/setter. 63 * 64 * @return null 65 * if for some reason it fails to create an optimized version. 66 */ 67 public static final <B,V> Accessor<B,V> get(Method getter, Method setter) { 68 // make sure the method signatures are what we expect 69 if(getter.getParameterTypes().length!=0) 70 return null; 71 Class<?>[] sparams = setter.getParameterTypes(); 72 if(sparams.length!=1) 73 return null; 74 if(sparams[0]!=getter.getReturnType()) 75 return null; 76 if(setter.getReturnType()!=Void.TYPE) 77 return null; 78 if(getter.getDeclaringClass()!=setter.getDeclaringClass()) 79 return null; 80 if(Modifier.isPrivate(getter.getModifiers()) || Modifier.isPrivate(setter.getModifiers())) 81 // we can't access private fields 82 return null; 83 84 Class t = sparams[0]; 85 String typeName = t.getName().replace('.','_'); 86 if (t.isArray()) { 87 typeName = "AOf_"; 88 String compName = t.getComponentType().getName().replace('.','_'); 89 while (compName.startsWith("[L")) { 90 compName = compName.substring(2); 91 typeName += "AOf_"; 92 } 93 typeName = typeName + compName; 94 } 95 96 String newClassName = toVMClassName(getter.getDeclaringClass())+"$JaxbAccessorM_"+getter.getName()+'_'+setter.getName()+'_'+typeName; 97 Class opt; 98 99 if(t.isPrimitive()) 100 opt = AccessorInjector.prepare( getter.getDeclaringClass(), 101 methodTemplateName+RuntimeUtil.primitiveToBox.get(t).getSimpleName(), 102 newClassName, 103 toVMClassName(Bean.class), 104 toVMClassName(getter.getDeclaringClass()), 105 "get_"+t.getName(), 106 getter.getName(), 107 "set_"+t.getName(), 108 setter.getName()); 109 else 110 opt = AccessorInjector.prepare( getter.getDeclaringClass(), 111 methodTemplateName+"Ref", 112 newClassName, 113 toVMClassName(Bean.class), 114 toVMClassName(getter.getDeclaringClass()), 115 toVMClassName(Ref.class), 116 toVMClassName(t), 117 "()"+toVMTypeName(Ref.class), 118 "()"+toVMTypeName(t), 119 '('+toVMTypeName(Ref.class)+")V", 120 '('+toVMTypeName(t)+")V", 121 "get_ref", 122 getter.getName(), 123 "set_ref", 124 setter.getName()); 125 126 if(opt==null) 127 return null; 128 129 Accessor<B,V> acc = instanciate(opt); 130 if (acc!=null) { 131 if (logger.isLoggable(Level.FINE)) { 132 logger.log(Level.FINE, "Using optimized Accessor for {0} and {1}", new Object[]{getter, setter}); 133 } 134 } 135 return acc; 136 } 137 138 139 /** 140 * Gets the optimized {@link Accessor} that accesses the given field. 141 * 142 * @return null 143 * if for some reason it fails to create an optimized version. 144 */ 145 public static final <B,V> Accessor<B,V> get(Field field) { 146 int mods = field.getModifiers(); 147 if(Modifier.isPrivate(mods) || Modifier.isFinal(mods)) 148 // we can't access private fields 149 return null; 150 151 String newClassName = toVMClassName(field.getDeclaringClass())+"$JaxbAccessorF_"+field.getName(); 152 153 Class opt; 154 155 if(field.getType().isPrimitive()) 156 opt = AccessorInjector.prepare( field.getDeclaringClass(), 157 fieldTemplateName+RuntimeUtil.primitiveToBox.get(field.getType()).getSimpleName(), 158 newClassName, 159 toVMClassName(Bean.class), 160 toVMClassName(field.getDeclaringClass()), 161 "f_"+field.getType().getName(), 162 field.getName() ); 163 else 164 opt = AccessorInjector.prepare( field.getDeclaringClass(), 165 fieldTemplateName+"Ref", 166 newClassName, 167 toVMClassName(Bean.class), 168 toVMClassName(field.getDeclaringClass()), 169 toVMClassName(Ref.class), 170 toVMClassName(field.getType()), 171 toVMTypeName(Ref.class), 172 toVMTypeName(field.getType()), 173 "f_ref", 174 field.getName() ); 175 176 if(opt==null) 177 return null; 178 179 Accessor<B,V> acc = instanciate(opt); 180 if (acc!=null) { 181 if (logger.isLoggable(Level.FINE)) { 182 logger.log(Level.FINE, "Using optimized Accessor for {0}", field); 183 } 184 } 185 return acc; 186 } 187 188 private static <B,V> Accessor<B,V> instanciate(Class opt) { 189 try { 190 return (Accessor<B,V>)opt.newInstance(); 191 } catch (InstantiationException e) { 192 logger.log(Level.INFO,"failed to load an optimized Accessor",e); 193 } catch (IllegalAccessException e) { 194 logger.log(Level.INFO,"failed to load an optimized Accessor",e); 195 } catch (SecurityException e) { 196 logger.log(Level.INFO,"failed to load an optimized Accessor",e); 197 } 198 return null; 199 } 200 }