Skip to content

Commit 2279d78

Browse files
author
Vincent Potucek
committed
Pull #2292: Modernize codebase with Java improvements - functionalize DefaultModelProcessor#read
1 parent 6be7a12 commit 2279d78

File tree

2 files changed

+294
-50
lines changed

2 files changed

+294
-50
lines changed

impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelProcessor.java

Lines changed: 51 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -29,37 +29,39 @@
2929
import java.util.Optional;
3030

3131
import org.apache.maven.api.annotations.Nullable;
32-
import org.apache.maven.api.di.Inject;
3332
import org.apache.maven.api.di.Named;
3433
import org.apache.maven.api.di.Singleton;
3534
import org.apache.maven.api.model.Model;
35+
import org.apache.maven.api.services.Source;
3636
import org.apache.maven.api.services.model.ModelProcessor;
3737
import org.apache.maven.api.services.xml.ModelXmlFactory;
3838
import org.apache.maven.api.services.xml.XmlReaderRequest;
3939
import org.apache.maven.api.spi.ModelParser;
4040
import org.apache.maven.api.spi.ModelParserException;
4141

42+
import static org.apache.maven.api.spi.ModelParser.STRICT;
43+
4244
/**
4345
*
4446
* Note: uses @Typed to limit the types it is available for injection to just ModelProcessor.
45-
*
47+
* <p>
4648
* This is because the ModelProcessor interface extends ModelLocator and ModelReader. If we
4749
* made this component available under all its interfaces then it could end up being injected
4850
* into itself leading to a stack overflow.
49-
*
51+
* <p>
5052
* A side effect of using @Typed is that it translates to explicit bindings in the container.
5153
* So instead of binding the component under a 'wildcard' key it is now bound with an explicit
5254
* key. Since this is a default component; this will be a plain binding of ModelProcessor to
5355
* this implementation type; that is, no hint/name.
54-
*
56+
* <p>
5557
* This leads to a second side effect in that any @Inject request for just ModelProcessor in
5658
* the same injector is immediately matched to this explicit binding, which means extensions
5759
* cannot override this binding. This is because the lookup is always short-circuited in this
5860
* specific situation (plain @Inject request, and plain explicit binding for the same type.)
59-
*
61+
* <p>
6062
* The simplest solution is to use a custom @Named here so it isn't bound under the plain key.
6163
* This is only necessary for default components using @Typed that want to support overriding.
62-
*
64+
* <p>
6365
* As a non-default component this now gets a negative priority relative to other implementations
6466
* of the same interface. Since we want to allow overriding this doesn't matter in this case.
6567
* (if it did we could add @Priority of 0 to match the priority given to default components.)
@@ -69,75 +71,74 @@
6971
public class DefaultModelProcessor implements ModelProcessor {
7072

7173
private final ModelXmlFactory modelXmlFactory;
72-
private final List<ModelParser> modelParsers;
74+
private final @Nullable List<ModelParser> modelParsers;
7375

74-
@Inject
7576
public DefaultModelProcessor(ModelXmlFactory modelXmlFactory, @Nullable List<ModelParser> modelParsers) {
7677
this.modelXmlFactory = modelXmlFactory;
7778
this.modelParsers = modelParsers;
7879
}
7980

81+
/**
82+
* @implNote The ModelProcessor#locatePom never returns null while the ModelParser#locatePom needs to return an existing path!
83+
*/
8084
@Override
8185
public Path locateExistingPom(Path projectDirectory) {
82-
// Note that the ModelProcessor#locatePom never returns null
83-
// while the ModelParser#locatePom needs to return an existing path!
84-
Path pom = modelParsers.stream()
85-
.map(m -> m.locate(projectDirectory)
86-
.map(org.apache.maven.api.services.Source::getPath)
87-
.orElse(null))
88-
.filter(Objects::nonNull)
86+
return modelParsers.stream()
87+
.map(parser -> parser.locate(projectDirectory))
88+
.filter(Optional::isPresent)
89+
.map(Optional::get)
90+
.map(Source::getPath)
91+
.peek(path -> throwIfWrongProjectDirLocation(path, projectDirectory))
8992
.findFirst()
90-
.orElseGet(() -> doLocateExistingPom(projectDirectory));
93+
.orElseGet(() -> locateExistingPomWithUserDirDefault(projectDirectory));
94+
}
95+
96+
private static void throwIfWrongProjectDirLocation(Path pom, Path projectDirectory) {
9197
if (pom != null && !pom.equals(projectDirectory) && !pom.getParent().equals(projectDirectory)) {
9298
throw new IllegalArgumentException("The POM found does not belong to the given directory: " + pom);
9399
}
94-
return pom;
100+
}
101+
102+
private Path locateExistingPomWithUserDirDefault(Path project) {
103+
return locateExistingPomInDirOrFile(project != null ? project : Paths.get(System.getProperty("user.dir")));
104+
}
105+
106+
private static Path locateExistingPomInDirOrFile(Path project) {
107+
return Files.isDirectory(project) ? isRegularFileOrNull(project.resolve("pom.xml")) : project;
108+
}
109+
110+
private static Path isRegularFileOrNull(Path pom) {
111+
return Files.isRegularFile(pom) ? pom : null;
95112
}
96113

97114
@Override
98115
public Model read(XmlReaderRequest request) throws IOException {
99116
Objects.requireNonNull(request, "source cannot be null");
100-
Path pomFile = request.getPath();
117+
return readPomWithParentInheritance(request, request.getPath());
118+
}
119+
120+
private Model readPomWithParentInheritance(XmlReaderRequest request, Path pomFile) {
121+
List<ModelParserException> exceptions = new ArrayList<>();
101122
if (pomFile != null) {
102-
Path projectDirectory = pomFile.getParent();
103-
List<ModelParserException> exceptions = new ArrayList<>();
104123
for (ModelParser parser : modelParsers) {
105124
try {
106-
Optional<Model> model =
107-
parser.locateAndParse(projectDirectory, Map.of(ModelParser.STRICT, request.isStrict()));
108-
if (model.isPresent()) {
109-
return model.get().withPomFile(pomFile);
110-
}
111-
} catch (ModelParserException e) {
112-
exceptions.add(e);
125+
return parser.locateAndParse(pomFile, Map.of(STRICT, request.isStrict()))
126+
.orElseThrow()
127+
.withPomFile(pomFile);
128+
} catch (RuntimeException ex) {
129+
exceptions.add(new ModelParserException(ex));
113130
}
114131
}
115-
try {
116-
return doRead(request);
117-
} catch (IOException e) {
118-
exceptions.forEach(e::addSuppressed);
119-
throw e;
120-
}
121-
} else {
122-
return doRead(request);
123132
}
133+
return readPomWithSuppressedErrorRethrow(request, exceptions);
124134
}
125135

126-
private Path doLocateExistingPom(Path project) {
127-
if (project == null) {
128-
project = Paths.get(System.getProperty("user.dir"));
129-
}
130-
if (Files.isDirectory(project)) {
131-
Path pom = project.resolve("pom.xml");
132-
return Files.isRegularFile(pom) ? pom : null;
133-
} else if (Files.isRegularFile(project)) {
134-
return project;
135-
} else {
136-
return null;
136+
private Model readPomWithSuppressedErrorRethrow(XmlReaderRequest request, List<ModelParserException> exceptions) {
137+
try {
138+
return modelXmlFactory.read(request);
139+
} catch (RuntimeException ex) {
140+
exceptions.forEach(ex::addSuppressed);
141+
throw ex;
137142
}
138143
}
139-
140-
private Model doRead(XmlReaderRequest request) throws IOException {
141-
return modelXmlFactory.read(request);
142-
}
143144
}

0 commit comments

Comments
 (0)