Skip to content

Commit ca2c4e7

Browse files
committed
Add record component registry and pool.
1 parent 87b6365 commit ca2c4e7

File tree

9 files changed

+696
-17
lines changed

9 files changed

+696
-17
lines changed

byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/DynamicType.java

Lines changed: 37 additions & 1 deletion
Large diffs are not rendered by default.

byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/scaffold/InstrumentedType.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1333,7 +1333,7 @@ public TypeList getNestMembers() {
13331333
/**
13341334
* {@inheritDoc}
13351335
*/
1336-
public RecordComponentList getRecordComponents() {
1336+
public RecordComponentList<RecordComponentDescription.InDefinedShape> getRecordComponents() {
13371337
return new RecordComponentList.ForTokens(this, recordComponentTokens);
13381338
}
13391339

Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
/*
2+
* Copyright 2014 - 2020 Rafael Winterhalter
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package net.bytebuddy.dynamic.scaffold;
17+
18+
import net.bytebuddy.build.HashCodeAndEqualsPlugin;
19+
import net.bytebuddy.description.type.RecordComponentDescription;
20+
import net.bytebuddy.description.type.TypeDescription;
21+
import net.bytebuddy.dynamic.Transformer;
22+
import net.bytebuddy.implementation.attribute.RecordComponentAttributeAppender;
23+
import net.bytebuddy.matcher.ElementMatcher;
24+
import net.bytebuddy.matcher.LatentMatcher;
25+
26+
import java.util.*;
27+
28+
/**
29+
* A record component registry represents an extendable collection of record components which are identified by their names that are mapped
30+
* to a given {@link RecordComponentAttributeAppender}. Record components
31+
* can be uniquely identified by their name for a given type since record components are never inherited.
32+
* <p>&nbsp;</p>
33+
* This registry is the counterpart of a {@link MethodRegistry}.
34+
* However, a record component registry is implemented simpler since it does not have to deal with complex signatures or
35+
* inheritance. For the sake of consistency, the record component registry follows however a similar pattern without introducing
36+
* unnecessary complexity.
37+
*/
38+
public interface RecordComponentRegistry {
39+
40+
/**
41+
* Prepends the given record component definition to this record component registry, i.e. this configuration is applied first.
42+
*
43+
* @param matcher The matcher to identify any record component that this definition concerns.
44+
* @param recordComponentAttributeAppenderFactory The record component attribute appender factory to apply on any matched record component.
45+
* @param transformer The record component transformer to apply to any matched record component.
46+
* @return An adapted version of this method registry.
47+
*/
48+
RecordComponentRegistry prepend(LatentMatcher<? super RecordComponentDescription> matcher,
49+
RecordComponentAttributeAppender.Factory recordComponentAttributeAppenderFactory,
50+
Transformer<RecordComponentDescription> transformer);
51+
52+
/**
53+
* Prepares the record component registry for a given instrumented type.
54+
*
55+
* @param instrumentedType The instrumented type.
56+
* @return A prepared record component registry.
57+
*/
58+
Compiled compile(TypeDescription instrumentedType);
59+
60+
/**
61+
* Represents a compiled record component registry.
62+
*/
63+
interface Compiled extends TypeWriter.RecordComponentPool {
64+
65+
/**
66+
* A no-op record component registry that does not register annotations for any record component.
67+
*/
68+
enum NoOp implements Compiled {
69+
70+
/**
71+
* The singleton instance.
72+
*/
73+
INSTANCE;
74+
75+
/**
76+
* {@inheritDoc}
77+
*/
78+
public Record target(RecordComponentDescription recordComponentDescription) {
79+
return new Record.ForImplicitRecordComponent(recordComponentDescription);
80+
}
81+
}
82+
}
83+
84+
/**
85+
* An immutable default implementation of a record component registry.
86+
*/
87+
@HashCodeAndEqualsPlugin.Enhance
88+
class Default implements RecordComponentRegistry {
89+
90+
/**
91+
* This registries entries.
92+
*/
93+
private final List<Entry> entries;
94+
95+
/**
96+
* Creates a new empty default record component registry.
97+
*/
98+
public Default() {
99+
this(Collections.<Entry>emptyList());
100+
}
101+
102+
/**
103+
* Creates a new default record component registry.
104+
*
105+
* @param entries The entries of the record component registry.
106+
*/
107+
private Default(List<Entry> entries) {
108+
this.entries = entries;
109+
}
110+
111+
/**
112+
* {@inheritDoc}
113+
*/
114+
public RecordComponentRegistry prepend(LatentMatcher<? super RecordComponentDescription> matcher,
115+
RecordComponentAttributeAppender.Factory recordComponentAttributeAppenderFactory,
116+
Transformer<RecordComponentDescription> transformer) {
117+
List<Entry> entries = new ArrayList<Entry>(this.entries.size() + 1);
118+
entries.add(new Entry(matcher, recordComponentAttributeAppenderFactory, transformer));
119+
entries.addAll(this.entries);
120+
return new Default(entries);
121+
}
122+
123+
/**
124+
* {@inheritDoc}
125+
*/
126+
public RecordComponentRegistry.Compiled compile(TypeDescription instrumentedType) {
127+
List<Compiled.Entry> entries = new ArrayList<Compiled.Entry>(this.entries.size());
128+
Map<RecordComponentAttributeAppender.Factory, RecordComponentAttributeAppender> recordComponentAttributeAppenders = new HashMap<RecordComponentAttributeAppender.Factory, RecordComponentAttributeAppender>();
129+
for (Entry entry : this.entries) {
130+
RecordComponentAttributeAppender recordComponentAttributeAppender = recordComponentAttributeAppenders.get(entry.getRecordComponentAttributeAppender());
131+
if (recordComponentAttributeAppender == null) {
132+
recordComponentAttributeAppender = entry.getRecordComponentAttributeAppender().make(instrumentedType);
133+
recordComponentAttributeAppenders.put(entry.getRecordComponentAttributeAppender(), recordComponentAttributeAppender);
134+
}
135+
entries.add(new Compiled.Entry(entry.resolve(instrumentedType), recordComponentAttributeAppender, entry.getTransformer()));
136+
}
137+
return new Compiled(instrumentedType, entries);
138+
}
139+
140+
/**
141+
* An entry of the default record component registry.
142+
*/
143+
@HashCodeAndEqualsPlugin.Enhance
144+
protected static class Entry implements LatentMatcher<RecordComponentDescription> {
145+
146+
/**
147+
* The matcher to identify any record component that this definition concerns.
148+
*/
149+
private final LatentMatcher<? super RecordComponentDescription> matcher;
150+
151+
/**
152+
* The record component attribute appender factory to apply on any matched record component.
153+
*/
154+
private final RecordComponentAttributeAppender.Factory recordComponentAttributeAppender;
155+
156+
/**
157+
* The record component transformer to apply to any matched record component.
158+
*/
159+
private final Transformer<RecordComponentDescription> transformer;
160+
161+
/**
162+
* Creates a new entry.
163+
*
164+
* @param matcher The matcher to identify any record component that this definition concerns.
165+
* @param recordComponentAttributeAppender The record component attribute appender factory to apply on any matched record component.
166+
* @param transformer The record component transformer to apply to any matched record component.
167+
*/
168+
protected Entry(LatentMatcher<? super RecordComponentDescription> matcher,
169+
RecordComponentAttributeAppender.Factory recordComponentAttributeAppender,
170+
Transformer<RecordComponentDescription> transformer) {
171+
this.matcher = matcher;
172+
this.recordComponentAttributeAppender = recordComponentAttributeAppender;
173+
this.transformer = transformer;
174+
}
175+
176+
/**
177+
* Returns the record component attribute appender factory to apply on any matched record component.
178+
*
179+
* @return The record component attribute appender factory to apply on any matched record component.
180+
*/
181+
protected RecordComponentAttributeAppender.Factory getRecordComponentAttributeAppender() {
182+
return recordComponentAttributeAppender;
183+
}
184+
185+
/**
186+
* Returns the record component transformer to apply to any matched record component.
187+
*
188+
* @return The record component transformer to apply to any matched record component.
189+
*/
190+
protected Transformer<RecordComponentDescription> getTransformer() {
191+
return transformer;
192+
}
193+
194+
/**
195+
* {@inheritDoc}
196+
*/
197+
public ElementMatcher<? super RecordComponentDescription> resolve(TypeDescription typeDescription) {
198+
return matcher.resolve(typeDescription);
199+
}
200+
}
201+
202+
/**
203+
* A compiled default record component registry.
204+
*/
205+
@HashCodeAndEqualsPlugin.Enhance
206+
protected static class Compiled implements RecordComponentRegistry.Compiled {
207+
208+
/**
209+
* The instrumented type for which this registry was compiled for.
210+
*/
211+
private final TypeDescription instrumentedType;
212+
213+
/**
214+
* The entries of this compiled record component registry.
215+
*/
216+
private final List<Entry> entries;
217+
218+
/**
219+
* Creates a new compiled record component registry.
220+
*
221+
* @param instrumentedType The instrumented type for which this registry was compiled for.
222+
* @param entries The entries of this compiled record component registry.
223+
*/
224+
protected Compiled(TypeDescription instrumentedType, List<Entry> entries) {
225+
this.instrumentedType = instrumentedType;
226+
this.entries = entries;
227+
}
228+
229+
/**
230+
* {@inheritDoc}
231+
*/
232+
public Record target(RecordComponentDescription recordComponentDescription) {
233+
for (Entry entry : entries) {
234+
if (entry.matches(recordComponentDescription)) {
235+
return entry.bind(instrumentedType, recordComponentDescription);
236+
}
237+
}
238+
return new Record.ForImplicitRecordComponent(recordComponentDescription);
239+
}
240+
241+
/**
242+
* An entry of a compiled record component registry.
243+
*/
244+
@HashCodeAndEqualsPlugin.Enhance
245+
protected static class Entry implements ElementMatcher<RecordComponentDescription> {
246+
247+
/**
248+
* The matcher to identify any record component that this definition concerns.
249+
*/
250+
private final ElementMatcher<? super RecordComponentDescription> matcher;
251+
252+
/**
253+
* The record component attribute appender to apply on any matched record component.
254+
*/
255+
private final RecordComponentAttributeAppender recordComponentAttributeAppender;
256+
257+
/**
258+
* The record component transformer to apply to any matched record component.
259+
*/
260+
private final Transformer<RecordComponentDescription> transformer;
261+
262+
/**
263+
* Creates a new entry.
264+
*
265+
* @param matcher The matcher to identify any record component that this definition concerns.
266+
* @param recordComponentAttributeAppender The record component attribute appender to apply on any matched record component.
267+
* @param transformer The record component transformer to apply to any matched record component.
268+
*/
269+
protected Entry(ElementMatcher<? super RecordComponentDescription> matcher,
270+
RecordComponentAttributeAppender recordComponentAttributeAppender,
271+
Transformer<RecordComponentDescription> transformer) {
272+
this.matcher = matcher;
273+
this.recordComponentAttributeAppender = recordComponentAttributeAppender;
274+
this.transformer = transformer;
275+
}
276+
277+
/**
278+
* Binds this entry to the provided record component description.
279+
*
280+
* @param instrumentedType The instrumented type for which this entry applies.
281+
* @param recordComponentDescription The record component description to be bound to this entry.
282+
* @return A record representing the binding of this entry to the provided record component.
283+
*/
284+
protected Record bind(TypeDescription instrumentedType, RecordComponentDescription recordComponentDescription) {
285+
return new Record.ForExplicitRecordComponent(recordComponentAttributeAppender, transformer.transform(instrumentedType, recordComponentDescription));
286+
}
287+
288+
/**
289+
* {@inheritDoc}
290+
*/
291+
public boolean matches(RecordComponentDescription target) {
292+
return matcher.matches(target);
293+
}
294+
}
295+
}
296+
}
297+
}

0 commit comments

Comments
 (0)