11package dev .lukebemish .codecextras .structured .reflective ;
22
3+ import com .google .common .base .Suppliers ;
34import dev .lukebemish .codecextras .structured .Structure ;
45import dev .lukebemish .codecextras .utility .LayeredServiceLoader ;
56import java .lang .reflect .ParameterizedType ;
67import java .lang .reflect .Type ;
78import java .util .ArrayList ;
9+ import java .util .HashMap ;
810import java .util .IdentityHashMap ;
911import java .util .List ;
1012import java .util .Map ;
1113import java .util .Objects ;
1214import java .util .function .Function ;
15+ import java .util .function .Supplier ;
1316
1417public interface ReflectiveStructureCreator {
1518 Map <Class <?>, Creator > creators ();
@@ -88,8 +91,10 @@ public Instance build() {
8891
8992 private static final LayeredServiceLoader <ReflectiveStructureCreator > SERVICE_LOADER = LayeredServiceLoader .of (ReflectiveStructureCreator .class );
9093
94+ private final Map <Type , Creator > cachedCreators = new HashMap <>();
95+
9196 @ SuppressWarnings ("unchecked" )
92- public <T > Structure <T > create (Class <T > clazz ) {
97+ public synchronized <T > Structure <T > create (Class <T > clazz ) {
9398 var caller = StackWalker .getInstance (StackWalker .Option .RETAIN_CLASS_REFERENCE ).getCallerClass ();
9499 List <ReflectiveStructureCreator > services = LayeredServiceLoader .unique (SERVICE_LOADER .at (ReflectiveStructureCreator .class ), SERVICE_LOADER .at (clazz ), SERVICE_LOADER .at (caller ));
95100 Map <Class <?>, Creator > creatorsMap = new IdentityHashMap <>();
@@ -106,7 +111,10 @@ public <T> Structure<T> create(Class<T> clazz) {
106111 flexibleCreatorsList .addAll (this .flexibleCreators );
107112
108113 flexibleCreatorsList .sort ((a , b ) -> Integer .compare (b .priority (), a .priority ()));
109- var creator = forType (clazz , creatorsMap , parameterizedCreatorsMap , flexibleCreatorsList );
114+
115+ var recursionCache = new HashMap <Type , Structure <?>>();
116+
117+ var creator = forType (cachedCreators , recursionCache , clazz , creatorsMap , parameterizedCreatorsMap , flexibleCreatorsList );
110118 return (Structure <T >) creator .create ();
111119 }
112120 }
@@ -115,60 +123,79 @@ static <T> Structure<T> create(Class<T> clazz) {
115123 return Instance .builder ().build ().create (clazz );
116124 }
117125
118- private static Creator forType (Type type , Map <Class <?>, Creator > creatorsMap , Map <Class <?>, ParameterizedCreator > parameterizedCreatorsMap , List <FlexibleCreator > flexibleCreators ) {
119- Class <?> rawType = null ;
120- TypedCreator [] parameterCreators = null ;
121- if (type instanceof ParameterizedType parameterizedType ) {
122- if (parameterizedType .getRawType () instanceof Class <?> clazz ) {
123- rawType = clazz ;
124- var parameters = parameterizedType .getActualTypeArguments ();
125- parameterCreators = new TypedCreator [parameters .length ];
126- if (parameterizedCreatorsMap .containsKey (clazz )) {
127- for (int i = 0 ; i < parameters .length ; i ++) {
128- var creator = forType (parameters [i ], creatorsMap , parameterizedCreatorsMap , flexibleCreators );
129- var parameterType = parameters [i ];
130- parameterCreators [i ] = new TypedCreator () {
131- @ Override
132- public Structure <?> create () {
133- return creator .create ();
134- }
135-
136- @ Override
137- public Type type () {
138- return parameterType ;
139- }
140-
141- @ Override
142- public Class <?> rawType () {
143- if (parameterType instanceof Class <?> clazz ) {
144- return clazz ;
145- } else if (parameterType instanceof ParameterizedType parameterizedType ) {
146- return (Class <?>) parameterizedType .getRawType ();
147- } else {
148- throw new IllegalArgumentException ("Unknown type: " + type );
149- }
126+ private static Creator forType (Map <Type , Creator > cachedCreators , Map <Type , Structure <?>> recursionCache , Type type , Map <Class <?>, Creator > creatorsMap , Map <Class <?>, ParameterizedCreator > parameterizedCreatorsMap , List <FlexibleCreator > flexibleCreators ) {
127+ if (cachedCreators .containsKey (type )) {
128+ return cachedCreators .get (type );
129+ }
130+ if (recursionCache .containsKey (type )) {
131+ var value = recursionCache .get (type );
132+ return () -> value ;
133+ }
134+ @ SuppressWarnings ({"rawtypes" , "unchecked" }) Supplier <Structure <?>> full = Suppliers .memoize (() -> Structure .recursive ((Function ) (Function <Structure , Structure >) (Structure itself ) -> {
135+ recursionCache .put (type , itself );
136+
137+ Supplier <Creator > creatorSupplier = () -> {
138+ Class <?> rawType = null ;
139+ TypedCreator [] parameterCreators = null ;
140+ if (type instanceof ParameterizedType parameterizedType ) {
141+ if (parameterizedType .getRawType () instanceof Class <?> clazz ) {
142+ rawType = clazz ;
143+ var parameters = parameterizedType .getActualTypeArguments ();
144+ parameterCreators = new TypedCreator [parameters .length ];
145+ if (parameterizedCreatorsMap .containsKey (clazz )) {
146+ for (int i = 0 ; i < parameters .length ; i ++) {
147+ var creator = forType (cachedCreators , recursionCache , parameters [i ], creatorsMap , parameterizedCreatorsMap , flexibleCreators );
148+ var parameterType = parameters [i ];
149+ parameterCreators [i ] = new TypedCreator () {
150+ @ Override
151+ public Structure <?> create () {
152+ return creator .create ();
153+ }
154+
155+ @ Override
156+ public Type type () {
157+ return parameterType ;
158+ }
159+
160+ @ Override
161+ public Class <?> rawType () {
162+ if (parameterType instanceof Class <?> clazz ) {
163+ return clazz ;
164+ } else if (parameterType instanceof ParameterizedType parameterizedType ) {
165+ return (Class <?>) parameterizedType .getRawType ();
166+ } else {
167+ throw new IllegalArgumentException ("Unknown type: " + type );
168+ }
169+ }
170+ };
150171 }
151- };
172+ return parameterizedCreatorsMap .get (clazz ).creator (parameterCreators );
173+ }
152174 }
153- return parameterizedCreatorsMap .get (clazz ).creator (parameterCreators );
175+ } else if (type instanceof Class <?> clazz ) {
176+ rawType = clazz ;
177+ parameterCreators = new TypedCreator [0 ];
178+ var foundCreator = creatorsMap .get (clazz );
179+ if (foundCreator != null ) {
180+ return foundCreator ;
181+ }
182+ } else {
183+ throw new IllegalArgumentException ("Unknown type: " + type );
154184 }
155- }
156- } else if (type instanceof Class <?> clazz ) {
157- rawType = clazz ;
158- parameterCreators = new TypedCreator [0 ];
159- var foundCreator = creatorsMap .get (clazz );
160- if (foundCreator != null ) {
161- return foundCreator ;
162- }
163- } else {
164- throw new IllegalArgumentException ("Unknown type: " + type );
165- }
166185
167- for (var flexibleCreator : flexibleCreators ) {
168- if (flexibleCreator .supports (Objects .requireNonNull (rawType ), parameterCreators )) {
169- return flexibleCreator .creator (rawType , parameterCreators , type1 -> forType (type1 , creatorsMap , parameterizedCreatorsMap , flexibleCreators ).create ());
170- }
171- }
172- throw new IllegalArgumentException ("No creator found for type: " + type );
186+ for (var flexibleCreator : flexibleCreators ) {
187+ if (flexibleCreator .supports (Objects .requireNonNull (rawType ), parameterCreators )) {
188+ return flexibleCreator .creator (rawType , parameterCreators , type1 -> forType (cachedCreators , recursionCache , type1 , creatorsMap , parameterizedCreatorsMap , flexibleCreators ).create ());
189+ }
190+ }
191+ throw new IllegalArgumentException ("No creator found for type: " + type );
192+ };
193+ var creator = creatorSupplier .get ();
194+ var structure = creator .create ();
195+ recursionCache .remove (type );
196+ return structure ;
197+ }));
198+ cachedCreators .put (type , full ::get );
199+ return full ::get ;
173200 }
174201}
0 commit comments