3131import static org .eclipse .lsp4mp .jdt .core .utils .JDTTypeUtils .getSourceMethod ;
3232import static org .eclipse .lsp4mp .jdt .core .utils .JDTTypeUtils .getSourceType ;
3333import static org .eclipse .lsp4mp .jdt .core .utils .JDTTypeUtils .isOptional ;
34- import static org .eclipse .lsp4mp .jdt .core .utils .JDTTypeUtils .isPrimitiveType ;
3534
3635import java .util .ArrayList ;
3736import java .util .Arrays ;
37+ import java .util .Collections ;
3838import java .util .HashSet ;
3939import java .util .List ;
4040import java .util .Set ;
@@ -111,17 +111,27 @@ private void processConfigMapping(IJavaElement javaElement, IAnnotation configMa
111111 return ;
112112 }
113113 // @ConfigMapping(prefix="server") case
114- List < IType > allInterfaces = new ArrayList <>( Arrays . asList ( findInterfaces ( configMappingType , monitor )));
115- allInterfaces . add ( 0 , configMappingType );
114+ // @ConfigMapping(prefix="server") case
115+ Set < IType > allInterfaces = findInterfaces ( configMappingType , monitor );
116116 for (IType configMappingInterface : allInterfaces ) {
117117 populateConfigObject (configMappingInterface , prefix , extensionName , new HashSet <>(),
118118 configMappingAnnotation , collector , monitor );
119119 }
120120 }
121121
122- private static IType [] findInterfaces (IType type , IProgressMonitor progressMonitor ) throws JavaModelException {
122+ private static Set <IType > findInterfaces (IType type , IProgressMonitor progressMonitor ) throws JavaModelException {
123+ // No reason to use a JDK interface to generate a config class? Primarily to fix the java.nio.file.Path case.
124+ // see https://github.com/smallrye/smallrye-config/blob/22635f24dc7634706867cc52e28d5bd82d15f54e/implementation/src/main/java/io/smallrye/config/ConfigMappingInterface.java#L782C9-L783C58
125+ if (type .getFullyQualifiedName () == null || type .getFullyQualifiedName ().startsWith ("java" )) {
126+ return Collections .emptySet ();
127+ }
128+ Set <IType > result = new HashSet <>();
129+ result .add (type );
130+
123131 ITypeHierarchy typeHierarchy = type .newSupertypeHierarchy (progressMonitor );
124- return typeHierarchy .getAllSuperInterfaces (type );
132+ IType [] allSuperInterfaces = typeHierarchy .getAllSuperInterfaces (type );
133+ result .addAll (Arrays .asList (allSuperInterfaces ));
134+ return result ;
125135 }
126136
127137 private void populateConfigObject (IType configMappingType , String prefixStr , String extensionName ,
@@ -156,22 +166,7 @@ private void populateConfigObject(IType configMappingType, String prefixStr, Str
156166 }
157167
158168 IType returnType = findType (method .getJavaProject (), resolvedTypeSignature );
159- boolean simpleType = isSimpleType (resolvedTypeSignature , returnType );
160- if (!simpleType ) {
161- if (returnType != null && !returnType .isInterface ()) {
162- // When type is not an interface, it requires Converters
163- // ex :
164- // interface Server {Log log; class Log {}}
165- // throw the error;
166- // java.lang.IllegalArgumentException: SRCFG00013: No Converter registered for
167- // class org.acme.Server2$Log
168- // at
169- // io.smallrye.config.SmallRyeConfig.requireConverter(SmallRyeConfig.java:466)
170- // at
171- // io.smallrye.config.ConfigMappingContext.getConverter(ConfigMappingContext.java:113)
172- continue ;
173- }
174- }
169+ boolean leafType = isLeafType (returnType );
175170
176171 String defaultValue = getWithDefault (method );
177172 String propertyName = getPropertyName (method , prefixStr , configMappingAnnotation );
@@ -190,27 +185,26 @@ private void populateConfigObject(IType configMappingType, String prefixStr, Str
190185 IType enclosedType = getEnclosedType (returnType , resolvedTypeSignature , method .getJavaProject ());
191186 super .updateHint (collector , enclosedType );
192187
193- if (!simpleType ) {
188+ if (!leafType ) {
194189 if (isMap (returnType , resolvedTypeSignature )) {
195190 // Map<String, String>
196191 propertyName += ".{*}" ;
197- simpleType = true ;
192+ leafType = true ;
198193 } else if (isCollection (returnType , resolvedTypeSignature )) {
199194 // List<String>, List<App>
200195 propertyName += "[*]" ; // Generate indexed property.
201- String [] typeArguments = org .eclipse .jdt .core .Signature
202- .getTypeArguments (returnTypeSignature );
196+ String [] typeArguments = org .eclipse .jdt .core .Signature .getTypeArguments (returnTypeSignature );
203197 if (typeArguments .length < 1 ) {
204198 continue ;
205199 }
206200 String genericTypeName = typeArguments [0 ];
207201 resolvedTypeSignature = JavaModelUtil .getResolvedTypeName (genericTypeName , configMappingType );
208202 returnType = findType (method .getJavaProject (), resolvedTypeSignature );
209- simpleType = isSimpleType ( resolvedTypeSignature , returnType );
203+ leafType = isLeafType ( returnType );
210204 }
211205 }
212206
213- if (simpleType ) {
207+ if (leafType ) {
214208 // String, int, etc
215209 ItemMetadata metadata = super .addItemMetadata (collector , propertyName , type , description ,
216210 sourceType , null , sourceMethod , defaultValue , extensionName , method .isBinary ());
@@ -224,8 +218,15 @@ private void populateConfigObject(IType configMappingType, String prefixStr, Str
224218 }
225219 }
226220
227- private boolean isSimpleType (String resolvedTypeSignature , IType returnType ) {
228- return returnType == null || isPrimitiveType (resolvedTypeSignature );
221+ /**
222+ * Returns true if the given return type should be treated as a leaf in the
223+ * configuration tree, i.e. it is null or not an interface, and therefore not
224+ * recursively visited.
225+ *
226+ * @throws JavaModelException
227+ */
228+ private static boolean isLeafType (IType returnType ) throws JavaModelException {
229+ return returnType == null || !returnType .isInterface ();
229230 }
230231
231232 private static boolean isMap (IType type , String typeName ) {
@@ -276,7 +277,7 @@ private static String convertName(IMember member, IAnnotation configMappingAnnot
276277 // public interface ServerVerbatimNamingStrategy
277278 // --> See https://quarkus.io/guides/config-mappings#namingstrategy
278279 NamingStrategy namingStrategy = getNamingStrategy (configMappingAnnotation );
279- if (namingStrategy != null ) {
280+ if (namingStrategy != null ) {
280281 switch (namingStrategy ) {
281282 case VERBATIM :
282283 // The method name is used as is to map the configuration property.
@@ -321,7 +322,7 @@ private static NamingStrategy getNamingStrategy(IAnnotation configMappingAnnotat
321322 }
322323 return null ;
323324 }
324-
325+
325326 /**
326327 * Returns the value of @WithDefault("a value") and null otherwise.
327328 *
0 commit comments