Repository: quarkusio/quarkus
Issue: ServiceConfigurationError with "not a subtype" for external library in dev mode

**Describe the bug**
I get several ServiceConfigurationError exceptions with "not a subtype" message when initializing the GeoTools library suite, but only in dev mode. I've verified that the classes in the error messages are both included in the project, but also that they are in different jars (e.g. interface "CRSFactory" in gt-opengis, and "ReferencingObjectFactory" that implements CRSFactory in gt-referencing).
 

**Expected behavior**
No errors even in dev mode.

**Actual behavior**
Several error messages like this when GeoTools is first used: 
"java.util.ServiceConfigurationError: org.opengis.referencing.crs.CRSFactory: org.geotools.referencing.factory.ReferencingObjectFactory not a subtype"


**To Reproduce**
Steps to reproduce the behavior:
1. Start attached project 
2. Access http://localhost:8080/test
3. Check console for error messages

**Configuration**
No application.properties in use

**Screenshots**
(If applicable, add screenshots to help explain your problem.)

**Environment (please complete the following information):**
 - Output of `uname -a`: Linux 5.7.15-100.fc31.x86_64 #1 SMP Tue Aug 11 17:18:01 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux 
 - Output of `java -version`: openjdk 11.0.8 2020-07-14 / OpenJDK Runtime Environment 18.9 (build 11.0.8+10) / OpenJDK 64-Bit Server VM 18.9 (build 11.0.8+10, mixed mode, sharing) 
 - Quarkus version: 1.7.3.Final
 - Build tool: Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f) 

**Additional context**
I've created the smallest possible test case here, so there's no difference in behaviour between dev and prod mode, except from the error messages. In my application I get bugs in dev mode because some of the services from the libraries won't load.

I've looked at https://quarkus.io/guides/class-loading-reference without finding a solution.
I tried to use <parentFirstArtifact> with quarkus-bootstrap-maven-plugin (and include the complete dependency graph for "gt-referencing"), but that didn't have any effect.

**Stack trace**
`2020-09-16 14:11:53,917 WARNING [org.geo.uti.factory] (executor-thread-1) 8: java.util.ServiceConfigurationError: org.opengis.referencing.crs.CRSFactory: org.geotools.referencing.factory.ReferencingObjectFactory not a subtype
	at java.base/java.util.ServiceLoader.fail(ServiceLoader.java:588)
	at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNextService(ServiceLoader.java:1236)
	at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNext(ServiceLoader.java:1264)
	at java.base/java.util.ServiceLoader$2.hasNext(ServiceLoader.java:1299)
	at java.base/java.util.ServiceLoader$3.hasNext(ServiceLoader.java:1384)
	at org.geotools.util.factory.FactoryRegistry.register(FactoryRegistry.java:950)
	at org.geotools.util.factory.FactoryRegistry.scanForPlugins(FactoryRegistry.java:859)
	at org.geotools.util.factory.FactoryRegistry.scanForPluginsIfNeeded(FactoryRegistry.java:889)
	at org.geotools.util.factory.FactoryRegistry.getUnfilteredFactories(FactoryRegistry.java:289)
	at org.geotools.util.factory.FactoryRegistry.getFactoryImplementation(FactoryRegistry.java:497)
	at org.geotools.util.factory.FactoryRegistry.getFactory(FactoryRegistry.java:420)
	at org.geotools.util.factory.FactoryCreator.getFactory(FactoryCreator.java:138)
	at org.geotools.referencing.ReferencingFactoryFinder.getFactory(ReferencingFactoryFinder.java:200)
	at org.geotools.referencing.ReferencingFactoryFinder.getCRSFactory(ReferencingFactoryFinder.java:291)
	at org.geotools.referencing.factory.ReferencingFactoryContainer.getCRSFactory(ReferencingFactoryContainer.java:249)
	at org.geotools.referencing.factory.ReferencingFactoryContainer.initialize(ReferencingFactoryContainer.java:175)
	at org.geotools.referencing.factory.ReferencingFactoryContainer.getImplementationHints(ReferencingFactoryContainer.java:195)
	at org.geotools.util.factory.FactoryRegistry.usesAcceptableHints(FactoryRegistry.java:620)
	at org.geotools.util.factory.FactoryRegistry.isAcceptable(FactoryRegistry.java:575)
	at org.geotools.util.factory.FactoryRegistry.lambda$getFactoryImplementation$2(FactoryRegistry.java:504)
	at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:176)
	at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177)
	at java.base/java.util.Spliterators$IteratorSpliterator.tryAdvance(Spliterators.java:1812)
	at java.base/java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:127)
	at java.base/java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:502)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:488)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
	at java.base/java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:150)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.base/java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:543)
	at org.geotools.util.factory.FactoryRegistry.getFactoryImplementation(FactoryRegistry.java:505)
	at org.geotools.util.factory.FactoryRegistry.getFactory(FactoryRegistry.java:420)
	at org.geotools.util.factory.FactoryCreator.getFactory(FactoryCreator.java:138)
	at org.geotools.referencing.factory.ReferencingFactoryContainer.instance(ReferencingFactoryContainer.java:162)
	at org.geotools.referencing.factory.epsg.FactoryUsingWKT.<init>(FactoryUsingWKT.java:142)
	at org.geotools.referencing.factory.epsg.FactoryUsingWKT.<init>(FactoryUsingWKT.java:136)
	at org.geotools.referencing.factory.epsg.FactoryUsingWKT.<init>(FactoryUsingWKT.java:126)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
	at java.base/java.util.ServiceLoader$ProviderImpl.newInstance(ServiceLoader.java:779)
	at java.base/java.util.ServiceLoader$ProviderImpl.get(ServiceLoader.java:721)
	at java.base/java.util.ServiceLoader$3.next(ServiceLoader.java:1394)
	at org.geotools.util.factory.FactoryRegistry.register(FactoryRegistry.java:953)
	at org.geotools.util.factory.FactoryRegistry.scanForPlugins(FactoryRegistry.java:859)
	at org.geotools.util.factory.FactoryRegistry.scanForPluginsIfNeeded(FactoryRegistry.java:889)
	at org.geotools.util.factory.FactoryRegistry.getFactories(FactoryRegistry.java:251)
	at org.geotools.referencing.ReferencingFactoryFinder.getFactories(ReferencingFactoryFinder.java:183)
	at org.geotools.referencing.ReferencingFactoryFinder.getCRSAuthorityFactories(ReferencingFactoryFinder.java:453)
	at org.geotools.referencing.DefaultAuthorityFactory.getSupportedCodes(DefaultAuthorityFactory.java:124)
	at org.geotools.referencing.CRS.getSupportedCodes(CRS.java:379)
	at org.acme.ExampleResource.test(ExampleResource.java:18)
`

Changed files:
devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java
independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/AppArtifactKey.java

diff --git a/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java b/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java
index ce34e442a0a..e2c54c2029a 100644
--- a/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java
+++ b/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java
@@ -38,6 +38,7 @@
 import java.util.jar.Manifest;
 import java.util.stream.Collectors;
 import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
 import java.util.zip.ZipOutputStream;
 
 import org.apache.maven.artifact.Artifact;
@@ -75,6 +76,7 @@
 import org.eclipse.aether.util.artifact.JavaScopes;
 
 import io.quarkus.bootstrap.model.AppArtifactKey;
+import io.quarkus.bootstrap.model.AppModel;
 import io.quarkus.bootstrap.resolver.maven.options.BootstrapMavenOptions;
 import io.quarkus.bootstrap.resolver.maven.workspace.LocalProject;
 import io.quarkus.bootstrap.resolver.maven.workspace.LocalWorkspace;
@@ -93,6 +95,7 @@
  */
 @Mojo(name = "dev", defaultPhase = LifecyclePhase.PREPARE_PACKAGE, requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME)
 public class DevMojo extends AbstractMojo {
+    private static final String EXT_PROPERTIES_PATH = "META-INF/quarkus-extension.properties";
 
     /**
      * running any one of these phases means the compile phase will have been run, if these have
@@ -717,11 +720,35 @@ void prepare(final boolean triggerCompile) throws Exception {
 
             //in most cases these are not used, however they need to be present for some
             //parent-first cases such as logging
+            //first we go through and get all the parent first artifacts
+            Set<AppArtifactKey> parentFirstArtifacts = new HashSet<>();
+            for (Artifact appDep : project.getArtifacts()) {
+                if (appDep.getArtifactHandler().getExtension().equals("jar") && appDep.getFile().isFile()) {
+                    try (ZipFile file = new ZipFile(appDep.getFile())) {
+                        ZipEntry entry = file.getEntry(EXT_PROPERTIES_PATH);
+                        if (entry != null) {
+                            Properties p = new Properties();
+                            try (InputStream inputStream = file.getInputStream(entry)) {
+                                p.load(inputStream);
+                                String parentFirst = p.getProperty(AppModel.PARENT_FIRST_ARTIFACTS);
+                                if (parentFirst != null) {
+                                    String[] artifacts = parentFirst.split(",");
+                                    for (String artifact : artifacts) {
+                                        parentFirstArtifacts.add(new AppArtifactKey(artifact.split(":")));
+                                    }
+                                }
+                            }
+
+                        }
+                    }
+                }
+            }
             for (Artifact appDep : project.getArtifacts()) {
                 // only add the artifact if it's present in the dev mode context
                 // we need this to avoid having jars on the classpath multiple times
-                if (!devModeContext.getLocalArtifacts().contains(new AppArtifactKey(appDep.getGroupId(), appDep.getArtifactId(),
-                        appDep.getClassifier(), appDep.getArtifactHandler().getExtension()))) {
+                AppArtifactKey key = new AppArtifactKey(appDep.getGroupId(), appDep.getArtifactId(),
+                        appDep.getClassifier(), appDep.getArtifactHandler().getExtension());
+                if (!devModeContext.getLocalArtifacts().contains(key) && parentFirstArtifacts.contains(key)) {
                     addToClassPaths(classPathManifest, appDep.getFile());
                 }
             }
diff --git a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/AppArtifactKey.java b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/AppArtifactKey.java
index a9c1a96ef67..de336cb2d6e 100644
--- a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/AppArtifactKey.java
+++ b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/AppArtifactKey.java
@@ -70,7 +70,7 @@ protected static String[] split(String str, String[] parts, int fromIndex) {
     protected final String classifier;
     protected final String type;
 
-    protected AppArtifactKey(String[] parts) {
+    public AppArtifactKey(String[] parts) {
         this.groupId = parts[0];
         this.artifactId = parts[1];
         if (parts.length == 2 || parts[2] == null) {