Java Maven Mojo : Complex Map Attribute
Asked Answered
G

2

1

The example of map attribute for a mojo mentioned in maven.apache.org is quite simple as it defines a Map with a String as a key and as a value as specified below :

/**
 * My Map.
 */
@Parameter
private Map myMap;

and it's assigned configuration would look like this :

<myMap>
 <key1>value1</key1>
 <key2>value2</key2>
</myMap>

What I am trying to achieve is a more advanced map which takes a String as a key and my own defined class Person as value:

/**
* My Advanced Map.
*/
@Parameter
private Map<String,Person> myMap;

The Person class is located in the same package as my MOJO and it looks like:

public class Person {
  private String name;
  private int age;

  public void setName( String name )
  {
      this.name = name;
  }

  public void setAge( int age )
  {
      this.age = age;
  }

  public String getName( )
  {
      return this.name;
  }

  public int getAge( )
  {
      return this.age ;
  }
}

I assume that the configuration for my MOJO would look like :

<myMap>
  <firstPerson>
    <person>
      <name>steve</name>
      <age>26</age>
    </person>
  </firstPerson>
  <secondPerson>
    <person>
      <name>meruem</name>
      <age>1</age>
    </person>
  </secondPerson>
</myMap>

Running this MOJO with the above configuration will create the map with the defined keys but I always get null values : {firstPerson=null,secondPerson=null}

Currently, I don't know whether I am doing something wrong or if the example is even supported as no documentation has been found that describes an 'advanced' map attribute and my last resort for now would be browsing the sources.

Grecian answered 8/5, 2014 at 19:12 Comment(2)
What will the key in your case? The name of the person? Or a combination of multiple attributes of the Person class?Vrablik
Well, the key will be an attribute to identify the person.Grecian
P
3

You are actually really close to the solution. You just need to configure your plugin like this (without the inner <person> element):

<myMap>
  <firstPerson>
    <name>steve</name>
    <age>26</age>
  </firstPerson>
  <secondPerson>
    <name>meruem</name>
    <age>1</age>
  </secondPerson>
</myMap>

To provide you with a full working example, consider the following Maven plugin POM:

<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>sample.plugin</groupId>
    <artifactId>test-maven-plugin</artifactId>
    <version>1.0.0</version>
    <packaging>maven-plugin</packaging>
    <dependencies>
        <dependency>
            <groupId>org.apache.maven</groupId>
            <artifactId>maven-plugin-api</artifactId>
            <version>2.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.maven.plugin-tools</groupId>
            <artifactId>maven-plugin-annotations</artifactId>
            <version>3.4</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</project>

having the following MOJO, declaring a goal foo and having a parameter of type Map<String, Person>, which simply logs the Map as info:

@Mojo(name = "foo")
public class MyMojo extends AbstractMojo {

    @Parameter
    private Map<String, Person> map;

    public void execute() throws MojoExecutionException, MojoFailureException {
        getLog().info(map.toString());
    }

}

and the following Person class:

public class Person {

    private String name;
    private int age;

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }

}

Once this Maven plugin is installed in the repo (using mvn clean install), we can use it in a project like this:

<plugin>
    <groupId>sample.plugin</groupId>
    <artifactId>test-maven-plugin</artifactId>
    <version>1.0.0</version>
    <executions>
        <execution>
            <id>foo</id>
            <phase>generate-sources</phase>
            <goals>
                <goal>foo</goal>
            </goals>
            <configuration>
                <map>
                    <person1>
                        <name>Name 1</name>
                        <age>10</age>
                    </person1>
                    <person2>
                         <name>Name 2</name>
                         <age>20</age>
                     </person2>
                </map>
            </configuration>
        </execution>
    </executions>
</plugin>

The output of this plugin when running mvn clean generate-sources is:

[INFO] --- test-maven-plugin:1.0.0:foo (add-source) @ test ---
[INFO] {person1=Person [name=Name 1, age=10], person2=Person [name=Name 2, age=20]}
Prodigal answered 11/10, 2015 at 13:7 Comment(1)
Thanks for elaborate example. I've rewarded you the bounty.Outstay
S
0

Add the @Parameter annotation to the name and age attributes in your Person class.

Suzan answered 15/5, 2014 at 1:20 Comment(1)
I don't think that would work also, as i went through the sources i came into the class MapConverter which instantiate the Map object but the convert method treats always the value of the map as a String and not an Object.Grecian

© 2022 - 2024 — McMap. All rights reserved.