# Plexus Container Five-Minute Tutorial

**May 21, 2009**  
By Brian Demers

5 minute read time

The goal of this blog is to show an updated and more involved example than what is currently located on the Plexus site. This will cover creating a few components and explain the different ways to inject your [dependencies](/content/blog/software-dependencies-a-beginners-guide/index.html). This example assumes you are using Maven 2 to make your life easier.

## Creating a Component Interface

The first task to creating a component is to define its _role_. In Java, this usually takes the form of defining an interface with the functionality the component will expose.

**Note:** Plexus does not strictly require you to use an interface to define the role, but is strongly recommended to help improve your application design.

```java
package example;

public interface Cheese
{
    /**
    * Slices the cheese for apportioning onto crackers.
    * @param slices the number of slices
    */
    void slice( int slices );

/**
    * Get the description of the aroma of the cheese.
    * @return the aroma
    */
    String getAroma();
}
```

That is it, nothing special, just an interface. We will use the class name as the role, in this example it will be `Cheese.class`

## Creating a Component Implementation

Once an interface is declared, you need to create one or more implementations of the functionality declared by it.

```java
package example;

import org.codehaus.plexus.component.annotations.Component;

/**
 * All we need to tell Plexus that this is a component.
 */
@Component( role = Cheese.class, hint = "parmesan" )
public class ParmesanCheese
    implements Cheese
{
    public void slice( int slices )
    {
        throw new UnsupportedOperationException( "No can do" );
    }

public String getAroma()
    {
        return "strong";
    }
}
```

All you need to do is add the `@Component` annotation, to define the role (the interface name from above) and a hint (to identify a unique implementation).

## Creating a Component Descriptor

Other then telling you how to create it, and what it is for, I am not going to tell you much about it. This file will be generated for you in `META-INF/plexus/components.xml` inside your jar.

The component descriptor describes the component and its dependencies (we will get to that next). All you need to do is configure the plexus-component-metadata plugin in your pom. And of course, you need to add your maven dependencies.

```xml
<project>
...
  <dependencies>

<!-- The Plexus annotations -->
    <dependency>
      <groupId>org.codehaus.plexus</groupId>
      <artifactId>plexus-component-annotations</artifactId>
      <version>1.0-beta-3.0.5</version>
    </dependency>

<!-- The plexus container -->
    <dependency>
      <groupId>org.codehaus.plexus</groupId>
      <artifactId>plexus-container-default</artifactId>
      <version>1.0-beta-3.0.5</version>
    </dependency>
...
  </dependencies>
 <build>
...
<plugins>
...
      <!-- Needed to process the annotations to create an xml file -->
<plugin>
        <groupId>org.codehaus.plexus</groupId>
        <artifactId>plexus-component-metadata</artifactId>
        <version>1.0-beta-3.0.5</version>
        <executions>
          <execution>
            <id>process-classes</id>
            <goals>
              <goal>generate-metadata</goal>
            </goals>
          </execution>
          <execution>
            <id>process-test-classes</id>
            <goals>
              <goal>generate-test-metadata</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
...
<plugins>
</project>
```

## Injecting Dependencies

The above is all great stuff, but so far we haven't injected anything yet.

First, we will add another cheese. This will be the default implementation.

```java
package example;

import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.logging.Logger;

/**
 * AmericanCheese is the default cheese in most places. So here we are using it as the default component. Note: no
 * <code>hint</code> is specified.
 */
@Component( role = Cheese.class )
public class AmericanCheese
    implements Cheese
{
    @Requirement
    Logger logger;

public void slice( int slices )
    {
        this.logger.info( "Slicing the cheese: " + slices + " times." );
    }

public String getAroma()
    {
        return "plastic";
    }
}
```

Then we will create another interface/component. Something simple:

```java
package example;

public interface Plate
{
    void printItems();
}
```

And now for the fun!

Create a Plate component

```java
package example;

public class CheesePlate
    implements Plate
{
...
  public void printItems()
  {
    ...
  }
}
```

To inject the default component, you just add the `@Requirement` to you field. Plexus assumes the role is the type of the field. In this case, the field is a `Cheese`

```java
  @Requirement
  private Cheese americanCheese;
```

This does the same as the above snippet, but is more verbose.

```java
  @Requirement( hint = "default" )
  private Cheese moreAmericanCheese;
```

To inject a specific implementation use the component's `hint`.

```java
  @Requirement( hint = "parmesan" )
  private Cheese parmesanCheese;
```

To inject all the implementations of a component, just define the `role`.

```java
  @Requirement( role = Cheese.class )
  private List<cheese> cheeses;
```

You can also inject the components as a Map, the key of the entry is the component's `hint`.

```java
  @Requirement( role = Cheese.class )
  private Map<string, Cheese> cheeseMap;
```

## Put Everything Together

The following class demonstrates the different dependency techniques.

```java
package example;

import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;

@Component( role = Plate.class )
public class CheesePlate
    implements Plate
{
    /**
     * Inject the default cheese.
     */
    @Requirement
    private Cheese americanCheese;

/**
     * Inject the default cheese, this does the same as the previous line.
     */
    @Requirement( hint = "default" )
    private Cheese moreAmericanCheese;

/**
     * Inject the ParmesanCheese.
     */
    @Requirement( hint = "parmesan" )
    private Cheese parmesanCheese;

/**
     * Inject all the cheese.  The container automatically add all the components defined with the role <code>Cheese.class</code>.
     */
    @Requirement( role = Cheese.class )
    private List<cheese> cheeses;

/**
     * You can also inject the components as a Map, where the key is the Components <code>hint</code>.
     */
    @Requirement( role = Cheese.class )
    private Map<string, Cheese> cheeseMap;

public void printItems()
    {
        System.out.println( "americanCheese smells like: " + americanCheese.getAroma() );
        System.out.println( "moreAmericanCheese smells like: " + moreAmericanCheese.getAroma() );
        System.out.println( "parmesanCheese smells : " + parmesanCheese.getAroma() );

System.out.println( "\nThe List of cheeses has:" );
        for ( Cheese cheese : this.cheeses )
        {
            System.out.println( "cheese: " + cheese.getClass().getSimpleName() );
        }

System.out.println( "\nThe Map contains:" );
        for ( Entry<string, Cheese> entry : this.cheeseMap.entrySet() )
        {
            System.out.println( "hint: " + entry.getKey() + ", value: " + entry.getValue().getClass().getSimpleName() );
        }
    }
}
```

## Executing the Plexus Application

The final step is to execute the application that uses this component. In this example, you will use an container from a standard Java class with a main() method.

### Creating the Container

Creating the container is very simple:

```java
package example;

import org.codehaus.plexus.DefaultPlexusContainer;
import org.codehaus.plexus.PlexusContainer;

public class Example
{
    public static void main( String[] args )
        throws Exception
    {
        // create a new container
        PlexusContainer container = new DefaultPlexusContainer();

...

// stop the components and container
        container.dispose();
    }
}
```

That's all there is to it: create the container, and start it. Defaults and the current classloader will be used.

### Retrieving the Component

To retrieve the Plate component from the container and execute its printItems() method, add the following lines after those that start the container:

```java
  Plate plate = container.lookup( Plate.class );
  plate.printItems();
```

That's all there is to getting started with Plexus.

Written by **Brian Demers**

Brian is a Developer Advocate at Okta. He has a strong knowledge of Java including experience with an array of java and web-base technologies, along with involvement in open source communities.
