Copilot commented on code in PR #264:
URL: 
https://github.com/apache/maven-dependency-analyzer/pull/264#discussion_r2733182787


##########
src/main/java/org/apache/maven/shared/dependency/analyzer/dependencyclasses/WarMainDependencyClassesProvider.java:
##########
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.shared.dependency.analyzer.dependencyclasses;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+import javax.xml.XMLConstants;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.apache.maven.model.Plugin;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.shared.dependency.analyzer.ClassesPatterns;
+import org.apache.maven.shared.dependency.analyzer.DependencyUsage;
+import 
org.apache.maven.shared.dependency.analyzer.MainDependencyClassesProvider;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+/**
+ * Implementation of {@link MainDependencyClassesProvider} for web 
applications.
+ */
+@Named
+@Singleton
+class WarMainDependencyClassesProvider implements 
MainDependencyClassesProvider {
+
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(WarMainDependencyClassesProvider.class);
+
+    @Override
+    public Set<DependencyUsage> getDependencyClasses(MavenProject project, 
ClassesPatterns excludedClasses)
+            throws IOException {
+        if (!"war".equals(project.getPackaging())) {
+            return Collections.emptySet();
+        }
+
+        File webXml = findWebXml(project);
+        if (webXml == null) {
+            LOGGER.debug("No web.xml found for project {}", project);
+            return Collections.emptySet();
+        }
+
+        if (!webXml.isFile()) {
+            LOGGER.debug("{} is not a file in project {}", webXml, project);
+            return Collections.emptySet();
+        }
+
+        try {
+            return processWebXml(webXml, excludedClasses);
+        } catch (SAXException | ParserConfigurationException e) {
+            LOGGER.warn("Error parsing web.xml file {}: {}", webXml, 
e.getMessage());
+            return Collections.emptySet();
+        }
+    }
+
+    private File findWebXml(MavenProject project) {
+        // standard location
+        File webXmlFile = new File(project.getBasedir(), 
"src/main/webapp/WEB-INF/web.xml");
+        if (webXmlFile.isFile()) {
+            return webXmlFile;
+        }
+
+        // check maven-war-plugin configuration for custom location of web.xml

Review Comment:
   Potential NullPointerException: project.getBuild() can return null. Consider 
adding a null check before calling getPluginsAsMap(), similar to how it's 
handled in the test at line 74 where an empty Build is explicitly set. If 
getBuild() returns null, the method should return null early to avoid the NPE.
   ```suggestion
           // check maven-war-plugin configuration for custom location of 
web.xml
           if (project.getBuild() == null) {
               LOGGER.debug("No build found for project {}", project);
               return null;
           }
   ```



##########
src/test/java/org/apache/maven/shared/dependency/analyzer/dependencyclasses/WarMainDependencyClassesProviderTest.java:
##########
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.shared.dependency.analyzer.dependencyclasses;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.Set;
+import java.util.stream.Stream;
+
+import org.apache.maven.model.Build;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.shared.dependency.analyzer.ClassesPatterns;
+import org.apache.maven.shared.dependency.analyzer.DependencyUsage;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+class WarMainDependencyClassesProviderTest {
+
+    @Mock
+    private MavenProject project;
+
+    private final WarMainDependencyClassesProvider provider = new 
WarMainDependencyClassesProvider();
+
+    @Test
+    void parseDefaultWebXml() throws IOException, URISyntaxException {
+        Path basePath = Paths.get(getClass().getResource("/webapp").toURI());
+        when(project.getBasedir()).thenReturn(basePath.toFile());
+        when(project.getPackaging()).thenReturn("war");
+
+        Set<DependencyUsage> classes =
+                provider.getDependencyClasses(project, new 
ClassesPatterns(Collections.singleton(".*\\.Servlet$")));
+
+        assertThat(classes)
+                .map(DependencyUsage::getDependencyClass)
+                .containsExactlyInAnyOrder("org.example.test.Filter", 
"org.example.test.Listener");
+    }
+
+    @Test
+    void noDefaultWebXml() throws IOException, URISyntaxException {
+        Path basePath = 
Paths.get(getClass().getResource("/webapp/examples").toURI());
+        when(project.getBasedir()).thenReturn(basePath.toFile());
+        when(project.getPackaging()).thenReturn("war");
+        when(project.getBuild()).thenReturn(new Build());
+
+        Set<DependencyUsage> classes = provider.getDependencyClasses(project, 
new ClassesPatterns());
+
+        assertThat(classes).isEmpty();
+    }
+
+    public static Stream<Arguments> examplesData() {
+        return Stream.of(
+                Arguments.of("empty-web.xml", new String[] {}),
+                Arguments.of("nons-web.xml", new String[] {
+                    "org.example.test.Filter", "org.example.test.Listener", 
"org.example.test.Servlet"
+                }),
+                Arguments.of("multi-web.xml", new String[] {
+                    "org.example.test.Filter1",
+                    "org.example.test.Filter2",
+                    "org.example.test.Listener1",
+                    "org.example.test.Listener2"
+                }),
+                Arguments.of("wrong-web.xml", new String[] {}),
+                Arguments.of("no-exists-web.xml", new String[] {}));
+    }
+
+    @ParameterizedTest
+    @MethodSource("examplesData")
+    void examples(String webXmlName, String[] expectedCLasses) throws 
Exception {
+        setupProjectWithWebXml(webXmlName);
+
+        Set<DependencyUsage> classes = provider.getDependencyClasses(project, 
new ClassesPatterns());
+
+        
assertThat(classes).map(DependencyUsage::getDependencyClass).containsExactlyInAnyOrder(expectedCLasses);

Review Comment:
   Parameter name has a typo: "expectedCLasses" should be "expectedClasses" 
(lowercase 'l' in 'Classes').
   ```suggestion
       void examples(String webXmlName, String[] expectedClasses) throws 
Exception {
           setupProjectWithWebXml(webXmlName);
   
           Set<DependencyUsage> classes = 
provider.getDependencyClasses(project, new ClassesPatterns());
   
           
assertThat(classes).map(DependencyUsage::getDependencyClass).containsExactlyInAnyOrder(expectedClasses);
   ```



##########
src/it/web-application/pom.xml:
##########
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<project
+    xmlns="http://maven.apache.org/POM/4.0.0";
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>org.apache.maven.shared.dependency-analyzer.tests</groupId>
+  <artifactId>web-applicaiton</artifactId>

Review Comment:
   Artifact ID has a typo: "web-applicaiton" should be "web-application" 
(missing 't' in 'application').
   ```suggestion
     <artifactId>web-application</artifactId>
   ```



##########
src/it/web-application/web2/pom.xml:
##########
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<project
+    xmlns="http://maven.apache.org/POM/4.0.0";
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.maven.shared.dependency-analyzer.tests</groupId>
+    <artifactId>web-applicaiton</artifactId>

Review Comment:
   Parent artifact ID has a typo: "web-applicaiton" should be "web-application" 
(missing 't' in 'application'). This must match the parent POM's artifactId.
   ```suggestion
       <artifactId>web-application</artifactId>
   ```



##########
src/main/java/org/apache/maven/shared/dependency/analyzer/dependencyclasses/WarMainDependencyClassesProvider.java:
##########
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.shared.dependency.analyzer.dependencyclasses;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+import javax.xml.XMLConstants;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.apache.maven.model.Plugin;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.shared.dependency.analyzer.ClassesPatterns;
+import org.apache.maven.shared.dependency.analyzer.DependencyUsage;
+import 
org.apache.maven.shared.dependency.analyzer.MainDependencyClassesProvider;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+/**
+ * Implementation of {@link MainDependencyClassesProvider} for web 
applications.
+ */
+@Named
+@Singleton
+class WarMainDependencyClassesProvider implements 
MainDependencyClassesProvider {
+
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(WarMainDependencyClassesProvider.class);
+
+    @Override
+    public Set<DependencyUsage> getDependencyClasses(MavenProject project, 
ClassesPatterns excludedClasses)
+            throws IOException {
+        if (!"war".equals(project.getPackaging())) {
+            return Collections.emptySet();
+        }
+
+        File webXml = findWebXml(project);
+        if (webXml == null) {
+            LOGGER.debug("No web.xml found for project {}", project);
+            return Collections.emptySet();
+        }
+
+        if (!webXml.isFile()) {
+            LOGGER.debug("{} is not a file in project {}", webXml, project);
+            return Collections.emptySet();
+        }
+
+        try {
+            return processWebXml(webXml, excludedClasses);
+        } catch (SAXException | ParserConfigurationException e) {
+            LOGGER.warn("Error parsing web.xml file {}: {}", webXml, 
e.getMessage());
+            return Collections.emptySet();
+        }
+    }
+
+    private File findWebXml(MavenProject project) {
+        // standard location
+        File webXmlFile = new File(project.getBasedir(), 
"src/main/webapp/WEB-INF/web.xml");
+        if (webXmlFile.isFile()) {
+            return webXmlFile;
+        }
+
+        // check maven-war-plugin configuration for custom location of web.xml
+        Plugin plugin = 
project.getBuild().getPluginsAsMap().get("org.apache.maven.plugins:maven-war-plugin");
+        if (plugin == null) {
+            // should not happen as we are in a war project
+            LOGGER.debug("No war plugin found for project {}", project);
+            return null;
+        }
+
+        return Optional.ofNullable(plugin.getConfiguration())
+                .map(Xpp3Dom.class::cast)
+                .map(config -> config.getChild("webXml"))
+                .map(Xpp3Dom::getValue)
+                .map(path -> new File(project.getBasedir(), path))
+                .orElse(null);
+    }
+
+    private Set<DependencyUsage> processWebXml(File webXml, ClassesPatterns 
excludedClasses)
+            throws IOException, SAXException, ParserConfigurationException {
+
+        DocumentBuilderFactory documentBuilderFactory = 
DocumentBuilderFactory.newInstance();
+        
documentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+        documentBuilderFactory.setNamespaceAware(true);
+        
documentBuilderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd";,
 false);
+
+        DocumentBuilder documentBuilder = 
documentBuilderFactory.newDocumentBuilder();
+
+        Document doc = documentBuilder.parse(webXml);
+
+        List<String> classes = new ArrayList<>();
+
+        processClassesFromTags(doc, classes, "filter-class");
+        processClassesFromTags(doc, classes, "listener-class");
+        processClassesFromTags(doc, classes, "servlet-class");
+
+        return classes.stream()
+                .filter(className -> !excludedClasses.isMatch(className))
+                .map(className -> new DependencyUsage(className, 
webXml.toString()))
+                .collect(Collectors.toSet());
+    }
+
+    private void processClassesFromTags(Document doc, List<String> classes, 
String tagName) {
+        NodeList tags = doc.getElementsByTagName(tagName);
+        for (int i = 0; i < tags.getLength(); i++) {
+            Node node = tags.item(i);
+            classes.add(node.getTextContent());

Review Comment:
   The textContent from XML nodes includes leading and trailing whitespace. 
Consider using trim() on the class name to handle XML files with different 
formatting, where class names might be on separate lines with indentation. This 
would make the implementation more robust against various XML formatting styles.
   ```suggestion
               String className = node.getTextContent();
               if (className != null) {
                   className = className.trim();
                   if (!className.isEmpty()) {
                       classes.add(className);
                   }
               }
   ```



##########
src/it/web-application/web1/pom.xml:
##########
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<project
+    xmlns="http://maven.apache.org/POM/4.0.0";
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.maven.shared.dependency-analyzer.tests</groupId>
+    <artifactId>web-applicaiton</artifactId>

Review Comment:
   Parent artifact ID has a typo: "web-applicaiton" should be "web-application" 
(missing 't' in 'application'). This must match the parent POM's artifactId.
   ```suggestion
       <artifactId>web-application</artifactId>
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to