View Javadoc
1   package org.apache.maven.model.normalization;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.ArrayList;
23  import java.util.Collections;
24  import java.util.LinkedHashMap;
25  import java.util.List;
26  import java.util.Map;
27  
28  import javax.inject.Named;
29  import javax.inject.Singleton;
30  
31  import org.apache.maven.model.Build;
32  import org.apache.maven.model.Dependency;
33  import org.apache.maven.model.Model;
34  import org.apache.maven.model.Plugin;
35  import org.apache.maven.model.building.ModelBuildingRequest;
36  import org.apache.maven.model.building.ModelProblemCollector;
37  import org.apache.maven.model.merge.MavenModelMerger;
38  import org.codehaus.plexus.util.StringUtils;
39  
40  /**
41   * Handles normalization of a model.
42   *
43   * @author Benjamin Bentmann
44   */
45  @Named
46  @Singleton
47  public class DefaultModelNormalizer
48      implements ModelNormalizer
49  {
50  
51      private DuplicateMerger merger = new DuplicateMerger();
52  
53      @Override
54      public void mergeDuplicates( Model model, ModelBuildingRequest request, ModelProblemCollector problems )
55      {
56          Build build = model.getBuild();
57          if ( build != null )
58          {
59              List<Plugin> plugins = build.getPlugins();
60              Map<Object, Plugin> normalized = new LinkedHashMap<>( plugins.size() * 2 );
61  
62              for ( Plugin plugin : plugins )
63              {
64                  Object key = plugin.getKey();
65                  Plugin first = normalized.get( key );
66                  if ( first != null )
67                  {
68                      merger.mergePlugin( plugin, first );
69                  }
70                  normalized.put( key, plugin );
71              }
72  
73              if ( plugins.size() != normalized.size() )
74              {
75                  build.setPlugins( new ArrayList<>( normalized.values() ) );
76              }
77          }
78  
79          /*
80           * NOTE: This is primarily to keep backward-compat with Maven 2.x which did not validate that dependencies are
81           * unique within a single POM. Upon multiple declarations, 2.x just kept the last one but retained the order of
82           * the first occurrence. So when we're in lenient/compat mode, we have to deal with such broken POMs and mimic
83           * the way 2.x works. When we're in strict mode, the removal of duplicates just saves other merging steps from
84           * aftereffects and bogus error messages.
85           */
86          List<Dependency> dependencies = model.getDependencies();
87          Map<String, Dependency> normalized = new LinkedHashMap<>( dependencies.size() * 2 );
88  
89          for ( Dependency dependency : dependencies )
90          {
91              normalized.put( dependency.getManagementKey(), dependency );
92          }
93  
94          if ( dependencies.size() != normalized.size() )
95          {
96              model.setDependencies( new ArrayList<>( normalized.values() ) );
97          }
98      }
99  
100     /**
101      * DuplicateMerger
102      */
103     protected static class DuplicateMerger
104         extends MavenModelMerger
105     {
106 
107         public void mergePlugin( Plugin target, Plugin source )
108         {
109             super.mergePlugin( target, source, false, Collections.emptyMap() );
110         }
111 
112     }
113 
114     @Override
115     public void injectDefaultValues( Model model, ModelBuildingRequest request, ModelProblemCollector problems )
116     {
117         injectDependencyDefaults( model.getDependencies() );
118 
119         Build build = model.getBuild();
120         if ( build != null )
121         {
122             for ( Plugin plugin : build.getPlugins() )
123             {
124                 injectDependencyDefaults( plugin.getDependencies() );
125             }
126         }
127     }
128 
129     private void injectDependencyDefaults( List<Dependency> dependencies )
130     {
131         for ( Dependency dependency : dependencies )
132         {
133             if ( StringUtils.isEmpty( dependency.getScope() ) )
134             {
135                 // we cannot set this directly in the MDO due to the interactions with dependency management
136                 dependency.setScope( "compile" );
137             }
138         }
139     }
140 
141 }