Versions Compared

Key

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

...

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
xmlxml
titlepom.xml
xml
<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:

xml
Code Block
xml
titlepom.xml with CDI implementation
xml
<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:

xml
Code Block
xml
titlestruts.xml
xml
    <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
javajava
titleNumberGuess.java
java
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
htmlhtml
1NumberGuess.jsp
html
<%@ 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

xml
Code Block
xml
1struts.xml
xml
<?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:

java
Code Block
java
1Random.java
java
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 {}
java
Code Block
java
1MaxNumber.java
java
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
javajava
1Game.java
java
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
javajava
1Generator.java
java
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;
   }

} 

...