Repository: avaje/avaje-inject
Pull request #548 (2024-04-20 01:56:42)

Qualifiers preserve their case (no longer forced lower case) for BeanEntry and @QualifierMap keys (but still using case insensitive matching for wiring)
Idk about this one, while I do think it's only natural that qualifiers be case sensitive, this can break a lot of stuff

----
**_Edit:_**
- So qualifier names / keys in a `@QualifierMap` `Map<String,T>` will preserve their case (no longer forced toLowerCase)
- Qualifier names returned by BeanEntry.qualifierName() also preserve their case  (no longer forced toLowerCase)

The wiring will still be case insensitive such that `@Named("red")` and `@Red` are both matched the same via equalsIgnoreCase being used internally.

rbygrave: > only natural that qualifiers be case sensitive, this can break a lot of stuff

For myself I see it more that avaje-inject can keep the original case but use case-insensitive matching. I think that is the more realistic approach, with the view that it is a breaking change for `@QualifiedMap Map<String, T>` with the keys now keeping their original case (rather than all forced toLowerCase).

SentryMan: > For myself I see it more that avaje-inject can keep the original case but use case-insensitive matching.

I'm fine with this then

rob-bygrave: > I'm fine with this then

Cool.

I think this is an improvement in that the qualifier map keys being forced to all lower case is kind of odd or unexpected. Also preserving the case of the qualifiers gives people a better chance of doing something like an EnumMap.

Patch:
diff --git a/inject-generator/src/main/java/io/avaje/inject/generator/TypeAnnotationReader.java b/inject-generator/src/main/java/io/avaje/inject/generator/TypeAnnotationReader.java
index 1109700c..23e1fa43 100644
--- a/inject-generator/src/main/java/io/avaje/inject/generator/TypeAnnotationReader.java
+++ b/inject-generator/src/main/java/io/avaje/inject/generator/TypeAnnotationReader.java
@@ -36,8 +36,7 @@ final class TypeAnnotationReader {
         var shortName = Util.shortName(annotationType.toString());
         qualifierName = AnnotationCopier.toSimpleAnnotationString(annotationMirror)
           .replaceFirst(annotationType.toString(), shortName)
-          .replace("\"", "\\\"")
-          .toLowerCase();
+          .replace("\"", "\\\"");
 
       } else if (annType.indexOf('.') == -1) {
         logWarn("skip when no package on annotation " + annType);
diff --git a/inject-generator/src/main/java/io/avaje/inject/generator/TypeExtendsReader.java b/inject-generator/src/main/java/io/avaje/inject/generator/TypeExtendsReader.java
index 19a71109..711fab99 100644
--- a/inject-generator/src/main/java/io/avaje/inject/generator/TypeExtendsReader.java
+++ b/inject-generator/src/main/java/io/avaje/inject/generator/TypeExtendsReader.java
@@ -152,7 +152,7 @@ final class TypeExtendsReader {
         final String baseName = baseType.getSimpleName().toString();
         final String superName = superElement.getSimpleName().toString();
         if (baseName.endsWith(superName)) {
-          qualifierName = baseName.substring(0, baseName.length() - superName.length()).toLowerCase();
+          qualifierName = baseName.substring(0, baseName.length() - superName.length());
         }
       }
       addSuperType(superElement, superMirror, proxyBean);
@@ -226,7 +226,7 @@ final class TypeExtendsReader {
         final String iShortName = Util.shortName(mainType);
         if (beanSimpleName.endsWith(iShortName)) {
           // derived qualifier name based on prefix to interface short name
-          qualifierName = beanSimpleName.substring(0, beanSimpleName.length() - iShortName.length()).toLowerCase();
+          qualifierName = beanSimpleName.substring(0, beanSimpleName.length() - iShortName.length());
         }
       }
       interfaceTypes.add(rawUType);
diff --git a/inject-generator/src/main/java/io/avaje/inject/generator/TypeReader.java b/inject-generator/src/main/java/io/avaje/inject/generator/TypeReader.java
index 561595c4..17bbc3a8 100644
--- a/inject-generator/src/main/java/io/avaje/inject/generator/TypeReader.java
+++ b/inject-generator/src/main/java/io/avaje/inject/generator/TypeReader.java
@@ -110,7 +110,7 @@ final class TypeReader {
   String name() {
     NamedPrism named = NamedPrism.getInstanceOn(beanType);
     if (named != null) {
-      return named.value().toLowerCase();
+      return named.value();
     }
     if (annotationReader.hasQualifierName()) {
       return annotationReader.qualifierName();
diff --git a/inject-generator/src/main/java/io/avaje/inject/generator/Util.java b/inject-generator/src/main/java/io/avaje/inject/generator/Util.java
index 721e78f5..b3127b30 100644
--- a/inject-generator/src/main/java/io/avaje/inject/generator/Util.java
+++ b/inject-generator/src/main/java/io/avaje/inject/generator/Util.java
@@ -284,7 +284,7 @@ final class Util {
   static String getNamed(Element p) {
     final NamedPrism named = NamedPrism.getInstanceOn(p);
     if (named != null) {
-      return named.value().toLowerCase();
+      return named.value();
     }
     for (final AnnotationMirror annotationMirror : p.getAnnotationMirrors()) {
       final DeclaredType annotationType = annotationMirror.getAnnotationType();
@@ -294,8 +294,7 @@ final class Util {
 
         return AnnotationCopier.toSimpleAnnotationString(annotationMirror)
           .replaceFirst(annotationType.toString(), shortName)
-          .replace("\"", "\\\"")
-          .toLowerCase();
+          .replace("\"", "\\\"");
       }
     }
     return null;
diff --git a/inject/src/main/java/io/avaje/inject/spi/DBeanMap.java b/inject/src/main/java/io/avaje/inject/spi/DBeanMap.java
index d3fb9194..65ea0b05 100644
--- a/inject/src/main/java/io/avaje/inject/spi/DBeanMap.java
+++ b/inject/src/main/java/io/avaje/inject/spi/DBeanMap.java
@@ -91,7 +91,7 @@ final class DBeanMap {
     if (entry == null) {
       return null;
     }
-    return entry.getStrict(KeyUtil.lower(name));
+    return entry.getStrict(name);
   }
 
   boolean contains(String type) {
@@ -112,7 +112,7 @@ final class DBeanMap {
     if (entry == null) {
       return null;
     }
-    return (T) entry.get(KeyUtil.lower(name));
+    return (T) entry.get(name);
   }
 
   @SuppressWarnings("unchecked")
@@ -121,7 +121,7 @@ final class DBeanMap {
     if (entry == null) {
       return null;
     }
-    return (Provider<T>) entry.provider(KeyUtil.lower(name));
+    return (Provider<T>) entry.provider(name);
   }
 
   /**
diff --git a/inject/src/main/java/io/avaje/inject/spi/DContextEntryBean.java b/inject/src/main/java/io/avaje/inject/spi/DContextEntryBean.java
index 26c4e9ea..17215478 100644
--- a/inject/src/main/java/io/avaje/inject/spi/DContextEntryBean.java
+++ b/inject/src/main/java/io/avaje/inject/spi/DContextEntryBean.java
@@ -43,7 +43,7 @@ class DContextEntryBean {
 
   private DContextEntryBean(Object source, String name, int flag) {
     this.source = source;
-    this.name = KeyUtil.lower(name);
+    this.name = name;
     this.flag = flag;
   }
 
@@ -64,14 +64,14 @@ class DContextEntryBean {
    * Return true if qualifierName is null or matched.
    */
   final boolean isNameMatch(String qualifierName) {
-    return qualifierName == null || qualifierName.equals(name);
+    return qualifierName == null || qualifierName.equalsIgnoreCase(name);
   }
 
   /**
    * Return true if qualifierName is matched including null.
    */
   final boolean isNameEqual(String qualifierName) {
-    return Objects.equals(qualifierName, name);
+    return qualifierName == null ? name == null : qualifierName.equalsIgnoreCase(name);
   }
 
   /**
diff --git a/inject/src/main/java/io/avaje/inject/spi/EnrichBean.java b/inject/src/main/java/io/avaje/inject/spi/EnrichBean.java
index 942ba7f7..a1951dee 100644
--- a/inject/src/main/java/io/avaje/inject/spi/EnrichBean.java
+++ b/inject/src/main/java/io/avaje/inject/spi/EnrichBean.java
@@ -16,7 +16,7 @@ public final class EnrichBean<B> {
 
   public EnrichBean(Type type, String name, Consumer<B> consumer) {
     this.type = type;
-    this.name = KeyUtil.lower(name);
+    this.name = name;
     this.consumer = consumer;
   }
 
diff --git a/inject/src/main/java/io/avaje/inject/spi/KeyUtil.java b/inject/src/main/java/io/avaje/inject/spi/KeyUtil.java
index be495c13..5dc1d67d 100644
--- a/inject/src/main/java/io/avaje/inject/spi/KeyUtil.java
+++ b/inject/src/main/java/io/avaje/inject/spi/KeyUtil.java
@@ -7,12 +7,9 @@ import java.lang.reflect.Type;
  */
 final class KeyUtil {
 
-  static String lower(String name) {
-    return name == null ? null : name.toLowerCase();
-  }
 
   static String key(Type type, String name) {
-    return name == null ? type.getTypeName() : type.getTypeName() + "|" + name;
+    return name == null ? type.getTypeName() : type.getTypeName() + "|" + name.toLowerCase();
   }
 
 }


Test patch:
diff --git a/inject-generator/src/test/java/io/avaje/inject/generator/InjectProcessorTest.java b/inject-generator/src/test/java/io/avaje/inject/generator/InjectProcessorTest.java
index 1cac1a06..585a4b07 100644
--- a/inject-generator/src/test/java/io/avaje/inject/generator/InjectProcessorTest.java
+++ b/inject-generator/src/test/java/io/avaje/inject/generator/InjectProcessorTest.java
@@ -35,6 +35,8 @@ class InjectProcessorTest {
           .map(Path::toFile)
           .forEach(File::delete);
       Paths.get("io.avaje.inject.spi.Module").toAbsolutePath().toFile().delete();
+      Paths.get("io.avaje.inject.spi.ModuleOrdering").toAbsolutePath().toFile().delete();
+
     } catch (final Exception e) {
     }
   }
diff --git a/inject-test/src/main/java/io/avaje/inject/test/MetaReader.java b/inject-test/src/main/java/io/avaje/inject/test/MetaReader.java
index d4444bf6..0d7a91b1 100644
--- a/inject-test/src/main/java/io/avaje/inject/test/MetaReader.java
+++ b/inject-test/src/main/java/io/avaje/inject/test/MetaReader.java
@@ -157,7 +157,7 @@ final class MetaReader {
   private String name(Field field) {
     final Named named = field.getAnnotation(Named.class);
     if (named != null) {
-      return named.value().toLowerCase();
+      return named.value();
     }
     for (Annotation annotation : field.getAnnotations()) {
       final var annotationType = annotation.annotationType();
@@ -165,8 +165,7 @@ final class MetaReader {
         if (metaAnnotation.annotationType().equals(Qualifier.class)) {
           return AnnotationReader.simplifyAnnotation(annotation.toString())
             .replaceFirst(annotationType.getCanonicalName(), annotationType.getSimpleName())
-            .replace("()", "").substring(1)
-            .toLowerCase();
+            .replace("()", "").substring(1);
         }
       }
     }
diff --git a/inject-test/src/test/java/org/example/coffee/CoffeeMakerTest.java b/inject-test/src/test/java/org/example/coffee/CoffeeMakerTest.java
index fe1d7674..531f3872 100644
--- a/inject-test/src/test/java/org/example/coffee/CoffeeMakerTest.java
+++ b/inject-test/src/test/java/org/example/coffee/CoffeeMakerTest.java
@@ -64,11 +64,11 @@ class CoffeeMakerTest {
       assertThat(bsomeEntry).isPresent();
 
       final BeanEntry entry = bsomeEntry.get();
-      assertThat(entry.qualifierName()).isEqualTo("b");
+      assertThat(entry.qualifierName()).isEqualTo("B");
       assertThat(entry.keys()).containsExactlyInAnyOrder(name(BSomei.class), name(Somei.class));
       assertThat(entry.type()).isEqualTo(BSomei.class);
       assertThat(entry.priority()).isEqualTo(0);
-      assertThat(entry.bean()).isEqualTo(context.get(Somei.class, "b"));
+      assertThat(entry.bean()).isEqualTo(context.get(Somei.class, "B"));
       assertThat(entry.bean()).isEqualTo(context.get(BSomei.class));
     }
   }
diff --git a/inject-test/src/test/java/org/example/coffee/InjectListTest.java b/inject-test/src/test/java/org/example/coffee/InjectListTest.java
index 47e9c30f..7d63cdc7 100644
--- a/inject-test/src/test/java/org/example/coffee/InjectListTest.java
+++ b/inject-test/src/test/java/org/example/coffee/InjectListTest.java
@@ -36,7 +36,7 @@ class InjectListTest {
     try (BeanScope context = BeanScope.builder().build()) {
       CombinedMapSomei bean = context.get(CombinedMapSomei.class);
       List<String> keys = bean.someKeys();
-      assertThat(keys).containsOnly("a", "b", "a2");
+      assertThat(keys).containsOnly("A", "B", "A2");
       List<String> vals = bean.someVals();
       assertThat(vals).containsOnly("a", "b", "a2");
     }
diff --git a/inject-test/src/test/java/org/example/coffee/qualifier/StoreManagerWithNamedTest.java b/inject-test/src/test/java/org/example/coffee/qualifier/StoreManagerWithNamedTest.java
index 1dde3bfc..eaff1d81 100644
--- a/inject-test/src/test/java/org/example/coffee/qualifier/StoreManagerWithNamedTest.java
+++ b/inject-test/src/test/java/org/example/coffee/qualifier/StoreManagerWithNamedTest.java
@@ -22,9 +22,9 @@ class StoreManagerWithNamedTest {
       SomeStore blueStore = beanScope.get(SomeStore.class, "blue");
       Map<String, SomeStore> stores = beanScope.map(SomeStore.class);
 
-      SomeStore green = stores.get("green");
+      SomeStore green = stores.get("Green");
       assertThat(green).isSameAs(greenStore);
-      SomeStore blue = stores.get("blue");
+      SomeStore blue = stores.get("Blue");
       assertThat(blue).isSameAs(blueStore);
 
       // a map with unnamed component
diff --git a/inject-test/src/test/java/org/example/custom/CustomScopeTest.java b/inject-test/src/test/java/org/example/custom/CustomScopeTest.java
index f514a232..83c80409 100644
--- a/inject-test/src/test/java/org/example/custom/CustomScopeTest.java
+++ b/inject-test/src/test/java/org/example/custom/CustomScopeTest.java
@@ -90,7 +90,7 @@ class CustomScopeTest {
 
       assertThat(customBeanEntry).isPresent();
       assertThat(customBeanEntry.get().bean()).isSameAs(customBean);
-      assertThat(customBeanEntry.get().qualifierName()).isEqualTo("hello");
+      assertThat(customBeanEntry.get().qualifierName()).isEqualTo("Hello");
       assertThat(customBeanEntry.get().priority()).isEqualTo(0);
       assertThat(customBeanEntry.get().keys()).containsExactly(CustomBean.class.getCanonicalName());
 
diff --git a/inject-test/src/test/java/org/example/injectextension/WithExtnNamedSpyTest.java b/inject-test/src/test/java/org/example/injectextension/WithExtnNamedSpyTest.java
index e2a59aee..94acc39f 100644
--- a/inject-test/src/test/java/org/example/injectextension/WithExtnNamedSpyTest.java
+++ b/inject-test/src/test/java/org/example/injectextension/WithExtnNamedSpyTest.java
@@ -44,7 +44,7 @@ class WithExtnNamedSpyTest {
       try (BeanScope beanScope = BeanScope.builder()
         .forTesting()
         .spy(SomeStore.class, "blue")
-        .spy(SomeStore.class, "Green")
+        .spy(SomeStore.class, "green")
         .build()) {
 
         final StoreManagerWithSetterQualifier storeManager = beanScope.get(StoreManagerWithSetterQualifier.class);