src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeanLinker.java
changeset 48244 2bf9071e8dce
parent 48219 f3b561b13ddf
child 48354 c96d4c720995
equal deleted inserted replaced
48243:ddba406af760 48244:2bf9071e8dce
   105 import jdk.dynalink.linker.support.Lookup;
   105 import jdk.dynalink.linker.support.Lookup;
   106 import jdk.dynalink.linker.support.TypeUtilities;
   106 import jdk.dynalink.linker.support.TypeUtilities;
   107 
   107 
   108 /**
   108 /**
   109  * A class that provides linking capabilities for a single POJO class. Normally not used directly, but managed by
   109  * A class that provides linking capabilities for a single POJO class. Normally not used directly, but managed by
   110  * {@link BeansLinker}.
   110  * {@link BeansLinker}. Most of the functionality is provided by the {@link AbstractJavaLinker} superclass; this
       
   111  * class adds length and element operations for arrays and collections.
   111  */
   112  */
   112 class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicLinker {
   113 class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicLinker {
   113     BeanLinker(final Class<?> clazz) {
   114     BeanLinker(final Class<?> clazz) {
   114         super(clazz, Guards.getClassGuard(clazz), Guards.getInstanceOfGuard(clazz));
   115         super(clazz, Guards.getClassGuard(clazz), Guards.getInstanceOfGuard(clazz));
   115         if(clazz.isArray()) {
   116         if(clazz.isArray()) {
   145             if (ns == StandardNamespace.ELEMENT) {
   146             if (ns == StandardNamespace.ELEMENT) {
   146                 if (op == StandardOperation.GET) {
   147                 if (op == StandardOperation.GET) {
   147                     return getElementGetter(req.popNamespace());
   148                     return getElementGetter(req.popNamespace());
   148                 } else if (op == StandardOperation.SET) {
   149                 } else if (op == StandardOperation.SET) {
   149                     return getElementSetter(req.popNamespace());
   150                     return getElementSetter(req.popNamespace());
       
   151                 } else if (op == StandardOperation.REMOVE) {
       
   152                     return getElementRemover(req.popNamespace());
   150                 }
   153                 }
   151             }
   154             }
   152         }
   155         }
   153         return null;
   156         return null;
   154     }
   157     }
   226         // If declared type of receiver at the call site is already an array, a list or map, bind without guard. Thing
   229         // If declared type of receiver at the call site is already an array, a list or map, bind without guard. Thing
   227         // is, it'd be quite stupid of a call site creator to go though invokedynamic when it knows in advance they're
   230         // is, it'd be quite stupid of a call site creator to go though invokedynamic when it knows in advance they're
   228         // dealing with an array, or a list or map, but hey...
   231         // dealing with an array, or a list or map, but hey...
   229         // Note that for arrays and lists, using LinkerServices.asType() will ensure that any language specific linkers
   232         // Note that for arrays and lists, using LinkerServices.asType() will ensure that any language specific linkers
   230         // in use will get a chance to perform any (if there's any) implicit conversion to integer for the indices.
   233         // in use will get a chance to perform any (if there's any) implicit conversion to integer for the indices.
   231         if(declaredType.isArray()) {
   234         if(declaredType.isArray() && arrayMethod != null) {
   232             return new GuardedInvocationComponentAndCollectionType(
   235             return new GuardedInvocationComponentAndCollectionType(
   233                     createInternalFilteredGuardedInvocationComponent(arrayMethod.apply(declaredType), linkerServices),
   236                     createInternalFilteredGuardedInvocationComponent(arrayMethod.apply(declaredType), linkerServices),
   234                     CollectionType.ARRAY);
   237                     CollectionType.ARRAY);
   235         } else if(List.class.isAssignableFrom(declaredType)) {
   238         } else if(List.class.isAssignableFrom(declaredType)) {
   236             return new GuardedInvocationComponentAndCollectionType(
   239             return new GuardedInvocationComponentAndCollectionType(
   238                     CollectionType.LIST);
   241                     CollectionType.LIST);
   239         } else if(Map.class.isAssignableFrom(declaredType)) {
   242         } else if(Map.class.isAssignableFrom(declaredType)) {
   240             return new GuardedInvocationComponentAndCollectionType(
   243             return new GuardedInvocationComponentAndCollectionType(
   241                     createInternalFilteredGuardedInvocationComponent(mapMethod, linkerServices),
   244                     createInternalFilteredGuardedInvocationComponent(mapMethod, linkerServices),
   242                     CollectionType.MAP);
   245                     CollectionType.MAP);
   243         } else if(clazz.isArray()) {
   246         } else if(clazz.isArray() && arrayMethod != null) {
   244             return new GuardedInvocationComponentAndCollectionType(
   247             return new GuardedInvocationComponentAndCollectionType(
   245                     getClassGuardedInvocationComponent(linkerServices.filterInternalObjects(arrayMethod.apply(clazz)), callSiteType),
   248                     getClassGuardedInvocationComponent(linkerServices.filterInternalObjects(arrayMethod.apply(clazz)), callSiteType),
   246                     CollectionType.ARRAY);
   249                     CollectionType.ARRAY);
   247         } else if(List.class.isAssignableFrom(clazz)) {
   250         } else if(List.class.isAssignableFrom(clazz)) {
   248             return new GuardedInvocationComponentAndCollectionType(
   251             return new GuardedInvocationComponentAndCollectionType(
   448         }
   451         }
   449         return 0 <= intIndex && intIndex < list.size();
   452         return 0 <= intIndex && intIndex < list.size();
   450     }
   453     }
   451 
   454 
   452     @SuppressWarnings("unused")
   455     @SuppressWarnings("unused")
   453     private static void noOpSetter() {
   456     private static void noOp() {
   454     }
   457     }
   455 
   458 
   456     private static final MethodHandle SET_LIST_ELEMENT = Lookup.PUBLIC.findVirtual(List.class, "set",
   459     private static final MethodHandle SET_LIST_ELEMENT = Lookup.PUBLIC.findVirtual(List.class, "set",
   457             MethodType.methodType(Object.class, int.class, Object.class));
   460             MethodType.methodType(Object.class, int.class, Object.class));
   458 
   461 
   459     private static final MethodHandle PUT_MAP_ELEMENT = Lookup.PUBLIC.findVirtual(Map.class, "put",
   462     private static final MethodHandle PUT_MAP_ELEMENT = Lookup.PUBLIC.findVirtual(Map.class, "put",
   460             MethodType.methodType(Object.class, Object.class, Object.class));
   463             MethodType.methodType(Object.class, Object.class, Object.class));
   461 
   464 
   462     private static final MethodHandle NO_OP_SETTER_2;
   465     private static final MethodHandle NO_OP_1;
   463     private static final MethodHandle NO_OP_SETTER_3;
   466     private static final MethodHandle NO_OP_2;
       
   467     private static final MethodHandle NO_OP_3;
   464     static {
   468     static {
   465         final MethodHandle noOpSetter = Lookup.findOwnStatic(MethodHandles.lookup(), "noOpSetter", void.class);
   469         final MethodHandle noOp = Lookup.findOwnStatic(MethodHandles.lookup(), "noOp", void.class);
   466         NO_OP_SETTER_2 = dropObjectArguments(noOpSetter, 2);
   470         NO_OP_1 = dropObjectArguments(noOp, 1);
   467         NO_OP_SETTER_3 = dropObjectArguments(noOpSetter, 3);
   471         NO_OP_2 = dropObjectArguments(noOp, 2);
       
   472         NO_OP_3 = dropObjectArguments(noOp, 3);
   468     }
   473     }
   469 
   474 
   470     private GuardedInvocationComponent getElementSetter(final ComponentLinkRequest req) throws Exception {
   475     private GuardedInvocationComponent getElementSetter(final ComponentLinkRequest req) throws Exception {
   471         final CallSiteDescriptor callSiteDescriptor = req.getDescriptor();
   476         final CallSiteDescriptor callSiteDescriptor = req.getDescriptor();
   472         final Object name = req.name;
   477         final Object name = req.name;
   501 
   506 
   502         if (isMap) {
   507         if (isMap) {
   503             return gic.replaceInvocation(binder.bind(invocation));
   508             return gic.replaceInvocation(binder.bind(invocation));
   504         }
   509         }
   505 
   510 
   506         return guardComponentWithRangeCheck(gicact, callSiteType, nextComponent, binder, isFixedKey ? NO_OP_SETTER_2 : NO_OP_SETTER_3);
   511         return guardComponentWithRangeCheck(gicact, callSiteType, nextComponent, binder, isFixedKey ? NO_OP_2 : NO_OP_3);
       
   512     }
       
   513 
       
   514     private static final MethodHandle REMOVE_LIST_ELEMENT = Lookup.PUBLIC.findVirtual(List.class, "remove",
       
   515             MethodType.methodType(Object.class, int.class));
       
   516 
       
   517     private static final MethodHandle REMOVE_MAP_ELEMENT = Lookup.PUBLIC.findVirtual(Map.class, "remove",
       
   518             MethodType.methodType(Object.class, Object.class));
       
   519 
       
   520     private GuardedInvocationComponent getElementRemover(final ComponentLinkRequest req) throws Exception {
       
   521         final CallSiteDescriptor callSiteDescriptor = req.getDescriptor();
       
   522         final Object name = req.name;
       
   523         final boolean isFixedKey = name != null;
       
   524         assertParameterCount(callSiteDescriptor, isFixedKey ? 1 : 2);
       
   525         final LinkerServices linkerServices = req.linkerServices;
       
   526         final MethodType callSiteType = callSiteDescriptor.getMethodType();
       
   527         final GuardedInvocationComponent nextComponent = getNextComponent(req);
       
   528 
       
   529         final GuardedInvocationComponentAndCollectionType gicact = guardedInvocationComponentAndCollectionType(
       
   530                 callSiteType, linkerServices, null, REMOVE_LIST_ELEMENT, REMOVE_MAP_ELEMENT);
       
   531 
       
   532         if (gicact == null) {
       
   533             // Can't remove elements for objects that are neither lists, nor maps.
       
   534             return nextComponent;
       
   535         }
       
   536 
       
   537         final Object typedName = getTypedName(name, gicact.collectionType == CollectionType.MAP, linkerServices);
       
   538         if (typedName == INVALID_NAME) {
       
   539             return nextComponent;
       
   540         }
       
   541 
       
   542         return guardComponentWithRangeCheck(gicact, callSiteType, nextComponent,
       
   543                 new Binder(linkerServices, callSiteType, typedName), isFixedKey ? NO_OP_1: NO_OP_2);
   507     }
   544     }
   508 
   545 
   509     private static final MethodHandle GET_COLLECTION_LENGTH = Lookup.PUBLIC.findVirtual(Collection.class, "size",
   546     private static final MethodHandle GET_COLLECTION_LENGTH = Lookup.PUBLIC.findVirtual(Collection.class, "size",
   510             MethodType.methodType(int.class));
   547             MethodType.methodType(int.class));
   511 
   548