4040import org .springframework .graphql .data .method .annotation .support .HandlerDataFetcherExceptionResolver ;
4141import org .springframework .graphql .execution .ErrorType ;
4242import org .springframework .lang .Nullable ;
43- import org .springframework .util .Assert ;
4443
4544/**
4645 * DataFetcher that handles the "_entities" query by invoking
@@ -93,12 +92,11 @@ public Mono<DataFetcherResult<List<Object>>> get(DataFetchingEnvironment env) {
9392 }
9493 else {
9594 if (!batchedTypes .contains (type )) {
96- EntityBatchDelegate delegate = new EntityBatchDelegate (env , representations , handlerMethod , type );
97- monoList .add (delegate .invokeEntityBatchMethod ());
95+ monoList .add (invokeEntitiesMethod (env , handlerMethod , representations , type ));
9896 batchedTypes .add (type );
9997 }
10098 else {
101- // Covered by batch invocation , but zip needs a value (to be replaced by batch results)
99+ // Already covered , but zip needs a value (to be replaced by batch results)
102100 monoList .add (Mono .just (Collections .emptyMap ()));
103101 }
104102 }
@@ -107,11 +105,48 @@ public Mono<DataFetcherResult<List<Object>>> get(DataFetchingEnvironment env) {
107105 }
108106
109107 private Mono <Object > invokeEntityMethod (
110- DataFetchingEnvironment env , EntityHandlerMethod handlerMethod , Map <String , Object > map , int index ) {
108+ DataFetchingEnvironment environment , EntityHandlerMethod handlerMethod ,
109+ Map <String , Object > representation , int index ) {
111110
112- return handlerMethod .getEntity (env , map )
113- .switchIfEmpty (Mono .error (new RepresentationNotResolvedException (map , handlerMethod )))
114- .onErrorResume ((ex ) -> resolveException (ex , env , handlerMethod , index ));
111+ return handlerMethod .getEntity (environment , representation )
112+ .switchIfEmpty (Mono .error (new RepresentationNotResolvedException (representation , handlerMethod )))
113+ .onErrorResume ((ex ) -> resolveException (ex , environment , handlerMethod , index ));
114+ }
115+
116+ private Mono <EntitiesResultContainer > invokeEntitiesMethod (
117+ DataFetchingEnvironment environment , EntityHandlerMethod handlerMethod ,
118+ List <Map <String , Object >> representations , String type ) {
119+
120+ List <Map <String , Object >> typeRepresentations = new ArrayList <>();
121+ List <Integer > originalIndexes = new ArrayList <>();
122+
123+ for (int i = 0 ; i < representations .size (); i ++) {
124+ Map <String , Object > map = representations .get (i );
125+ if (type .equals (map .get ("__typename" ))) {
126+ typeRepresentations .add (map );
127+ originalIndexes .add (i );
128+ }
129+ }
130+
131+ return handlerMethod .getEntities (environment , typeRepresentations )
132+ .mapNotNull ((result ) -> (((List <?>) result ).isEmpty ()) ? null : result )
133+ .switchIfEmpty (Mono .defer (() -> {
134+ List <Mono <?>> exceptions = new ArrayList <>(originalIndexes .size ());
135+ for (int i = 0 ; i < originalIndexes .size (); i ++) {
136+ exceptions .add (resolveException (
137+ new RepresentationNotResolvedException (typeRepresentations .get (i ), handlerMethod ),
138+ environment , handlerMethod , originalIndexes .get (i )));
139+ }
140+ return Mono .zip (exceptions , Arrays ::asList );
141+ }))
142+ .onErrorResume ((ex ) -> {
143+ List <Mono <?>> list = new ArrayList <>();
144+ for (Integer index : originalIndexes ) {
145+ list .add (resolveException (ex , environment , handlerMethod , index ));
146+ }
147+ return Mono .zip (list , Arrays ::asList );
148+ })
149+ .map ((result ) -> new EntitiesResultContainer ((List <?>) result , originalIndexes ));
115150 }
116151
117152 private Mono <ErrorContainer > resolveException (
@@ -141,8 +176,8 @@ private static DataFetcherResult<List<Object>> toDataFetcherResult(List<Object>
141176 List <GraphQLError > errors = new ArrayList <>();
142177 for (int i = 0 ; i < entities .size (); i ++) {
143178 Object entity = entities .get (i );
144- if (entity instanceof EntityBatchDelegate delegate ) {
145- delegate . processResults (entities , errors );
179+ if (entity instanceof EntitiesResultContainer resultHandler ) {
180+ resultHandler . applyResults (entities , errors );
146181 }
147182 if (entity instanceof ErrorContainer errorContainer ) {
148183 errors .addAll (errorContainer .errors ());
@@ -153,77 +188,6 @@ private static DataFetcherResult<List<Object>> toDataFetcherResult(List<Object>
153188 }
154189
155190
156- private class EntityBatchDelegate {
157-
158- private final DataFetchingEnvironment environment ;
159-
160- private final EntityHandlerMethod handlerMethod ;
161-
162- private final List <Map <String , Object >> filteredRepresentations = new ArrayList <>();
163-
164- private final List <Integer > indexes = new ArrayList <>();
165-
166- @ Nullable
167- private List <?> resultList ;
168-
169- EntityBatchDelegate (
170- DataFetchingEnvironment env , List <Map <String , Object >> allRepresentations ,
171- EntityHandlerMethod handlerMethod , String type ) {
172-
173- this .environment = env ;
174- this .handlerMethod = handlerMethod ;
175- for (int i = 0 ; i < allRepresentations .size (); i ++) {
176- Map <String , Object > map = allRepresentations .get (i );
177- if (type .equals (map .get ("__typename" ))) {
178- this .filteredRepresentations .add (map );
179- this .indexes .add (i );
180- }
181- }
182- }
183-
184- Mono <Object > invokeEntityBatchMethod () {
185- return this .handlerMethod .getEntities (this .environment , this .filteredRepresentations )
186- .mapNotNull ((result ) -> (((List <?>) result ).isEmpty ()) ? null : result )
187- .switchIfEmpty (Mono .defer (this ::handleEmptyResult ))
188- .onErrorResume (this ::handleErrorResult )
189- .map ((result ) -> {
190- this .resultList = (List <?>) result ;
191- return this ;
192- });
193- }
194-
195- Mono <Object > handleEmptyResult () {
196- List <Mono <?>> exceptions = new ArrayList <>(this .indexes .size ());
197- for (int i = 0 ; i < this .indexes .size (); i ++) {
198- Map <String , Object > map = this .filteredRepresentations .get (i );
199- Exception ex = new RepresentationNotResolvedException (map , this .handlerMethod );
200- exceptions .add (resolveException (ex , this .environment , this .handlerMethod , this .indexes .get (i )));
201- }
202- return Mono .zip (exceptions , Arrays ::asList );
203- }
204-
205- Mono <List <Object >> handleErrorResult (Throwable ex ) {
206- List <Mono <?>> list = new ArrayList <>();
207- for (Integer index : this .indexes ) {
208- list .add (resolveException (ex , this .environment , this .handlerMethod , index ));
209- }
210- return Mono .zip (list , Arrays ::asList );
211- }
212-
213- void processResults (List <Object > entities , List <GraphQLError > errors ) {
214- Assert .state (this .resultList != null , "Expected resultList" );
215- for (int i = 0 ; i < this .resultList .size (); i ++) {
216- Object entity = this .resultList .get (i );
217- if (entity instanceof ErrorContainer errorContainer ) {
218- errors .addAll (errorContainer .errors ());
219- entity = null ;
220- }
221- entities .set (this .indexes .get (i ), entity );
222- }
223- }
224- }
225-
226-
227191 private static class IndexedDataFetchingEnvironment extends DelegatingDataFetchingEnvironment {
228192
229193 private final ExecutionStepInfo executionStepInfo ;
@@ -242,6 +206,24 @@ public ExecutionStepInfo getExecutionStepInfo() {
242206 }
243207
244208
209+ private record EntitiesResultContainer (List <?> results , List <Integer > originalIndexes ) {
210+
211+ public void applyResults (List <Object > entities , List <GraphQLError > errors ) {
212+ for (int i = 0 ; i < this .results .size (); i ++) {
213+ Object result = this .results .get (i );
214+ Integer index = this .originalIndexes .get (i );
215+ if (result instanceof ErrorContainer container ) {
216+ errors .addAll (container .errors ());
217+ entities .set (index , null );
218+ }
219+ else {
220+ entities .set (index , result );
221+ }
222+ }
223+ }
224+ }
225+
226+
245227 private record ErrorContainer (List <GraphQLError > errors ) {
246228
247229 ErrorContainer (GraphQLError error ) {
0 commit comments