66
77import java .util .ArrayList ;
88import java .util .Collections ;
9+ import java .util .LinkedHashSet ;
910import java .util .List ;
1011import java .util .Map ;
12+ import java .util .Set ;
1113import java .util .concurrent .ConcurrentHashMap ;
14+ import java .util .function .Predicate ;
1215
1316import org .hibernate .models .UnknownClassException ;
17+ import org .hibernate .models .internal .util .CollectionHelper ;
1418import org .hibernate .models .spi .ClassDetails ;
1519import org .hibernate .models .spi .ModelsContext ;
20+ import org .hibernate .models .spi .TypeDetails ;
1621
1722import static org .hibernate .models .spi .ClassDetails .CLASS_CLASS_DETAILS ;
1823import static org .hibernate .models .spi .ClassDetails .OBJECT_CLASS_DETAILS ;
@@ -30,18 +35,22 @@ public abstract class AbstractClassDetailsRegistry implements MutableClassDetail
3035 protected final Map <String , ClassDetails > classDetailsMap ;
3136
3237 // subtype per type
33- protected final Map <String , List <ClassDetails >> subTypeClassDetailsMap ;
38+ protected final Map <String , Set <ClassDetails >> directSubTypeMap ;
39+ // implementor by interface
40+ protected final Map <String , Set <ClassDetails >> directImplementorMap ;
3441
3542 protected AbstractClassDetailsRegistry (ModelsContext context ) {
36- this ( new ConcurrentHashMap <>(), new ConcurrentHashMap <>(), context );
43+ this ( new ConcurrentHashMap <>(), new ConcurrentHashMap <>(), new ConcurrentHashMap <>(), context );
3744 }
3845
3946 protected AbstractClassDetailsRegistry (
4047 Map <String , ClassDetails > classDetailsMap ,
41- Map <String , List <ClassDetails >> subTypeClassDetailsMap ,
48+ Map <String , Set <ClassDetails >> directSubTypeMap ,
49+ Map <String , Set <ClassDetails >> directImplementorMap ,
4250 ModelsContext context ) {
4351 this .classDetailsMap = classDetailsMap ;
44- this .subTypeClassDetailsMap = subTypeClassDetailsMap ;
52+ this .directSubTypeMap = directSubTypeMap ;
53+ this .directImplementorMap = directImplementorMap ;
4554 this .context = context ;
4655
4756 classDetailsMap .put ( CLASS_CLASS_DETAILS .getName (), CLASS_CLASS_DETAILS );
@@ -51,13 +60,22 @@ protected AbstractClassDetailsRegistry(
5160 }
5261
5362 @ Override
54- public List <ClassDetails > getDirectSubTypes (String superTypeName ) {
55- return subTypeClassDetailsMap .get ( superTypeName );
63+ public List <ClassDetails > getDirectSubTypes (String typeName ) {
64+ final Set <ClassDetails > directSubtypes = getDirectSubtypes ( typeName );
65+ return CollectionHelper .isNotEmpty ( directSubtypes )
66+ ? new ArrayList <>( directSubtypes )
67+ : List .of ();
5668 }
5769
5870 @ Override
59- public void forEachDirectSubType (String superTypeName , ClassDetailsConsumer consumer ) {
60- final List <ClassDetails > directSubTypes = getDirectSubTypes ( superTypeName );
71+ public Set <ClassDetails > getDirectSubtypes (String typeName ) {
72+ final Set <ClassDetails > directSubtypes = directSubTypeMap .get ( typeName );
73+ return directSubtypes != null ? directSubtypes : Set .of ();
74+ }
75+
76+ @ Override
77+ public void forEachDirectSubtype (String typeName , ClassDetailsConsumer consumer ) {
78+ final List <ClassDetails > directSubTypes = getDirectSubTypes ( typeName );
6179 if ( directSubTypes == null ) {
6280 return ;
6381 }
@@ -66,6 +84,85 @@ public void forEachDirectSubType(String superTypeName, ClassDetailsConsumer cons
6684 }
6785 }
6886
87+ @ Override
88+ public Set <ClassDetails > getDirectImplementors (String interfaceName ) {
89+ final Set <ClassDetails > implementors = directImplementorMap .get ( interfaceName );
90+ return implementors != null ? implementors : Set .of ();
91+ }
92+
93+ @ Override
94+ public void forEachDirectImplementor (String interfaceName , ClassDetailsConsumer consumer ) {
95+ final Set <ClassDetails > directImplementors = getDirectImplementors ( interfaceName );
96+ if ( directImplementors != null ) {
97+ directImplementors .forEach ( consumer ::consume );
98+ }
99+ }
100+
101+ @ Override
102+ public Set <ClassDetails > findConcreteTypes (String base , boolean includeBase ) {
103+ final Set <ClassDetails > result = new LinkedHashSet <>();
104+ walkImplementors ( base , includeBase , classDetails -> {
105+ if ( !classDetails .isAbstract () && !classDetails .isInterface () ) {
106+ result .add ( classDetails );
107+ }
108+
109+ });
110+ return result ;
111+ }
112+
113+ @ Override
114+ public Set <ClassDetails > collectImplementors (String base , boolean includeBase , Predicate <ClassDetails > exclusions ) {
115+ final Set <ClassDetails > result = new LinkedHashSet <>();
116+ walkImplementors ( base , includeBase , classDetails -> {
117+ if ( exclusions == null || !exclusions .test ( classDetails ) ) {
118+ result .add ( classDetails );
119+ }
120+ } );
121+ return result ;
122+ }
123+
124+ @ Override
125+ public void walkImplementors (String base , boolean includeBase , ClassDetailsConsumer consumer ) {
126+ if ( includeBase ) {
127+ final ClassDetails baseDetails = resolveClassDetails ( base );
128+ consumer .consume ( baseDetails );
129+ }
130+
131+ forEachDirectSubtype ( base , (subType ) -> {
132+ consumer .consume ( subType );
133+ walkSubtypes ( subType , consumer );
134+ } );
135+
136+ forEachDirectImplementor ( base , (implementor ) -> {
137+ consumer .consume ( implementor );
138+ walkInterfaceImplementors ( implementor , consumer );
139+ } );
140+ }
141+
142+ private void walkSubtypes (ClassDetails base , ClassDetailsConsumer consumer ) {
143+ forEachDirectSubtype ( base .getName (), (subType ) -> {
144+ consumer .consume ( subType );
145+ walkSubtypes ( subType , consumer );
146+ } );
147+ }
148+
149+ private void walkInterfaceImplementors (ClassDetails implementor , ClassDetailsConsumer consumer ) {
150+ if ( implementor .isInterface () ) {
151+ // the direct interface implementor is itself an interface...
152+ forEachDirectImplementor ( implementor .getName (), (implementorImplementor ) -> {
153+ consumer .consume ( implementorImplementor );
154+ walkInterfaceImplementors ( implementorImplementor , consumer );
155+ } );
156+ }
157+ else {
158+ // the direct interface implementor is itself a class...
159+ forEachDirectSubtype ( implementor .getName (), (subtype ) -> {
160+ consumer .consume ( subtype );
161+ walkSubtypes ( subtype , consumer );
162+ } );
163+ }
164+ }
165+
69166 @ Override
70167 public ClassDetails findClassDetails (String name ) {
71168 return classDetailsMap .get ( name );
@@ -119,14 +216,25 @@ public void addClassDetails(String name, ClassDetails classDetails) {
119216 classDetailsMap .put ( name , classDetails );
120217
121218 if ( classDetails .getSuperClass () != null ) {
122- List <ClassDetails > subTypes = subTypeClassDetailsMap .get ( classDetails .getSuperClass ().getName () );
219+ Set <ClassDetails > subTypes = directSubTypeMap .get ( classDetails .getSuperClass ().getName () );
123220 //noinspection Java8MapApi
124221 if ( subTypes == null ) {
125- subTypes = new ArrayList <>();
126- subTypeClassDetailsMap .put ( classDetails .getSuperClass ().getName (), subTypes );
222+ subTypes = new LinkedHashSet <>();
223+ directSubTypeMap .put ( classDetails .getSuperClass ().getName (), subTypes );
127224 }
128225 subTypes .add ( classDetails );
129226 }
227+
228+ final List <TypeDetails > implementedInterfaces = classDetails .getImplementedInterfaces ();
229+ if ( implementedInterfaces != null ) {
230+ implementedInterfaces .forEach ( (implementedInterface ) -> {
231+ final Set <ClassDetails > directImplementors = directImplementorMap .computeIfAbsent (
232+ implementedInterface .getName (),
233+ (interfaceName ) -> new LinkedHashSet <>()
234+ );
235+ directImplementors .add ( classDetails );
236+ } );
237+ }
130238 }
131239
132240 @ Override
@@ -172,7 +280,11 @@ public Map<String, ClassDetails> getClassDetailsMap() {
172280 return Collections .unmodifiableMap ( classDetailsMap );
173281 }
174282
175- public Map <String , List <ClassDetails >> getSubTypeClassDetailsMap () {
176- return Collections .unmodifiableMap ( subTypeClassDetailsMap );
283+ public Map <String , Set <ClassDetails >> getDirectSubTypeMap () {
284+ return Collections .unmodifiableMap ( directSubTypeMap );
285+ }
286+
287+ public Map <String , Set <ClassDetails >> getDirectImplementorMap () {
288+ return Collections .unmodifiableMap ( directImplementorMap );
177289 }
178290}
0 commit comments