126 this.clazz = clazz; |
125 this.clazz = clazz; |
127 this.classGuard = classGuard; |
126 this.classGuard = classGuard; |
128 this.assignableGuard = assignableGuard; |
127 this.assignableGuard = assignableGuard; |
129 |
128 |
130 final FacetIntrospector introspector = createFacetIntrospector(); |
129 final FacetIntrospector introspector = createFacetIntrospector(); |
131 try { |
130 // Add methods and properties |
132 // Add methods and properties |
131 for(Method method: introspector.getMethods()) { |
133 for(Method method: introspector.getMethods()) { |
132 final String name = method.getName(); |
134 final String name = method.getName(); |
133 final MethodHandle methodHandle = introspector.unreflect(method); |
135 final MethodHandle methodHandle = introspector.unreflect(method); |
134 // Add method |
136 // Add method |
135 addMember(name, methodHandle, methods); |
137 addMember(name, methodHandle, methods); |
136 // Add the method as a property getter and/or setter |
138 // Add the method as a property getter and/or setter |
137 if(name.startsWith("get") && name.length() > 3 && method.getParameterTypes().length == 0) { |
139 if(name.startsWith("get") && name.length() > 3 && method.getParameterTypes().length == 0) { |
138 // Property getter |
140 // Property getter |
139 setPropertyGetter(Introspector.decapitalize(name.substring(3)), introspector.unreflect( |
141 setPropertyGetter(Introspector.decapitalize(name.substring(3)), introspector.unreflect( |
140 getMostGenericGetter(method)), ValidationType.INSTANCE_OF); |
142 getMostGenericGetter(method)), ValidationType.INSTANCE_OF); |
141 } else if(name.startsWith("is") && name.length() > 2 && method.getParameterTypes().length == 0 && |
143 } else if(name.startsWith("is") && name.length() > 2 && method.getParameterTypes().length == 0 && |
142 method.getReturnType() == boolean.class) { |
144 method.getReturnType() == boolean.class) { |
143 // Boolean property getter |
145 // Boolean property getter |
144 setPropertyGetter(Introspector.decapitalize(name.substring(2)), introspector.unreflect( |
146 setPropertyGetter(Introspector.decapitalize(name.substring(2)), introspector.unreflect( |
145 getMostGenericGetter(method)), ValidationType.INSTANCE_OF); |
147 getMostGenericGetter(method)), ValidationType.INSTANCE_OF); |
146 } else if(name.startsWith("set") && name.length() > 3 && method.getParameterTypes().length == 1) { |
148 } else if(name.startsWith("set") && name.length() > 3 && method.getParameterTypes().length == 1) { |
147 // Property setter |
149 // Property setter |
148 addMember(Introspector.decapitalize(name.substring(3)), methodHandle, propertySetters); |
150 addMember(Introspector.decapitalize(name.substring(3)), methodHandle, propertySetters); |
149 } |
151 } |
150 } |
152 } |
151 |
153 |
152 // Add field getter/setters as property getters/setters. |
154 // Add field getter/setters as property getters/setters. |
153 for(Field field: introspector.getFields()) { |
155 for(Field field: introspector.getFields()) { |
154 final String name = field.getName(); |
156 final String name = field.getName(); |
155 // Only add a property getter when one is not defined already as a getXxx()/isXxx() method. |
157 // Only add a property getter when one is not defined already as a getXxx()/isXxx() method. |
156 if(!propertyGetters.containsKey(name)) { |
158 if(!propertyGetters.containsKey(name)) { |
157 setPropertyGetter(name, introspector.unreflectGetter(field), ValidationType.EXACT_CLASS); |
159 setPropertyGetter(name, introspector.unreflectGetter(field), ValidationType.EXACT_CLASS); |
158 } |
160 } |
159 if(!(Modifier.isFinal(field.getModifiers()) || propertySetters.containsKey(name))) { |
161 if(!(Modifier.isFinal(field.getModifiers()) || propertySetters.containsKey(name))) { |
160 addMember(name, introspector.unreflectSetter(field), propertySetters); |
162 addMember(name, introspector.unreflectSetter(field), propertySetters); |
161 } |
163 } |
162 } |
164 } |
163 |
165 |
164 // Add inner classes, but only those for which we don't hide a property with it |
166 // Add inner classes, but only those for which we don't hide a property with it |
165 for(Map.Entry<String, MethodHandle> innerClassSpec: introspector.getInnerClassGetters().entrySet()) { |
167 for(Map.Entry<String, MethodHandle> innerClassSpec: introspector.getInnerClassGetters().entrySet()) { |
166 final String name = innerClassSpec.getKey(); |
168 final String name = innerClassSpec.getKey(); |
167 if(!propertyGetters.containsKey(name)) { |
169 if(!propertyGetters.containsKey(name)) { |
168 setPropertyGetter(name, innerClassSpec.getValue(), ValidationType.EXACT_CLASS); |
170 setPropertyGetter(name, innerClassSpec.getValue(), ValidationType.EXACT_CLASS); |
169 } |
171 } |
|
172 } |
|
173 } finally { |
|
174 introspector.close(); |
|
175 } |
170 } |
176 } |
171 } |
177 |
172 |
178 abstract FacetIntrospector createFacetIntrospector(); |
173 abstract FacetIntrospector createFacetIntrospector(); |
179 |
174 |
392 // fold(R(MethodHandle, O, N, V), MethodHandle(O, N, V)) |
387 // fold(R(MethodHandle, O, N, V), MethodHandle(O, N, V)) |
393 final MethodHandle compositeSetter = MethodHandles.foldArguments(MethodHandles.guardWithTest( |
388 final MethodHandle compositeSetter = MethodHandles.foldArguments(MethodHandles.guardWithTest( |
394 IS_METHOD_HANDLE_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter); |
389 IS_METHOD_HANDLE_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter); |
395 if(nextComponent == null) { |
390 if(nextComponent == null) { |
396 return getClassGuardedInvocationComponent(compositeSetter, type); |
391 return getClassGuardedInvocationComponent(compositeSetter, type); |
397 } else { |
392 } |
398 return nextComponent.compose(compositeSetter, getClassGuard(type), clazz, |
393 return nextComponent.compose(compositeSetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS); |
399 ValidationType.EXACT_CLASS); |
|
400 } |
|
401 } |
394 } |
402 case 3: { |
395 case 3: { |
403 // Must have two arguments: target object and property value |
396 // Must have two arguments: target object and property value |
404 assertParameterCount(callSiteDescriptor, 2); |
397 assertParameterCount(callSiteDescriptor, 2); |
405 final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor.getMethodType(), |
398 final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor.getMethodType(), |
472 // fold(R(AnnotatedMethodHandle, T0, T1), AnnotatedMethodHandle(T0, T1)) |
465 // fold(R(AnnotatedMethodHandle, T0, T1), AnnotatedMethodHandle(T0, T1)) |
473 final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest( |
466 final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest( |
474 IS_ANNOTATED_HANDLE_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter); |
467 IS_ANNOTATED_HANDLE_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter); |
475 if(nextComponent == null) { |
468 if(nextComponent == null) { |
476 return getClassGuardedInvocationComponent(compositeGetter, type); |
469 return getClassGuardedInvocationComponent(compositeGetter, type); |
477 } else { |
470 } |
478 return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, |
471 return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS); |
479 ValidationType.EXACT_CLASS); |
|
480 } |
|
481 } |
472 } |
482 case 3: { |
473 case 3: { |
483 // Must have exactly one argument: receiver |
474 // Must have exactly one argument: receiver |
484 assertParameterCount(callSiteDescriptor, 1); |
475 assertParameterCount(callSiteDescriptor, 1); |
485 // Fixed name |
476 // Fixed name |
539 final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor, |
532 final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor, |
540 linkerServices, ops); |
533 linkerServices, ops); |
541 if(nextComponent == null) { |
534 if(nextComponent == null) { |
542 // No next component operation; just return a component for this operation. |
535 // No next component operation; just return a component for this operation. |
543 return getClassGuardedInvocationComponent(linkerServices.asType(getDynamicMethod, type), type); |
536 return getClassGuardedInvocationComponent(linkerServices.asType(getDynamicMethod, type), type); |
544 } else { |
537 } |
545 // What's below is basically: |
538 |
546 // foldArguments(guardWithTest(isNotNull, identity, nextComponent.invocation), getter) |
539 // What's below is basically: |
547 // only with a bunch of method signature adjustments. Basically, execute method getter; if |
540 // foldArguments(guardWithTest(isNotNull, identity, nextComponent.invocation), getter) only with a |
548 // it returns a non-null DynamicMethod, use identity to return it, otherwise delegate to |
541 // bunch of method signature adjustments. Basically, execute method getter; if it returns a non-null |
549 // nextComponent's invocation. |
542 // DynamicMethod, use identity to return it, otherwise delegate to nextComponent's invocation. |
550 |
543 |
551 final MethodHandle typedGetter = linkerServices.asType(getDynamicMethod, type.changeReturnType( |
544 final MethodHandle typedGetter = linkerServices.asType(getDynamicMethod, type.changeReturnType( |
552 DynamicMethod.class)); |
545 DynamicMethod.class)); |
553 // Since it is part of the foldArgument() target, it will have extra args that we need to drop. |
546 // Since it is part of the foldArgument() target, it will have extra args that we need to drop. |
554 final MethodHandle returnMethodHandle = linkerServices.asType(MethodHandles.dropArguments( |
547 final MethodHandle returnMethodHandle = linkerServices.asType(MethodHandles.dropArguments( |
555 DYNAMIC_METHOD_IDENTITY, 1, type.parameterList()), type.insertParameterTypes(0, |
548 DYNAMIC_METHOD_IDENTITY, 1, type.parameterList()), type.insertParameterTypes(0, |
556 DynamicMethod.class)); |
549 DynamicMethod.class)); |
557 final MethodHandle nextComponentInvocation = nextComponent.getGuardedInvocation().getInvocation(); |
550 final MethodHandle nextComponentInvocation = nextComponent.getGuardedInvocation().getInvocation(); |
558 // The assumption is that getGuardedInvocationComponent() already asType()'d it correctly |
551 // The assumption is that getGuardedInvocationComponent() already asType()'d it correctly |
559 assert nextComponentInvocation.type().equals(type); |
552 assert nextComponentInvocation.type().equals(type); |
560 // Since it is part of the foldArgument() target, we have to drop an extra arg it receives. |
553 // Since it is part of the foldArgument() target, we have to drop an extra arg it receives. |
561 final MethodHandle nextCombinedInvocation = MethodHandles.dropArguments(nextComponentInvocation, 0, |
554 final MethodHandle nextCombinedInvocation = MethodHandles.dropArguments(nextComponentInvocation, 0, |
562 DynamicMethod.class); |
555 DynamicMethod.class); |
563 // Assemble it all into a fold(guard(isNotNull, identity, nextInvocation), get) |
556 // Assemble it all into a fold(guard(isNotNull, identity, nextInvocation), get) |
564 final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest( |
557 final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest( |
565 IS_DYNAMIC_METHOD_NOT_NULL, returnMethodHandle, nextCombinedInvocation), typedGetter); |
558 IS_DYNAMIC_METHOD_NOT_NULL, returnMethodHandle, nextCombinedInvocation), typedGetter); |
566 |
559 |
567 return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, |
560 return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS); |
568 ValidationType.EXACT_CLASS); |
|
569 } |
|
570 } |
561 } |
571 case 3: { |
562 case 3: { |
572 // Must have exactly one argument: receiver |
563 // Must have exactly one argument: receiver |
573 assertParameterCount(callSiteDescriptor, 1); |
564 assertParameterCount(callSiteDescriptor, 1); |
574 final DynamicMethod method = getDynamicMethod(callSiteDescriptor.getNameToken( |
565 final DynamicMethod method = getDynamicMethod(callSiteDescriptor.getNameToken( |