Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3

...

The most easy and recommended way use is to simply add a maven dependency for it, along with a dependency to the CDI API for development time usage:

Code Block
xml
xml
titlepom.xmlxml
<dependencies>
    ...
    <dependency>
        <groupId>org.apache.struts</groupId>
        <artifactId>struts2-cdi-plugin</artifactId>
        <version>${struts2.version}</version>
    </dependency>
    <dependency>
        <groupId>javax.enterprise</groupId>
        <artifactId>cdi-api</artifactId>
        <version>1.0-SP1</version>
        <scope>provided</scope>
    </dependency>
    ...
</dependencies>

...

should be set either as a property in your pom (recommended) or substituted by a concrete version information, such as 2.3.2 by the time of writing of this document. If you want to use CDI without an application server providing it, you may also want to add a dependency to a CDI implementation of your choice, for example Weld:

Code Block
xml
xml
titlepom.xml with CDI implementationxml
<dependencies>
    ...
    <dependency>
        <groupId>org.apache.struts</groupId>
        <artifactId>struts2-cdi-plugin</artifactId>
        <version>${struts2.version}</version>
    </dependency>
    <dependency>
        <groupId>javax.enterprise</groupId>
        <artifactId>cdi-api</artifactId>
        <version>1.0-SP1</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.jboss.weld</groupId>
        <artifactId>weld-core</artifactId>
        <version>1.0.1-Final</version>
    </dependency>
    <dependency>
        <groupId>org.jboss.weld</groupId>
        <artifactId>weld-se</artifactId>
        <version>1.0.1-Final</version>
    </dependency>
    ...
</dependencies>

...

If your container of choice uses other naming references, the plugin has a single configuration option to point to the right name. Just add a constant like this to your struts.xml to be on the happy path again:

Code Block
xml
xml
titlestruts.xmlxml
    <constant name="struts.objectFactory.cdi.jndiKey" value="java:comp/some/weird/BeanManagerReference" />

...

Implement your Struts 2 actions or interceptors just as usual, enriched with CDI and @Inject annotations:

Code Block
java
java
titleNumberGuess.javajava
package org.apache.struts2.example.cdi;

import com.opensymphony.xwork2.ActionSupport;
import javax.inject.Inject;

public class NumberGuess extends ActionSupport {

    @Inject
    Game game;

    public Game getGame() {
        return game;
    }

    @Override
    public String execute() throws Exception {
        return SUCCESS;
    }

    public String guess() throws Exception {
        final String errorMessage = game.check();
        addActionError(errorMessage);

        if (Game.CORRECT.equals(errorMessage)) {
            game.reset();
        } else if (game.getRemainingGuesses() == 0) {
            addActionError("The correct guess was " + game.getGuess() + ". Game is reset.");
            game.reset();
        }


        return SUCCESS;
    }


}

...

Now that you are aware of that, here is the rest of the inevitable NumberGuess CDI example in Struts 2 flavour. Add a JSP view similar to this:

Code Block
html
html
1NumberGuess.jsphtml
<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
    <title>Numberguess</title>
</head>

<body>
<h2>Numberguess Game - Struts 2 CDI Example</h2>

<h3>I've picked a number between <s:property value="game.smallest"/> and <s:property value="game.biggest"/>.
    You have <s:property value="game.remainingGuesses"/>remaining guesses.</h3>

<s:form action="guess">
    <s:textfield name="game.guess" label="Your Guess"/>
    <s:submit/>
</s:form>
<p/>
<s:actionerror/>

</body>
</html>

along - if not using the fabulous and recommended Struts 2 Convention Plugin - with a struts.xml like this

Code Block
xml
xml
1struts.xmlxml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
          "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"       
          "http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
  <constant name="struts.enable.DynamicMethodInvocation" value="false"/>
  <constant name="struts.devMode" value="true"/>
  
    <package name="numberguess" extends="struts-default">

        <action name="NumberGuess" class="org.apache.struts2.example.cdi.NumberGuess">
            <result>/WEB-INF/pages/NumberGuess.jsp</result>
        </action>

        <action name="guess" class="org.apache.struts2.example.cdi.NumberGuess" method="guess">
            <result>/WEB-INF/pages/NumberGuess.jsp</result>
        </action>

    </package>

</struts>

Now you can add the business logic we want to be managed and injected by CDI. Start with two qualifier annotations:

Code Block
java
java
1Random.javajava
package org.apache.struts2.example.cdi;

import javax.inject.Qualifier;
import java.lang.annotation.Documented;
import static java.lang.annotation.ElementType.*;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Target;

@Target( { TYPE, METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
@Documented
@Qualifier
public @interface Random {}
Code Block
java
java
1MaxNumber.javajava
package org.apache.struts2.example.cdi;

import javax.inject.Qualifier;
import java.lang.annotation.Documented;
import static java.lang.annotation.ElementType.*;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Target;

@Target( { TYPE, METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
@Documented
@Qualifier
public @interface MaxNumber {}

Now on to the actual business beans, the Game and the Generator bean:

Code Block
java
java
1Game.javajava
package org.apache.struts2.example.cdi;

import javax.annotation.PostConstruct;
import javax.enterprise.context.SessionScoped;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;
import javax.inject.Named;
import java.io.Serializable;

@Named
@SessionScoped
public class Game implements Serializable {

    public static final String CORRECT = "Correct !!!";
    public static final String WRONG = "Sorry, wrong number !!!";

    private int number;
    private int guess;
    private int smallest;

    @MaxNumber
    @Inject
    private int maxNumber;

    private int biggest;
    private int remainingGuesses;

    @Random
    @Inject
    Instance<Integer> randomNumber;

    public Game() {
    }

    public int getNumber() {
        return number;
    }

    public int getGuess() {
        return guess;
    }

    public void setGuess( int guess ) {
        this.guess = guess;
    }

    public int getSmallest() {
        return smallest;
    }

    public int getBiggest() {
        return biggest;
    }

    public int getRemainingGuesses() {
        return remainingGuesses;
    }

    public String check() throws InterruptedException {
        if (guess > number) {
            biggest = guess - 1;
        }
        if (guess < number) {
            smallest = guess + 1;
        }
        if (guess == number) {
            return CORRECT;
        }
        remainingGuesses--;
        return WRONG;
    }

    @PostConstruct
    public void reset() {
        this.smallest = 0;
        this.guess = 0;
        this.remainingGuesses = 10;
        this.biggest = maxNumber;
        this.number = randomNumber.get();
    }

}
Code Block
java
java
1Generator.javajava
package org.apache.struts2.example.cdi;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
import java.io.Serializable;

@ApplicationScoped
public class Generator implements Serializable {
   
   private java.util.Random random = new java.util.Random( System.currentTimeMillis() );
   
   private int maxNumber = 100;
   
   java.util.Random getRandom() {
      return random;
   }
   
   @Produces @Random int next() { 
      return getRandom().nextInt(maxNumber); 
   }
   
   @Produces @MaxNumber int getMaxNumber() {
      return maxNumber;
   }

} 

...