Issue with Jersery1.x, Guice and Tomcat - java

I am developing a simple application using Jersey 1.x, Guice and trying to run on Tomcat.
I used Guice filter and Guice Listener along with Resources and Application.
Below is my web.xml :
<filter>
<filter-name>guiceFilter</filter-name>
<filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>guiceFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<display-name>Guice Listener</display-name>
<listener-class>com.simple.application.GuiceListener</listener-class>
</listener>
And using GuiceListener I injected all my dependencies,
public class GuiceListener extends GuiceServletContextListener {
private Injector injector;
#Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
try {
super.contextDestroyed(servletContextEvent);
} finally {
injector = null;
}
}
#Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
injector = Guice.createInjector(new SimpleServlet());
super.contextInitialized(servletContextEvent);
injector.injectMembers(this);
}
#Override
protected Injector getInjector() {
return injector;
}
}
And This is how my Servlet looks
public class SimpleServlet extends JerseyServletModule {
#Override
protected void configureServlets() {
configureGuiceServlet();
}
private void configureGuiceServlet() {
bind(SimpleResource.class).in(Scopes.SINGLETON);
serve("/service/*").with(GuiceContainer.class);
bind(Manager.class).to(ManagerImpl.class);
}
}
And I created a resource with a GET method,
#Path("/stuff")
public class SimpleResource {
private final ManagerImpl manager;
#Inject
public SimpleResource(final ManagerImpl manager) {
this.manager = manager;
}
#GET
#Path("{id}")
#Produces(MediaType.TEXT_HTML)
public String submitData(#PathParam("id") final String id) {
String welcomeScreen = manager.getWelcomeScreen();
return "This is" + welcomeScreen + id;
}
}
I used Constructor Injection for injecting classes.
And this is how my application looks
public class SimpleApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
return ImmutableSet.<Class<?>>builder()
.add(SimpleResource.class)
.build();
}
}
I am deploying this on Tomcat 7 and when I try to hit the application endpoint, I am getting 404,
http://localhost:9999/simple-0.0.1-SNAPSHOT/service/stuff/id
I can see in the logs that all the classes are instantiated successfully.
These are the dependencies in my pom.
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>1.18.6</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-guice</artifactId>
<scope>compile</scope>
<version>1.18.6</version>
</dependency>
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-servlet</artifactId>
<scope>compile</scope>
<version>3.0</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<scope>provided</scope>
<version>2.5</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<scope>compile</scope>
<version>14.0</version>
</dependency>
</dependencies>
Is there anything that I am missing as far as Tomcat with guice?

You're using ServletModule. Use JerseyServletModule instead.
public class SimpleServlet extends JerseyServletModule
General Cleanup options:
When I used Guice/Tomcat/Jersey 1.x I did it a bit differently. To promote flexibility you can take the path param off SimpleResource's path param and move it to the method. Also can add Singleton Annotation to the resource directly.
#Singleton
#Path("/stuff")
public class SimpleResource {
private final ManagerImpl manager;
#Inject
public SimpleResource(final ManagerImpl manager) {
this.manager = manager;
}
#GET
#Path("{id}")
#Produces(MediaType.TEXT_HTML)
public String submitData(#PathParam("id") final String id) {
String welcomeScreen = manager.getWelcomeScreen();
return "This is" + welcomeScreen + id;
}
}
Remove SimpleApplication and in configureGuiceServlet remove reflection and options map and instead do:
public class SimpleServlet extends JerseyServletModule{
#Override
protected void configureServlets() {
configureGuiceServlet();
}
private void configureGuiceServlet() {
serve("/service/*").with(GuiceContainer.class, new HashMap<String, String>());
bind(Manager.class).to(ManagerImpl.class);
}
}

Related

CDI Produces Method InjectionPoint is Null

I am leaning CDI Annotation have a question with respect to Produces Annotation:
I have a Bank
public interface Bank {
public void withdrawal();
public void deposit();
}
Two Implementation flavors
public class BankOfAmerica implements Bank {
public void withdrawal() {
System.out.println("You are withdrawing from Bank Of America");
}
public void deposit() {
System.out.println("You are depositing in Bank Of America");
}
}
public class Chase implements Bank {
public void withdrawal() {
System.out.println("You are withdrawing from Chase");
}
public void deposit() {
System.out.println("You are depositing in Chase");
}
}
A Qualifier
#Qualifier
#Retention(RUNTIME)
#Target({TYPE, METHOD, PARAMETER, FIELD})
public #interface BankProducer {
}
An Enum
public enum BankName {
DCU(DCU.class), Chase(Chase.class), BankOfAmerica(BankOfAmerica.class);
private Class<? extends Bank> bankType;
private BankName(Class<? extends Bank> bankType) {
this.bankType = bankType;
}
public Class<? extends Bank> getBankType() {
return bankType;
}
}
An Annotation to bind the BankName
#Retention(RUNTIME)
#Target({TYPE, METHOD, PARAMETER, FIELD})
public #interface BankType {
#Nonbinding
BankName value();
}
A Factory
public class BankFactory {
#Produces
#BankProducer
public Bank createBank(#Any Instance<Bank> instance, InjectionPoint injectionPoint) {
Annotated annotated = injectionPoint.getAnnotated();
BankType bankTypeAnnotation = annotated.getAnnotation(BankType.class);
Class<? extends Bank> bankType = bankTypeAnnotation.value().getBankType();
return instance.select(bankType).get();
}
}
And a JUnit
#RunWith(Arquillian.class)
public class ProducesTest {
#Inject
#BankProducer
#BankType(BankName.BankOfAmerica)
private Bank bankOfAmerica;
#Deployment
public static JavaArchive createDeployment() {
return ShrinkWrap.create(JavaArchive.class).addPackages(true, "com.tutorial.produces")
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml").merge(getDependecies());
}
private static JavaArchive getDependecies() {
JavaArchive[] javaArchives = Maven.configureResolver().loadPomFromFile("pom.xml")
.resolve("org.projectlombok:lombok").withTransitivity().as(JavaArchive.class);
JavaArchive mergedLibraries = ShrinkWrap.create(JavaArchive.class);
for (JavaArchive javaArchive : javaArchives) {
mergedLibraries.merge(javaArchive);
}
return mergedLibraries;
}
#Test
public void create() {
assertEquals(banks.getBankOfAmerica().getClass(), BankOfAmerica.class);
}
}
POM - using tomee
<dependency>
<groupId>org.apache.tomee</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0-1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.tomee</groupId>
<artifactId>arquillian-tomee-embedded</artifactId>
<version>7.0.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.shrinkwrap.resolver</groupId>
<artifactId>shrinkwrap-resolver-depchain</artifactId>
<version>2.2.2</version>
<scope>test</scope>
<type>pom</type>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
I am getting a NullPointer exception in my factory createBank method. InjectionPoint is Null. What is the issue and how do I resolve it?
Alternate Solution: Tried Weld
<dependency>
<groupId>org.jboss.weld.se</groupId>
<artifactId>weld-se</artifactId>
<version>2.2.8.Final</version>
</dependency>
JUnit
#RunWith(WeldJUnit4Runner.class)
public class ProducesWeldTest {
#Inject
#BankProducer
#BankType(BankName.BankOfAmerica)
private Bank bankOfAmerica;
#Test
public void create() {
assertEquals(bankOfAmerica.getClass(), BankOfAmerica.class);
}
}
WeldContext and WeldJUnit4Runner are from here -
http://memorynotfound.com/java-se-unit-testing-cdi-junit-jboss-weld-se/
As I already mentioned in my comment to the post, the CDI implememtatin seems to work. I think the problem lies in the test. Originally, I just wrote a simple test with a main() method and everything works. Now I moved the same code to the JUnit test and it still works. To test your implementation I just added the following client for your factory and a test class as follows:
public class BankClient {
#Inject
#BankProducer
#BankType(BankName.BankOfAmerica)
private Bank bankOfAmerica;
public void deposit() {
bankOfAmerica.deposit();
}
public void withdrawal() {
bankOfAmerica.withdrawal();
}
}
// JUnit test
public class BankServiceTest {
private static Weld weld = new Weld();
private static BankClient sut;
#BeforeClass
public static void initWeld() {
WeldContainer container = weld.initialize();;
sut = container.instance().select(BankClient.class).get();
}
#Test
public void deposit_should_be_invoked() {
sut.deposit();
}
#Test
public void withdrawal_should_be_called() {
sut.withdrawal();
}
#AfterClass
public static void shutDown() {
weld.shutdown();
}
}
After executing the test, you should see the following output on the console and JUnit green bar:
You are depositing in Bank Of America
You are withdrawing from Bank Of America

Spring state machine annotation #WithStateMachine not working

I just encounter a problem when using spring state machine #WithStateMachine.
#WithStateMachine just work when I use it on inner class which defined in the class annotated by #EnableStateMachine, but when I define class in other place it seems not work.
Here is my code:
#Configuration#EnableStateMachine public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<States, Events> {
#Override
public void configure(StateMachineStateConfigurer<States, Events> states)
throws Exception {
states
.withStates()
.initial(States.UNPAID)
.states(EnumSet.allOf(States.class));
}
#Override
public void configure(StateMachineTransitionConfigurer<States, Events> transitions)
throws Exception {
transitions
.withExternal()
.source(States.UNPAID).target(States.WAITING_FOR_RECEIVE)
.event(Events.PAY)
.and()
.withExternal()
.source(States.WAITING_FOR_RECEIVE).target(States.DONE)
.event(Events.RECEIVE);
}
#Override
public void configure(StateMachineConfigurationConfigurer<States, Events> config)
throws Exception {
config
.withConfiguration()
.autoStartup(true);
}
#WithStateMachine
public class Action {
private Logger logger = LoggerFactory.getLogger(getClass());
#OnTransition(target = "UNPAID")
public void create() {
logger.info("UNPAID");
}
#OnTransition(source = "UNPAID", target = "WAITING_FOR_RECEIVE")
public void pay() {
logger.info("WAITING_FOR_RECEIVE");
}
#OnTransition(source = "WAITING_FOR_RECEIVE", target = "DONE")
public void receive() {
logger.info("DONE");
}
}}
but when I define Action in another class file, it is not work
my pom
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>1.2.3.RELEASE</version>
</dependency><dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.3.RELEASE</version>
</dependency>
#WithStateMachine is a meta-annotation having spring #Component. Check that your Action class is either component scanned or created manually as #Bean.
Then it exist in application context and statemachine can find it.

JAX-RS test web service showing a blank web page after adding a new #PATH annotation to a new method

I am implementing a restful service in java using JAX-RS, and when testing the service it works only for one of my methods, when I add a new method with a different #PATH annotation the test web page is just blank without errors
My resource class
#Path("beer")
public class BeerResources {
#Context
private UriInfo context;
/**
* Creates a new instance of BeerResources
*/
public BeerResources() {
}
#GET
#Path("/costliest")
#Produces(MediaType.TEXT_PLAIN)
public String getCostliest() {
//TODO return proper representation object
return new BusinessLayer().getCostliest();
}
#GET
#Path("/cheapest")
#Produces(MediaType.APPLICATION_XML)
public String getCheapest() {
//TODO return proper representation object
return new BusinessLayer().getCheapest();
}
}
Application config class
#javax.ws.rs.ApplicationPath("/webresources")
public class ApplicationConfig extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new java.util.HashSet<>();
addRestResourceClasses(resources);
return resources;
}
/**
* Do not modify addRestResourceClasses() method.
* It is automatically populated with
* all resources defined in the project.
* If required, comment out calling this method in getClasses().
*/
private void addRestResourceClasses(Set<Class<?>> resources) {
resources.add(beerrestful.BeerResources.class);
}
}
You can try to use Spring Boot + JAX-RS approach or Spring Boot + Spring MVC. Here are both of them on my Github page.
Also there is Spring Boot + JAX-RS source code:
Application.java:
#SpringBootApplication
public class Application extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
public static void main(String[] args) {
SpringApplicationBuilder builder = new SpringApplicationBuilder(Application.class);
new Application().configure(builder).run(args);
}
}
DrinkEndpoint.java:
#Component
#Path("/drinks")
public class DrinkEndpoint {
#Autowired
private DrinkService drinkService;
#GET
#Path("/list")
#Produces(MediaType.APPLICATION_JSON)
public Iterable<Drink> getCostliest() {
return drinkService.getDrinks();
}
#GET
#Path("/{drink}")
#Produces(MediaType.APPLICATION_JSON)
public Response getCheapest(#PathParam("drink") String name) {
Optional<Drink> drink = drinkService.getDrink(name);
if (drink.isPresent()) {
return Response.status(201).entity(drink.get().getName()).build();
} else {
return Response.status(201).entity("NOT_FOUND").build();
}
}
}
DrinkService.java:
public interface DrinkService {
Iterable<Drink> getDrinks();
Optional<Drink> getDrink(String name);
}
DrinkServiceImpl.java:
#Component
public class DrinkServiceImpl implements DrinkService {
private List<Drink> drinks = new ArrayList<Drink>() {{
add(new Drink("Coca Cola", 1886));
add(new Drink("Pepsi", 1903));
}};
public Iterable<Drink> getDrinks() {
return drinks;
}
public Optional<Drink> getDrink(String name) {
for (Drink drink : drinks) {
if (drink.getName().equalsIgnoreCase(name)) {
return Optional.of(drink);
}
}
return Optional.empty();
}
}
ApplicationConfig.java:
#Component
public class ApplicationConfig extends ResourceConfig {
public ApplicationConfig() {
register(DrinkEndpoint.class);
}
}
Drink.java:
public class Drink {
private String name;
private int since;
public Drink(String name, int since) {
this.name = name;
this.since = since;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSince() {
return since;
}
public void setSince(int since) {
this.since = since;
}
}
pom.xml:
<project>
....
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.3.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
To start application run:
mvn spring-boot:run
Then open in browser:
http://localhost:8080/drinks/list
http://localhost:8080/drinks/pepsi
Make sure you are returning proper XML format
Example:
#Produces(MediaType.APPLICATION_XML)
public String getCheapest() {
return "<abc>xyz</abc>";
}
If BusinessLayer().getCheapest() function is returning String and you have used tag #Produces(MediaType.APPLICATION_XML) it will just show you a blank page.
Use appropriate MediaType in #Produces tag according to the value returned from BusinessLayer().getCheapest() function

Jersey JUnit Test: #WebListener ServletContextListener not invoked

I created this test in Jersey (from the docs), which works fine, with one problem: the #WebListener ServletContextListener is not being invoked.
The Resource classes that I need to test rely on an attribute set on the ServletContext by the ServletContextListener.
Can I make sure it is invoked, or can I manipulate the ServletContext in some other way?
public class SimpleTest extends JerseyTest {
#WebListener
public static class AppContextListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent event) {
System.out.println("Context initialized");
}
#Override
public void contextDestroyed(ServletContextEvent event) {
System.out.println("Context destroyed");
}
}
#Path("hello")
public static class HelloResource {
#GET
public String getHello() {
return "Hello World!";
}
}
#Override
protected Application configure() {
return new ResourceConfig(HelloResource.class);
}
#Test
public void test() {
final String hello = target("hello").request().get(String.class);
assertEquals("Hello World!", hello);
}
}
I added these dependencies to make this work:
<dependency>
<groupId>org.glassfish.jersey.test-framework</groupId>
<artifactId>jersey-test-framework-core</artifactId>
<version>2.18</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<version>2.18</version>
</dependency>
The JerseyTest needs to be set up to run in a Servlet environment, as mentioned here. Here are the good parts:
#Override
protected TestContainerFactory getTestContainerFactory() {
return new GrizzlyWebTestContainerFactory();
}
#Override
protected DeploymentContext configureDeployment() {
ResourceConfig config = new ResourceConfig(SessionResource.class);
return ServletDeploymentContext.forServlet(new ServletContainer(config))
.addListener(AppContextListener.class)
.build();
}
See the APIs for
ServletDeploymentContext and
ServletDeployementContext.Builder (which is what is returned when you call forServlet on the ServletDeploymentContext).

Weld and Java SE

I'm new to Weld and have been trying to get my head around it's concepts. I have a little experience with Spring and nothing with Guice, so I'm pretty much a novice with the DI frameworks.
Here's a tutorial that introduce CDI, but in the context of web apps. I'm interested to see how this works in Java SE alone. I have created the following classes, but have no idea how to test the ItemProcessor's execute method with the DefaultItemDao class (or any other alternative) in a Java SE app.
Here're the classes:
public class Item {
private int value;
private int limit;
public Item(int v, int l) {
value = v;
limit = l;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public int getLimit() {
return limit;
}
public void setLimit(int limit) {
this.limit = limit;
}
#Override
public String toString() {
return "Item [value=" + value + ", limit=" + limit + "]";
}
}
import java.util.List;
public interface ItemDao {
List<Item> fetchItems();
}
import java.util.ArrayList;
import java.util.List;
public class DefaultItemDao implements ItemDao {
#Override
public List<Item> fetchItems() {
List<Item> results = new ArrayList<Item>(){{
add(new Item(1,2));
add(new Item(2,3));
}};
return results;
}
}
import java.util.List;
import javax.inject.Inject;
public class ItemProcessor {
#Inject
private ItemDao itemDao;
public void execute() {
List<Item> items = itemDao.fetchItems();
for (Item item : items) {
System.out.println("Found item: "+item);
}
}
}
And I have no idea how to write a test client for the ItemProcessor class. Can someone help me understand how to write one with CDI?
Thanks, Kumar
I had same question with injection Validator using JavaSE. Finally I managed to solve it. Hope it helps someone!
Dependencies i used:
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.0.Alpha2</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator-cdi</artifactId>
<version>6.0.0.Alpha2</version>
</dependency>
<dependency>
<groupId>org.jboss.weld.se</groupId>
<artifactId>weld-se</artifactId>
<version>2.4.3.Final</version>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>javax.el</artifactId>
<version>2.2.6</version>
</dependency>
Main method:
Weld weld = new Weld().interceptors(Validator.class);
WeldContainer container = weld.initialize();
PurchaseOrderService service =
container.select(ru.code.service.PurchaseOrderService.class).get();
Customer customer = new Customer(.....);
service.createCustomer(customer);
weld.shutdown();
PurchaseOrderService.java
#Inject
private Validator validator;
private Set<ConstraintViolation<Customer>> violations;
public PurchaseOrderService() {
}
public void createCustomer(Customer customer) {
violations = validator.validate(customer);
if (violations.size() > 0) {
throw new ConstraintViolationException(violations);
}
}
And also i created beans.xml in resources/META-INF directory:
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
bean-discovery-mode="all">
</beans>

Categories