|
11 | 11 | import java.util.Set;
|
12 | 12 |
|
13 | 13 |
|
14 |
| -public class DefaultReflector implements Reflector |
15 |
| -{ |
16 |
| - protected final ReflectorIsolatedClassLoader isolatedClassLoader; |
17 |
| - protected Object classFinder; |
18 |
| - |
19 |
| - public DefaultReflector(final ReflectorIsolatedClassLoader isolatedClassLoader) { |
20 |
| - this.isolatedClassLoader = Objects.requireNonNull(isolatedClassLoader); |
21 |
| - } |
22 |
| - |
23 |
| - public DefaultReflector(final Object copyFromOtherClassLoader) { |
24 |
| - try { |
25 |
| - isolatedClassLoader = Objects.requireNonNull( |
26 |
| - ReflectTools.getJavaFieldValue( |
27 |
| - copyFromOtherClassLoader, |
28 |
| - "isolatedClassLoader", |
29 |
| - ReflectorIsolatedClassLoader.class)); |
30 |
| - |
31 |
| - classFinder = ReflectTools.getJavaFieldValue(copyFromOtherClassLoader, "classFinder"); |
32 |
| - } |
33 |
| - catch(final Exception e) { |
34 |
| - throw new IllegalArgumentException( |
35 |
| - "Object of type " + copyFromOtherClassLoader.getClass().getName() + " is not compatible to " |
36 |
| - + getClass().getName(), |
37 |
| - e); |
38 |
| - } |
39 |
| - } |
40 |
| - |
41 |
| - @Override |
42 |
| - public ReflectorIsolatedClassLoader getIsolatedClassLoader() { |
43 |
| - return isolatedClassLoader; |
44 |
| - } |
45 |
| - |
46 |
| - protected Object getOrCreateClassFinderForIsolatedClassLoader() throws ReflectiveOperationException { |
47 |
| - if(classFinder == null) |
48 |
| - { |
49 |
| - initClassFinder(); |
50 |
| - } |
51 |
| - return classFinder; |
52 |
| - } |
53 |
| - |
54 |
| - protected synchronized void initClassFinder() throws ReflectiveOperationException { |
55 |
| - if(classFinder == null) { |
56 |
| - final Class<?> classFinderImplClass = getIsolatedClassLoader().loadClass( |
57 |
| - ReflectionsClassFinder.class.getName()); |
58 |
| - classFinder = classFinderImplClass |
59 |
| - .getConstructor(ClassLoader.class, URL[].class) |
60 |
| - .newInstance( |
61 |
| - isolatedClassLoader, |
62 |
| - isolatedClassLoader.urlsToScan()); |
63 |
| - } |
64 |
| - } |
65 |
| - |
66 |
| - @Override |
67 |
| - public Mojo createIsolatedMojo( |
68 |
| - final FlowModeAbstractMojo sourceMojo, |
69 |
| - final Set<String> ignoredFields) |
70 |
| - throws Exception { |
71 |
| - |
72 |
| - final Class<?> targetMojoClass = getIsolatedClassLoader().loadClass(sourceMojo.getClass().getName()); |
73 |
| - final Object targetMojo = targetMojoClass.getConstructor().newInstance(); |
74 |
| - copyFields(sourceMojo, targetMojo, ignoredFields); |
75 |
| - |
76 |
| - ReflectTools.setJavaFieldValue( |
77 |
| - targetMojo, |
78 |
| - FlowModeAbstractMojo.CLASSFINDER_FIELD_NAME, |
79 |
| - getOrCreateClassFinderForIsolatedClassLoader()); |
80 |
| - |
81 |
| - return (Mojo)targetMojo; |
82 |
| - } |
83 |
| - |
84 |
| - protected void copyFields( |
85 |
| - final FlowModeAbstractMojo sourceMojo, |
86 |
| - final Object targetMojo, |
87 |
| - final Set<String> ignoredFields) |
88 |
| - throws IllegalAccessException, NoSuchFieldException { |
89 |
| - Class<?> sourceClass = sourceMojo.getClass(); |
90 |
| - Class<?> targetClass = targetMojo.getClass(); |
91 |
| - while(sourceClass != null && sourceClass != Object.class) |
92 |
| - { |
93 |
| - for(final Field sourceField : Arrays.stream(sourceClass.getDeclaredFields()) |
94 |
| - .filter(f -> !ignoredFields.contains(f.getName())) |
95 |
| - .toList()) |
96 |
| - { |
97 |
| - copyField(sourceMojo, targetMojo, sourceField, targetClass); |
98 |
| - } |
99 |
| - targetClass = targetClass.getSuperclass(); |
100 |
| - sourceClass = sourceClass.getSuperclass(); |
101 |
| - } |
102 |
| - } |
103 |
| - |
104 |
| - protected void copyField( |
105 |
| - final FlowModeAbstractMojo sourceMojo, |
106 |
| - final Object targetMojo, |
107 |
| - final Field sourceField, |
108 |
| - final Class<?> targetClass) |
109 |
| - throws IllegalAccessException, NoSuchFieldException { |
110 |
| - if(Modifier.isStatic(sourceField.getModifiers())) |
111 |
| - { |
112 |
| - return; |
113 |
| - } |
114 |
| - sourceField.setAccessible(true); |
115 |
| - final Object value = sourceField.get(sourceMojo); |
116 |
| - if(value == null) |
117 |
| - { |
118 |
| - return; |
119 |
| - } |
120 |
| - final Field targetField; |
121 |
| - try |
122 |
| - { |
123 |
| - targetField = targetClass.getDeclaredField(sourceField.getName()); |
124 |
| - } |
125 |
| - catch(final NoSuchFieldException ex) |
126 |
| - { |
127 |
| - // Should never happen, since the class definition should be the same |
128 |
| - final String message = "Field " + sourceField.getName() + " defined in " |
129 |
| - + sourceField.getDeclaringClass().getName() |
130 |
| - + " is missing in " + targetClass.getName(); |
131 |
| - sourceMojo.logError(message, ex); |
132 |
| - throw ex; |
133 |
| - } |
134 |
| - |
135 |
| - final Class<?> targetFieldType = targetField.getType(); |
136 |
| - if(!targetFieldType.isAssignableFrom(sourceField.getType())) |
137 |
| - { |
138 |
| - final String message = "Field " + targetFieldType.getName() + " in class " |
139 |
| - + targetClass.getName() + " of type " |
140 |
| - + targetFieldType.getName() |
141 |
| - + " is loaded from different class loaders." |
142 |
| - + " Source class loader: " |
143 |
| - + sourceField.getType().getClassLoader() |
144 |
| - + ", Target class loader: " |
145 |
| - + targetFieldType.getClassLoader() |
146 |
| - + ". This is likely a bug in the Vaadin Maven plugin." |
147 |
| - + " Please, report the error on the issue tracker."; |
148 |
| - sourceMojo.logError(message); |
149 |
| - throw new NoSuchFieldException(message); |
150 |
| - } |
151 |
| - targetField.setAccessible(true); |
152 |
| - targetField.set(targetMojo, value); |
153 |
| - } |
| 14 | +public class DefaultReflector implements Reflector { |
| 15 | + protected final ReflectorIsolatedClassLoader isolatedClassLoader; |
| 16 | + protected Object classFinder; |
| 17 | + |
| 18 | + public DefaultReflector(final ReflectorIsolatedClassLoader isolatedClassLoader) { |
| 19 | + this.isolatedClassLoader = Objects.requireNonNull(isolatedClassLoader); |
| 20 | + } |
| 21 | + |
| 22 | + public DefaultReflector(final Object copyFromOtherClassLoader) { |
| 23 | + try { |
| 24 | + isolatedClassLoader = Objects.requireNonNull( |
| 25 | + ReflectTools.getJavaFieldValue( |
| 26 | + copyFromOtherClassLoader, |
| 27 | + "isolatedClassLoader", |
| 28 | + ReflectorIsolatedClassLoader.class)); |
| 29 | + |
| 30 | + classFinder = ReflectTools.getJavaFieldValue(copyFromOtherClassLoader, "classFinder"); |
| 31 | + } catch (final Exception e) { |
| 32 | + throw new IllegalArgumentException( |
| 33 | + "Object of type " + copyFromOtherClassLoader.getClass().getName() + " is not compatible to " |
| 34 | + + getClass().getName(), |
| 35 | + e); |
| 36 | + } |
| 37 | + } |
| 38 | + |
| 39 | + @Override |
| 40 | + public ReflectorIsolatedClassLoader getIsolatedClassLoader() { |
| 41 | + return isolatedClassLoader; |
| 42 | + } |
| 43 | + |
| 44 | + protected Object getOrCreateClassFinderForIsolatedClassLoader() throws ReflectiveOperationException { |
| 45 | + if (classFinder == null) { |
| 46 | + initClassFinder(); |
| 47 | + } |
| 48 | + return classFinder; |
| 49 | + } |
| 50 | + |
| 51 | + protected synchronized void initClassFinder() throws ReflectiveOperationException { |
| 52 | + if (classFinder == null) { |
| 53 | + final Class<?> classFinderImplClass = getIsolatedClassLoader().loadClass( |
| 54 | + ReflectionsClassFinder.class.getName()); |
| 55 | + classFinder = classFinderImplClass |
| 56 | + .getConstructor(ClassLoader.class, URL[].class) |
| 57 | + .newInstance( |
| 58 | + isolatedClassLoader, |
| 59 | + isolatedClassLoader.urlsToScan()); |
| 60 | + } |
| 61 | + } |
| 62 | + |
| 63 | + @Override |
| 64 | + public Mojo createIsolatedMojo( |
| 65 | + final FlowModeAbstractMojo sourceMojo, |
| 66 | + final Set<String> ignoredFields) |
| 67 | + throws Exception { |
| 68 | + |
| 69 | + final Class<?> targetMojoClass = getIsolatedClassLoader().loadClass(sourceMojo.getClass().getName()); |
| 70 | + final Object targetMojo = targetMojoClass.getConstructor().newInstance(); |
| 71 | + copyFields(sourceMojo, targetMojo, ignoredFields); |
| 72 | + |
| 73 | + ReflectTools.setJavaFieldValue( |
| 74 | + targetMojo, |
| 75 | + FlowModeAbstractMojo.CLASSFINDER_FIELD_NAME, |
| 76 | + getOrCreateClassFinderForIsolatedClassLoader()); |
| 77 | + |
| 78 | + return (Mojo) targetMojo; |
| 79 | + } |
| 80 | + |
| 81 | + protected void copyFields( |
| 82 | + final FlowModeAbstractMojo sourceMojo, |
| 83 | + final Object targetMojo, |
| 84 | + final Set<String> ignoredFields) |
| 85 | + throws IllegalAccessException, NoSuchFieldException { |
| 86 | + Class<?> sourceClass = sourceMojo.getClass(); |
| 87 | + Class<?> targetClass = targetMojo.getClass(); |
| 88 | + while (sourceClass != null && sourceClass != Object.class) { |
| 89 | + for (final Field sourceField : Arrays.stream(sourceClass.getDeclaredFields()) |
| 90 | + .filter(f -> !ignoredFields.contains(f.getName())) |
| 91 | + .toList()) { |
| 92 | + copyField(sourceMojo, targetMojo, sourceField, targetClass); |
| 93 | + } |
| 94 | + targetClass = targetClass.getSuperclass(); |
| 95 | + sourceClass = sourceClass.getSuperclass(); |
| 96 | + } |
| 97 | + } |
| 98 | + |
| 99 | + protected void copyField( |
| 100 | + final FlowModeAbstractMojo sourceMojo, |
| 101 | + final Object targetMojo, |
| 102 | + final Field sourceField, |
| 103 | + final Class<?> targetClass) |
| 104 | + throws IllegalAccessException, NoSuchFieldException { |
| 105 | + if (Modifier.isStatic(sourceField.getModifiers())) { |
| 106 | + return; |
| 107 | + } |
| 108 | + sourceField.setAccessible(true); |
| 109 | + final Object value = sourceField.get(sourceMojo); |
| 110 | + if (value == null) { |
| 111 | + return; |
| 112 | + } |
| 113 | + final Field targetField; |
| 114 | + try { |
| 115 | + targetField = targetClass.getDeclaredField(sourceField.getName()); |
| 116 | + } catch (final NoSuchFieldException ex) { |
| 117 | + // Should never happen, since the class definition should be the same |
| 118 | + final String message = "Field " + sourceField.getName() + " defined in " |
| 119 | + + sourceField.getDeclaringClass().getName() |
| 120 | + + " is missing in " + targetClass.getName(); |
| 121 | + sourceMojo.logError(message, ex); |
| 122 | + throw ex; |
| 123 | + } |
| 124 | + |
| 125 | + final Class<?> targetFieldType = targetField.getType(); |
| 126 | + if (!targetFieldType.isAssignableFrom(sourceField.getType())) { |
| 127 | + final String message = "Field " + targetFieldType.getName() + " in class " |
| 128 | + + targetClass.getName() + " of type " |
| 129 | + + targetFieldType.getName() |
| 130 | + + " is loaded from different class loaders." |
| 131 | + + " Source class loader: " |
| 132 | + + sourceField.getType().getClassLoader() |
| 133 | + + ", Target class loader: " |
| 134 | + + targetFieldType.getClassLoader() |
| 135 | + + ". This is likely a bug in the Vaadin Maven plugin." |
| 136 | + + " Please, report the error on the issue tracker."; |
| 137 | + sourceMojo.logError(message); |
| 138 | + throw new NoSuchFieldException(message); |
| 139 | + } |
| 140 | + targetField.setAccessible(true); |
| 141 | + targetField.set(targetMojo, value); |
| 142 | + } |
154 | 143 | }
|
0 commit comments