View Javadoc
1   /*-
2    * #%L
3    * io.earcam.instrumental.module.auto
4    * %%
5    * Copyright (C) 2018 earcam
6    * %%
7    * SPDX-License-Identifier: (BSD-3-Clause OR EPL-1.0 OR Apache-2.0 OR MIT)
8    * 
9    * You <b>must</b> choose to accept, in full - any individual or combination of 
10   * the following licenses:
11   * <ul>
12   * 	<li><a href="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</a></li>
13   * 	<li><a href="https://www.eclipse.org/legal/epl-v10.html">EPL-1.0</a></li>
14   * 	<li><a href="https://www.apache.org/licenses/LICENSE-2.0">Apache-2.0</a></li>
15   * 	<li><a href="https://opensource.org/licenses/MIT">MIT</a></li>
16   * </ul>
17   * #L%
18   */
19  package io.earcam.instrumental.module.auto;
20  
21  import static java.util.Arrays.asList;
22  import static java.util.Collections.unmodifiableSet;
23  import static java.util.stream.Collectors.toSet;
24  
25  import java.util.Arrays;
26  import java.util.Set;
27  import java.util.function.Consumer;
28  
29  import org.objectweb.asm.Type;
30  import org.objectweb.asm.commons.Remapper;
31  
32  /**
33   * TODO
34   * <ol>
35   * <li>Optionally skip imports found only in annotations and the annotations themselves</li>
36   * <li>Tests for Generic types/methods, lambdas, etc - override mapDesc and take a peek</li>
37   * </ol>
38   */
39  class ImportsOf extends Remapper {
40  
41  	private static final Set<String> PRIMITIVES = namesOf(
42  			short.class, int.class, long.class, float.class, double.class, char.class, byte.class, boolean.class, void.class);
43  
44  	private Consumer<String> importConsumer;
45  
46  
47  	/**
48  	 * <p>
49  	 * Constructor for ImportsOf.
50  	 * </p>
51  	 *
52  	 * @param importConsumer a {@link Consumer} of imported types.
53  	 */
54  	public ImportsOf(Consumer<String> importConsumer)
55  	{
56  		this.importConsumer = importConsumer;
57  	}
58  
59  
60  	private static Set<String> namesOf(Class<?>... items)
61  	{
62  		return unmodifiableSet(asList(items).stream()
63  				.map(Class::getCanonicalName)
64  				.collect(toSet()));
65  	}
66  
67  
68  	static boolean isPrimitive(String type)
69  	{
70  		return PRIMITIVES.contains(type);
71  	}
72  
73  
74  	@Override
75  	public String map(String typeName)
76  	{
77  		String mapped = super.map(typeName);
78  		addInternalType(typeName);
79  		return mapped;
80  	}
81  
82  
83  	@Override
84  	public String mapType(String type)
85  	{
86  		String mapped = super.mapType(type);
87  		addInternalType(type);
88  		return mapped;
89  	}
90  
91  
92  	void addInternalType(String internal)
93  	{
94  		Type type = Type.getObjectType(internal);
95  		addInternalType(type);
96  	}
97  
98  
99  	void addInternalType(Type type)
100 	{
101 		if(Type.ARRAY == type.getSort()) {
102 			return;// element/component type will be mapped later
103 		}
104 		String name = externalName(type);
105 		if(!isPrimitive(name)) {
106 			importConsumer.accept(name);
107 		}
108 	}
109 
110 
111 	String externalName(Type type)
112 	{
113 		return type.getClassName().replace('/', '.');
114 	}
115 
116 
117 	@Override
118 	public String[] mapTypes(String[] types)
119 	{
120 		String[] mapped = super.mapTypes(types);
121 		Arrays.stream(types).forEach(this::addInternalType);
122 		return mapped;
123 	}
124 }