1 /* 2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * - Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * - Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * - Neither the name of Oracle nor the names of its 16 * contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 20 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 import java.lang.invoke.MethodHandle; 33 import java.lang.invoke.MethodHandles; 34 import java.lang.invoke.MethodType; 35 import java.util.ArrayList; 36 import java.util.List; 37 import java.util.stream.DoubleStream; 38 import java.util.stream.IntStream; 39 import java.util.stream.LongStream; 40 import java.util.stream.Stream; 41 import jdk.dynalink.CallSiteDescriptor; 42 import jdk.dynalink.CompositeOperation; 43 import jdk.dynalink.NamedOperation; 44 import jdk.dynalink.Operation; 45 import jdk.dynalink.StandardOperation; 46 import jdk.dynalink.linker.GuardingDynamicLinker; 47 import jdk.dynalink.linker.GuardingDynamicLinkerExporter; 48 import jdk.dynalink.linker.GuardedInvocation; 49 import jdk.dynalink.linker.TypeBasedGuardingDynamicLinker; 50 import jdk.dynalink.linker.LinkRequest; 51 import jdk.dynalink.linker.LinkerServices; 52 import jdk.dynalink.linker.support.Guards; 53 import jdk.dynalink.linker.support.Lookup; 54 55 /** 56 * This is a dynalink pluggable linker (see http://openjdk.java.net/jeps/276). 57 * This linker adds "stream" property to Java arrays. The appropriate Stream 58 * type object is returned for "stream" property on Java arrays. Note that 59 * the dynalink beans linker just adds "length" property and Java array objects 60 * don't have any other property. "stream" property does not conflict with anything 61 * else! 62 */ 63 public final class ArrayStreamLinkerExporter extends GuardingDynamicLinkerExporter { 64 static { 65 System.out.println("pluggable dynalink array stream linker loaded"); 66 } 67 68 public static Object arrayToStream(Object array) { 69 if (array instanceof int[]) { 70 return IntStream.of((int[])array); 71 } else if (array instanceof long[]) { 72 return LongStream.of((long[])array); 73 } else if (array instanceof double[]) { 74 return DoubleStream.of((double[])array); 75 } else if (array instanceof Object[]) { 76 return Stream.of((Object[])array); 77 } else { 78 throw new IllegalArgumentException(); 79 } 80 } 81 82 private static final MethodType GUARD_TYPE = MethodType.methodType(Boolean.TYPE, Object.class); 83 private static final MethodHandle ARRAY_TO_STREAM = Lookup.PUBLIC.findStatic( 84 ArrayStreamLinkerExporter.class, "arrayToStream", 85 MethodType.methodType(Object.class, Object.class)); 86 87 @Override 88 public List<GuardingDynamicLinker> get() { 89 final ArrayList<GuardingDynamicLinker> linkers = new ArrayList<>(); 90 linkers.add(new TypeBasedGuardingDynamicLinker() { 91 @Override 92 public boolean canLinkType(final Class<?> type) { 93 return type == Object[].class || type == int[].class || 94 type == long[].class || type == double[].class; 95 } 96 97 @Override 98 public GuardedInvocation getGuardedInvocation(LinkRequest request, 99 LinkerServices linkerServices) throws Exception { 100 final Object self = request.getReceiver(); 101 if (self == null || !canLinkType(self.getClass())) { 102 return null; 103 } 104 105 CallSiteDescriptor desc = request.getCallSiteDescriptor(); 106 Operation op = desc.getOperation(); 107 Object name = NamedOperation.getName(op); 108 boolean getProp = CompositeOperation.contains( 109 NamedOperation.getBaseOperation(op), 110 StandardOperation.GET_PROPERTY); 111 if (getProp && name instanceof String) { 112 String nameStr = (String)name; 113 if (nameStr.equals("stream")) { 114 return new GuardedInvocation(ARRAY_TO_STREAM, 115 Guards.isOfClass(self.getClass(), GUARD_TYPE)); 116 } 117 } 118 119 return null; 120 } 121 }); 122 return linkers; 123 } 124 }