JAVA-29231 Move modules inside existing container modules (#15492)

This commit is contained in:
anuragkumawat
2024-01-01 11:27:05 -08:00
committed by GitHub
parent 76bde3ff46
commit 2096eac575
209 changed files with 472 additions and 222 deletions
@@ -0,0 +1,47 @@
package com.baeldung.jersey.client;
import org.glassfish.jersey.client.ClientConfig;
import com.baeldung.jersey.client.filter.RequestClientFilter;
import com.baeldung.jersey.client.filter.ResponseClientFilter;
import com.baeldung.jersey.client.interceptor.RequestClientWriterInterceptor;
import com.baeldung.jersey.server.Greetings;
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.client.Entity;
import jakarta.ws.rs.core.Response;
public class JerseyClient {
public static final String URI_GREETINGS = "http://localhost:8080/jersey/greetings";
public static String getHelloGreeting() {
return createClient().target(URI_GREETINGS)
.request()
.get(String.class);
}
public static String getHiGreeting() {
return createClient().target(URI_GREETINGS + "/hi")
.request()
.get(String.class);
}
public static Response getCustomGreeting() {
return createClient().target(URI_GREETINGS + "/custom")
.request()
.post(Entity.text("custom"));
}
private static Client createClient() {
ClientConfig config = new ClientConfig();
config.register(RequestClientFilter.class);
config.register(ResponseClientFilter.class);
config.register(RequestClientWriterInterceptor.class);
config.register(Greetings.class);
return ClientBuilder.newClient(config);
}
}
@@ -0,0 +1,192 @@
package com.baeldung.jersey.client;
import com.baeldung.jersey.client.filter.AddHeaderOnRequestFilter;
import org.glassfish.jersey.apache.connector.ApacheConnectorProvider;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
import org.glassfish.jersey.client.oauth1.AccessToken;
import org.glassfish.jersey.client.oauth1.ConsumerCredentials;
import org.glassfish.jersey.client.oauth1.OAuth1ClientSupport;
import org.glassfish.jersey.client.oauth2.OAuth2ClientSupport;
import static org.glassfish.jersey.client.authentication.HttpAuthenticationFeature.*;
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.client.Invocation;
import jakarta.ws.rs.client.WebTarget;
import jakarta.ws.rs.core.Feature;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.sse.InboundSseEvent;
import jakarta.ws.rs.sse.SseEventSource;
public class JerseyClientHeaders {
private static final String BEARER_CONSUMER_SECRET = "my-consumer-secret";
private static final String BEARER_ACCESS_TOKEN_SECRET = "my-access-token-secret";
private static final String TARGET = "http://localhost:9998/";
private static final String MAIN_RESOURCE = "echo-headers";
private static final String RESOURCE_AUTH_DIGEST = "digest";
private static String sseHeaderValue;
public static Response simpleHeader(String headerKey, String headerValue) {
Client client = ClientBuilder.newClient();
WebTarget webTarget = client.target(TARGET);
WebTarget resourceWebTarget = webTarget.path(MAIN_RESOURCE);
Invocation.Builder invocationBuilder = resourceWebTarget.request();
invocationBuilder.header(headerKey, headerValue);
return invocationBuilder.get();
}
public static Response simpleHeaderFluently(String headerKey, String headerValue) {
Client client = ClientBuilder.newClient();
return client.target(TARGET)
.path(MAIN_RESOURCE)
.request()
.header(headerKey, headerValue)
.get();
}
public static Response basicAuthenticationAtClientLevel(String username, String password) {
//To simplify we removed de SSL/TLS protection, but it's required to have an encryption
// when using basic authentication schema as it's send only on Base64 encoding
HttpAuthenticationFeature feature = HttpAuthenticationFeature.basic(username, password);
Client client = ClientBuilder.newBuilder().register(feature).build();
return client.target(TARGET)
.path(MAIN_RESOURCE)
.request()
.get();
}
public static Response basicAuthenticationAtRequestLevel(String username, String password) {
//To simplify we removed de SSL/TLS protection, but it's required to have an encryption
// when using basic authentication schema as it's send only on Base64 encoding
HttpAuthenticationFeature feature = HttpAuthenticationFeature.basicBuilder().build();
Client client = ClientBuilder.newBuilder().register(feature).build();
return client.target(TARGET)
.path(MAIN_RESOURCE)
.request()
.property(HTTP_AUTHENTICATION_BASIC_USERNAME, username)
.property(HTTP_AUTHENTICATION_BASIC_PASSWORD, password)
.get();
}
public static Response digestAuthenticationAtClientLevel(String username, String password) {
HttpAuthenticationFeature feature = HttpAuthenticationFeature.digest(username, password);
Client client = ClientBuilder.newBuilder().register(feature).build();
return client.target(TARGET)
.path(MAIN_RESOURCE)
.path(RESOURCE_AUTH_DIGEST)
.request()
.get();
}
public static Response digestAuthenticationAtRequestLevel(String username, String password) {
HttpAuthenticationFeature feature = HttpAuthenticationFeature.digest();
Client client = ClientBuilder.newBuilder().register(feature).build();
return client.target(TARGET)
.path(MAIN_RESOURCE)
.path(RESOURCE_AUTH_DIGEST)
.request()
.property(HTTP_AUTHENTICATION_DIGEST_USERNAME, username)
.property(HTTP_AUTHENTICATION_DIGEST_PASSWORD, password)
.get();
}
public static Response bearerAuthenticationWithOAuth1AtClientLevel(String token, String consumerKey) {
ConsumerCredentials consumerCredential = new ConsumerCredentials(consumerKey, BEARER_CONSUMER_SECRET);
AccessToken accessToken = new AccessToken(token, BEARER_ACCESS_TOKEN_SECRET);
Feature feature = OAuth1ClientSupport
.builder(consumerCredential)
.feature()
.accessToken(accessToken)
.build();
Client client = ClientBuilder.newBuilder().register(feature).build();
return client.target(TARGET)
.path(MAIN_RESOURCE)
.request()
.get();
}
public static Response bearerAuthenticationWithOAuth1AtRequestLevel(String token, String consumerKey) {
ConsumerCredentials consumerCredential = new ConsumerCredentials(consumerKey, BEARER_CONSUMER_SECRET);
AccessToken accessToken = new AccessToken(token, BEARER_ACCESS_TOKEN_SECRET);
Feature feature = OAuth1ClientSupport
.builder(consumerCredential)
.feature()
.build();
Client client = ClientBuilder.newBuilder().register(feature).build();
return client.target(TARGET)
.path(MAIN_RESOURCE)
.request()
.property(OAuth1ClientSupport.OAUTH_PROPERTY_ACCESS_TOKEN, accessToken)
.get();
}
public static Response bearerAuthenticationWithOAuth2AtClientLevel(String token) {
Feature feature = OAuth2ClientSupport.feature(token);
Client client = ClientBuilder.newBuilder().register(feature).build();
return client.target(TARGET)
.path(MAIN_RESOURCE)
.request()
.get();
}
public static Response bearerAuthenticationWithOAuth2AtRequestLevel(String token, String otherToken) {
Feature feature = OAuth2ClientSupport.feature(token);
Client client = ClientBuilder.newBuilder().register(feature).build();
return client.target(TARGET)
.path(MAIN_RESOURCE)
.request()
.property(OAuth2ClientSupport.OAUTH2_PROPERTY_ACCESS_TOKEN, otherToken)
.get();
}
public static Response filter() {
Client client = ClientBuilder.newBuilder().register(AddHeaderOnRequestFilter.class).build();
return client.target(TARGET)
.path(MAIN_RESOURCE)
.request()
.get();
}
public static Response sendRestrictedHeaderThroughDefaultTransportConnector(String headerKey, String headerValue) {
ClientConfig clientConfig = new ClientConfig().connectorProvider(new ApacheConnectorProvider());
Client client = ClientBuilder.newClient(clientConfig);
System.setProperty("sun.net.http.allowRestrictedHeaders", "true");
return client.target(TARGET)
.path(MAIN_RESOURCE)
.request()
.header(headerKey, headerValue)
.get();
}
public static String simpleSSEHeader() throws InterruptedException {
Client client = ClientBuilder.newBuilder()
.register(AddHeaderOnRequestFilter.class)
.build();
WebTarget webTarget = client.target(TARGET)
.path(MAIN_RESOURCE)
.path("events");
SseEventSource sseEventSource = SseEventSource.target(webTarget).build();
sseEventSource.register(JerseyClientHeaders::receiveEvent);
sseEventSource.open();
Thread.sleep(3_000);
sseEventSource.close();
return sseHeaderValue;
}
private static void receiveEvent(InboundSseEvent event) {
sseHeaderValue = event.readData();
}
}
@@ -0,0 +1,17 @@
package com.baeldung.jersey.client.filter;
import java.io.IOException;
import jakarta.ws.rs.client.ClientRequestContext;
import jakarta.ws.rs.client.ClientRequestFilter;
public class AddHeaderOnRequestFilter implements ClientRequestFilter {
public static final String FILTER_HEADER_VALUE = "filter-header-value";
public static final String FILTER_HEADER_KEY = "x-filter-header";
@Override
public void filter(ClientRequestContext requestContext) throws IOException {
requestContext.getHeaders().add(FILTER_HEADER_KEY, FILTER_HEADER_VALUE);
}
}
@@ -0,0 +1,24 @@
package com.baeldung.jersey.client.filter;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.client.ClientRequestContext;
import jakarta.ws.rs.client.ClientRequestFilter;
import jakarta.ws.rs.ext.Provider;
@Provider
public class RequestClientFilter implements ClientRequestFilter {
private static final Logger LOG = LoggerFactory.getLogger(RequestClientFilter.class);
@Override
public void filter(ClientRequestContext requestContext) throws IOException {
LOG.info("Request client filter");
requestContext.setProperty("test", "test client request filter");
}
}
@@ -0,0 +1,26 @@
package com.baeldung.jersey.client.filter;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.client.ClientRequestContext;
import jakarta.ws.rs.client.ClientResponseContext;
import jakarta.ws.rs.client.ClientResponseFilter;
import jakarta.ws.rs.ext.Provider;
@Provider
public class ResponseClientFilter implements ClientResponseFilter {
private static final Logger LOG = LoggerFactory.getLogger(ResponseClientFilter.class);
@Override
public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException {
LOG.info("Response client filter");
responseContext.getHeaders()
.add("X-Test-Client", "Test response client filter");
}
}
@@ -0,0 +1,28 @@
package com.baeldung.jersey.client.interceptor;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.ext.Provider;
import jakarta.ws.rs.ext.WriterInterceptor;
import jakarta.ws.rs.ext.WriterInterceptorContext;
@Provider
public class RequestClientWriterInterceptor implements WriterInterceptor {
private static final Logger LOG = LoggerFactory.getLogger(RequestClientWriterInterceptor.class);
@Override
public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException {
LOG.info("request writer interceptor in the client side");
context.getOutputStream()
.write(("Message added in the writer interceptor in the client side").getBytes());
context.proceed();
}
}
@@ -0,0 +1,15 @@
package com.baeldung.jersey.client.listdemo;
import java.util.List;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.QueryParam;
@Path("/")
public class JerseyListDemo {
@GET
public String getItems(@QueryParam("items") List<String> items) {
return "Received items: " + items;
}
}
@@ -0,0 +1,9 @@
package com.baeldung.jersey.client.listdemo;
import org.glassfish.jersey.server.ResourceConfig;
public class ListDemoApp extends ResourceConfig {
public ListDemoApp() {
packages("com.baeldung.jersey.client.listdemo");
}
}
@@ -0,0 +1,19 @@
package com.baeldung.jersey.exceptionhandling;
import org.glassfish.jersey.server.ResourceConfig;
import com.baeldung.jersey.exceptionhandling.rest.exceptions.IllegalArgumentExceptionMapper;
import com.baeldung.jersey.exceptionhandling.rest.exceptions.ServerExceptionMapper;
import jakarta.ws.rs.ApplicationPath;
@ApplicationPath("/exception-handling/*")
public class ExceptionHandlingConfig extends ResourceConfig {
public ExceptionHandlingConfig() {
packages("com.baeldung.jersey.exceptionhandling.rest");
register(IllegalArgumentExceptionMapper.class);
register(ServerExceptionMapper.class);
}
}
@@ -0,0 +1,33 @@
package com.baeldung.jersey.exceptionhandling.data;
import com.baeldung.jersey.exceptionhandling.repo.Identifiable;
public class Stock implements Identifiable {
private static final long serialVersionUID = 1L;
private String id;
private Double price;
public Stock() {
}
public Stock(String id, Double price) {
this.id = id;
this.price = price;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
}
@@ -0,0 +1,51 @@
package com.baeldung.jersey.exceptionhandling.data;
import com.baeldung.jersey.exceptionhandling.repo.Identifiable;
public class Wallet implements Identifiable {
private static final long serialVersionUID = 1L;
public static final Double MIN_CHARGE = 50.0;
public static final String MIN_CHARGE_MSG = "minimum charge is: " + MIN_CHARGE;
private String id;
private Double balance = 0.0;
public Wallet() {
}
public Wallet(String id) {
this.id = id;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Double getBalance() {
return balance;
}
public void setBalance(Double balance) {
this.balance = balance;
}
public Double addBalance(Double amount) {
if (balance == null)
balance = 0.0;
return balance += amount;
}
public boolean hasFunds(Double amount) {
if (balance == null || amount == null) {
return false;
}
return (balance - amount) >= 0;
}
}
@@ -0,0 +1,32 @@
package com.baeldung.jersey.exceptionhandling.repo;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
public class Db<T extends Identifiable> {
private Map<String, T> db = new HashMap<>();
public Optional<T> findById(String id) {
return Optional.ofNullable(db.get(id));
}
public String save(T t) {
String id = t.getId();
if (id == null) {
id = UUID.randomUUID()
.toString();
t.setId(id);
}
db.put(id, t);
return id;
}
public void remove(T t) {
db.entrySet()
.removeIf(entry -> entry.getValue()
.getId()
.equals(t.getId()));
}
}
@@ -0,0 +1,17 @@
package com.baeldung.jersey.exceptionhandling.repo;
import java.io.Serializable;
public interface Identifiable extends Serializable {
void setId(String id);
String getId();
public static void assertValid(Identifiable i) {
if (i == null)
throw new IllegalArgumentException("object cannot be null");
if (i.getId() == null)
throw new IllegalArgumentException("object id cannot be null");
}
}
@@ -0,0 +1,42 @@
package com.baeldung.jersey.exceptionhandling.rest;
import java.util.Optional;
import com.baeldung.jersey.exceptionhandling.data.Stock;
import com.baeldung.jersey.exceptionhandling.repo.Db;
import com.baeldung.jersey.exceptionhandling.service.Repository;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
@Path("/stocks")
public class StocksResource {
private static final Db<Stock> stocks = Repository.STOCKS_DB;
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response post(Stock stock) {
stocks.save(stock);
return Response.ok(stock)
.build();
}
@GET
@Path("/{ticker}")
@Produces(MediaType.APPLICATION_JSON)
public Response get(@PathParam("ticker") String id) {
Optional<Stock> stock = stocks.findById(id);
stock.orElseThrow(() -> new IllegalArgumentException("ticker"));
return Response.ok(stock.get())
.build();
}
}
@@ -0,0 +1,97 @@
package com.baeldung.jersey.exceptionhandling.rest;
import java.util.Optional;
import com.baeldung.jersey.exceptionhandling.data.Stock;
import com.baeldung.jersey.exceptionhandling.data.Wallet;
import com.baeldung.jersey.exceptionhandling.repo.Db;
import com.baeldung.jersey.exceptionhandling.rest.exceptions.InvalidTradeException;
import com.baeldung.jersey.exceptionhandling.rest.exceptions.RestErrorResponse;
import com.baeldung.jersey.exceptionhandling.service.Repository;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
@Path("/wallets")
public class WalletsResource {
private static final Db<Stock> stocks = Repository.STOCKS_DB;
private static final Db<Wallet> wallets = Repository.WALLETS_DB;
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response post(Wallet wallet) {
wallets.save(wallet);
return Response.ok(wallet)
.build();
}
@GET
@Path("/{id}")
@Produces(MediaType.APPLICATION_JSON)
public Response get(@PathParam("id") String id) {
Optional<Wallet> wallet = wallets.findById(id);
wallet.orElseThrow(IllegalArgumentException::new);
return Response.ok(wallet.get())
.build();
}
@PUT
@Path("/{id}/{amount}")
@Produces(MediaType.APPLICATION_JSON)
public Response putAmount(@PathParam("id") String id, @PathParam("amount") Double amount) {
Optional<Wallet> wallet = wallets.findById(id);
wallet.orElseThrow(IllegalArgumentException::new);
if (amount < Wallet.MIN_CHARGE) {
throw new InvalidTradeException(Wallet.MIN_CHARGE_MSG);
}
wallet.get()
.addBalance(amount);
wallets.save(wallet.get());
return Response.ok(wallet)
.build();
}
@POST
@Path("/{wallet}/buy/{ticker}")
@Produces(MediaType.APPLICATION_JSON)
public Response postBuyStock(@PathParam("wallet") String walletId, @PathParam("ticker") String id) {
Optional<Stock> stock = stocks.findById(id);
stock.orElseThrow(InvalidTradeException::new);
Optional<Wallet> w = wallets.findById(walletId);
w.orElseThrow(InvalidTradeException::new);
Wallet wallet = w.get();
Double price = stock.get()
.getPrice();
if (!wallet.hasFunds(price)) {
RestErrorResponse response = new RestErrorResponse();
response.setSubject(wallet);
response.setMessage("insufficient balance");
throw new WebApplicationException(Response.status(Response.Status.NOT_ACCEPTABLE)
.entity(response)
.build());
}
wallet.addBalance(-price);
wallets.save(wallet);
return Response.ok(wallet)
.build();
}
}
@@ -0,0 +1,23 @@
package com.baeldung.jersey.exceptionhandling.rest.exceptions;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
public class IllegalArgumentExceptionMapper implements ExceptionMapper<IllegalArgumentException> {
public static final String DEFAULT_MESSAGE = "an illegal argument was provided";
@Override
public Response toResponse(final IllegalArgumentException exception) {
return Response.status(Response.Status.EXPECTATION_FAILED)
.entity(build(exception.getMessage()))
.type(MediaType.APPLICATION_JSON)
.build();
}
private RestErrorResponse build(String message) {
RestErrorResponse response = new RestErrorResponse();
response.setMessage(DEFAULT_MESSAGE + ": " + message);
return response;
}
}
@@ -0,0 +1,17 @@
package com.baeldung.jersey.exceptionhandling.rest.exceptions;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.Response;
public class InvalidTradeException extends WebApplicationException {
private static final long serialVersionUID = 1L;
private static final String MESSAGE = "invalid trade operation";
public InvalidTradeException() {
super(MESSAGE, Response.Status.NOT_ACCEPTABLE);
}
public InvalidTradeException(String detail) {
super(MESSAGE + ": " + detail, Response.Status.NOT_ACCEPTABLE);
}
}
@@ -0,0 +1,34 @@
package com.baeldung.jersey.exceptionhandling.rest.exceptions;
public class RestErrorResponse {
private Object subject;
private String message;
public RestErrorResponse() {
}
public RestErrorResponse(String message) {
this.message = message;
}
public RestErrorResponse(Object subject, String message) {
this.subject = subject;
this.message = message;
}
public Object getSubject() {
return subject;
}
public void setSubject(Object subject) {
this.subject = subject;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
@@ -0,0 +1,34 @@
package com.baeldung.jersey.exceptionhandling.rest.exceptions;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
public class ServerExceptionMapper implements ExceptionMapper<WebApplicationException> {
public static final String HTTP_405_MESSAGE = "use one of";
@Override
public Response toResponse(final WebApplicationException exception) {
String message;
Response response = exception.getResponse();
Response.Status status = response.getStatusInfo()
.toEnum();
switch (status) {
case METHOD_NOT_ALLOWED:
message = HTTP_405_MESSAGE + response.getAllowedMethods();
break;
case INTERNAL_SERVER_ERROR:
message = "internal validation - " + exception;
break;
default:
message = "[unhandled response code] " + exception;
}
return Response.status(status)
.entity(status + ": " + message)
.type(MediaType.TEXT_PLAIN)
.build();
}
}
@@ -0,0 +1,10 @@
package com.baeldung.jersey.exceptionhandling.service;
import com.baeldung.jersey.exceptionhandling.data.Stock;
import com.baeldung.jersey.exceptionhandling.data.Wallet;
import com.baeldung.jersey.exceptionhandling.repo.Db;
public class Repository {
public static Db<Stock> STOCKS_DB = new Db<>();
public static Db<Wallet> WALLETS_DB = new Db<>();
}
@@ -0,0 +1,75 @@
package com.baeldung.jersey.server;
import com.baeldung.jersey.client.filter.AddHeaderOnRequestFilter;
import jakarta.annotation.security.RolesAllowed;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.sse.OutboundSseEvent;
import jakarta.ws.rs.sse.Sse;
import jakarta.ws.rs.sse.SseEventSink;
@Path("/echo-headers")
public class EchoHeaders {
static final String REALM_KEY = "realm";
static final String REALM_VALUE = "Baeldung";
static final String QOP_KEY = "qop";
static final String QOP_VALUE = "auth";
static final String NONCE_KEY = "nonce";
static final String NONCE_VALUE = "dcd98b7102dd2f0e8b11d0f600bfb0c093";
static final String OPAQUE_KEY = "opaque";
static final String OPAQUE_VALUE = "5ccc069c403ebaf9f0171e9517f40e41";
static final String SSE_HEADER_KEY = "x-sse-header-key";
@Context
HttpHeaders headers;
@GET
public Response getHeadersBack() {
return echoHeaders();
}
@RolesAllowed("ADMIN")
@GET
@Path("/digest")
public Response getHeadersBackFromDigestAuthentication() {
// As the Digest authentication require some complex steps to work we'll simulate the process
// https://en.wikipedia.org/wiki/Digest_access_authentication#Example_with_explanation
if (headers.getHeaderString("authorization") == null) {
String authenticationRequired = "Digest " + REALM_KEY + "=\"" + REALM_VALUE + "\", " + QOP_KEY + "=\"" + QOP_VALUE + "\", " + NONCE_KEY + "=\"" + NONCE_VALUE + "\", " + OPAQUE_KEY + "=\"" + OPAQUE_VALUE + "\"";
return Response.status(Response.Status.UNAUTHORIZED)
.header("WWW-Authenticate", authenticationRequired)
.build();
} else {
return echoHeaders();
}
}
@GET
@Path("/events")
@Produces(MediaType.SERVER_SENT_EVENTS)
public void getServerSentEvents(@Context SseEventSink eventSink, @Context Sse sse) {
OutboundSseEvent event = sse.newEventBuilder()
.name("echo-headers")
.data(String.class, headers.getHeaderString(AddHeaderOnRequestFilter.FILTER_HEADER_KEY))
.build();
eventSink.send(event);
}
private Response echoHeaders() {
Response.ResponseBuilder responseBuilder = Response.noContent();
headers.getRequestHeaders()
.forEach((k, v) -> {
v.forEach(value -> responseBuilder.header(k, value));
});
return responseBuilder.build();
}
}
@@ -0,0 +1,31 @@
package com.baeldung.jersey.server;
import com.baeldung.jersey.server.config.HelloBinding;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Response;
@Path("/greetings")
public class Greetings {
@GET
@HelloBinding
public String getHelloGreeting() {
return "hello";
}
@GET
@Path("/hi")
public String getHiGreeting() {
return "hi";
}
@POST
@Path("/custom")
public Response getCustomGreeting(String name) {
return Response.status(Response.Status.OK.getStatusCode())
.build();
}
}
@@ -0,0 +1,46 @@
package com.baeldung.jersey.server;
import jakarta.ws.rs.FormParam;
import jakarta.ws.rs.HeaderParam;
import jakarta.ws.rs.PathParam;
public class ItemParam {
@HeaderParam("headerParam")
private String shopKey;
@PathParam("pathParam")
private String itemId;
@FormParam("formParam")
private String price;
public String getShopKey() {
return shopKey;
}
public void setShopKey(String shopKey) {
this.shopKey = shopKey;
}
public String getItemId() {
return itemId;
}
public void setItemId(String itemId) {
this.itemId = itemId;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
@Override
public String toString() {
return "ItemParam{shopKey='" + shopKey + ", itemId='" + itemId + ", price='" + price + '}';
}
}
@@ -0,0 +1,58 @@
package com.baeldung.jersey.server;
import jakarta.ws.rs.BeanParam;
import jakarta.ws.rs.CookieParam;
import jakarta.ws.rs.FormParam;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.HeaderParam;
import jakarta.ws.rs.MatrixParam;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.QueryParam;
@Path("items")
public class Items {
@GET
@Path("/cookie")
public String readCookieParam(@CookieParam("cookieParamToRead") String cookieParamToRead) {
return "Cookie parameter value is [" + cookieParamToRead + "]";
}
@GET
@Path("/header")
public String readHeaderParam(@HeaderParam("headerParamToRead") String headerParamToRead) {
return "Header parameter value is [" + headerParamToRead + "]";
}
@GET
@Path("/path/{pathParamToRead}")
public String readPathParam(@PathParam("pathParamToRead") String pathParamToRead) {
return "Path parameter value is [" + pathParamToRead + "]";
}
@GET
@Path("/query")
public String readQueryParam(@QueryParam("queryParamToRead") String queryParamToRead) {
return "Query parameter value is [" + queryParamToRead + "]";
}
@POST
@Path("/form")
public String readFormParam(@FormParam("formParamToRead") String formParamToRead) {
return "Form parameter value is [" + formParamToRead + "]";
}
@GET
@Path("/matrix")
public String readMatrixParam(@MatrixParam("matrixParamToRead") String matrixParamToRead) {
return "Matrix parameter value is [" + matrixParamToRead + "]";
}
@POST
@Path("/bean/{pathParam}")
public String readBeanParam(@BeanParam ItemParam itemParam) {
return itemParam.toString();
}
}
@@ -0,0 +1,102 @@
package com.baeldung.jersey.server;
import com.baeldung.jersey.server.model.Person;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
@Path("/response")
public class Responder {
@GET
@Path("/ok")
public Response getOkResponse() {
String message = "This is a text response";
return Response
.status(Response.Status.OK)
.entity(message)
.build();
}
@GET
@Path("/not_ok")
public Response getNOkTextResponse() {
String message = "There was an internal server error";
return Response
.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(message)
.build();
}
@GET
@Path("/text_plain")
public Response getTextResponseTypeDefined() {
String message = "This is a plain text response";
return Response
.status(Response.Status.OK)
.entity(message)
.type(MediaType.TEXT_PLAIN)
.build();
}
@GET
@Path("/text_plain_annotation")
@Produces({ MediaType.TEXT_PLAIN })
public Response getTextResponseTypeAnnotated() {
String message = "This is a plain text response via annotation";
return Response
.status(Response.Status.OK)
.entity(message)
.build();
}
@GET
@Path("/pojo")
public Response getPojoResponse() {
Person person = new Person("Abh", "Nepal");
return Response
.status(Response.Status.OK)
.entity(person)
.build();
}
@GET
@Path("/json")
public Response getJsonResponse() {
String message = "{\"hello\": \"This is a JSON response\"}";
return Response
.status(Response.Status.OK)
.entity(message)
.type(MediaType.APPLICATION_JSON)
.build();
}
@GET
@Path("/xml")
@Produces(MediaType.TEXT_XML)
public String sayXMLHello() {
return "<?xml version=\"1.0\"?>" + "<hello> This is a xml response </hello>";
}
@GET
@Path("/html")
@Produces(MediaType.TEXT_HTML)
public String sayHtmlHello() {
return "<html> " + "<title>" + " This is a html title </title>" + "<body><h1>" + " This is a html response body " + "</body></h1>" + "</html> ";
}
}
@@ -0,0 +1,11 @@
package com.baeldung.jersey.server.config;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import jakarta.ws.rs.NameBinding;
@NameBinding
@Retention(RetentionPolicy.RUNTIME)
public @interface HelloBinding {
}
@@ -0,0 +1,25 @@
package com.baeldung.jersey.server.config;
import com.baeldung.jersey.server.Greetings;
import com.baeldung.jersey.server.filter.ResponseServerFilter;
import jakarta.ws.rs.container.DynamicFeature;
import jakarta.ws.rs.container.ResourceInfo;
import jakarta.ws.rs.core.FeatureContext;
import jakarta.ws.rs.ext.Provider;
@Provider
public class HelloDynamicBinding implements DynamicFeature {
@Override
public void configure(ResourceInfo resourceInfo, FeatureContext context) {
if (Greetings.class.equals(resourceInfo.getResourceClass()) && resourceInfo.getResourceMethod()
.getName()
.contains("HiGreeting")) {
context.register(ResponseServerFilter.class);
}
}
}
@@ -0,0 +1,14 @@
package com.baeldung.jersey.server.config;
import org.glassfish.jersey.server.ResourceConfig;
import jakarta.ws.rs.ApplicationPath;
@ApplicationPath("/*")
public class ServerConfig extends ResourceConfig {
public ServerConfig() {
packages("com.baeldung.jersey.server");
}
}
@@ -0,0 +1,16 @@
package com.baeldung.jersey.server.config;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.ServerProperties;
import org.glassfish.jersey.server.mvc.freemarker.FreemarkerMvcFeature;
public class ViewApplicationConfig extends ResourceConfig {
public ViewApplicationConfig() {
packages("com.baeldung.jersey.server");
property(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true);
property(FreemarkerMvcFeature.TEMPLATE_BASE_PATH, "templates/freemarker");
register(FreemarkerMvcFeature.class);;
}
}
@@ -0,0 +1,35 @@
package com.baeldung.jersey.server.constraints;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.regex.Pattern;
import jakarta.validation.Constraint;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import jakarta.validation.Payload;
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = { SerialNumber.Validator.class })
public @interface SerialNumber {
String message()
default "Fruit serial number is not valid";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
class Validator implements ConstraintValidator<SerialNumber, String> {
@Override
public void initialize(final SerialNumber serial) {
}
@Override
public boolean isValid(final String serial, final ConstraintValidatorContext constraintValidatorContext) {
final String serialNumRegex = "^\\d{3}-\\d{3}-\\d{4}$";
return Pattern.matches(serialNumRegex, serial);
}
}
}
@@ -0,0 +1,28 @@
package com.baeldung.jersey.server.filter;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerRequestFilter;
import jakarta.ws.rs.container.PreMatching;
import jakarta.ws.rs.ext.Provider;
@Provider
@PreMatching
public class PrematchingRequestFilter implements ContainerRequestFilter {
private static final Logger LOG = LoggerFactory.getLogger(PrematchingRequestFilter.class);
@Override
public void filter(ContainerRequestContext ctx) throws IOException {
LOG.info("prematching filter");
if (ctx.getMethod()
.equals("DELETE")) {
LOG.info("\"Deleting request");
}
}
}
@@ -0,0 +1,23 @@
package com.baeldung.jersey.server.filter;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerResponseContext;
import jakarta.ws.rs.container.ContainerResponseFilter;
public class ResponseServerFilter implements ContainerResponseFilter {
private static final Logger LOG = LoggerFactory.getLogger(ResponseServerFilter.class);
@Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
LOG.info("Response server filter");
responseContext.getHeaders()
.add("X-Test", "Filter test");
}
}
@@ -0,0 +1,36 @@
package com.baeldung.jersey.server.filter;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.baeldung.jersey.server.config.HelloBinding;
import jakarta.annotation.Priority;
import jakarta.ws.rs.Priorities;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerRequestFilter;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.Provider;
@Provider
@Priority(Priorities.AUTHORIZATION)
@HelloBinding
public class RestrictedOperationsRequestFilter implements ContainerRequestFilter {
private static final Logger LOG = LoggerFactory.getLogger(RestrictedOperationsRequestFilter.class);
@Override
public void filter(ContainerRequestContext ctx) throws IOException {
LOG.info("Restricted operations filter");
if (ctx.getLanguage() != null && "EN".equals(ctx.getLanguage()
.getLanguage())) {
LOG.info("Aborting request");
ctx.abortWith(Response.status(Response.Status.FORBIDDEN)
.entity("Cannot access")
.build());
}
}
}
@@ -0,0 +1,61 @@
package com.baeldung.jersey.server.form;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import org.glassfish.jersey.media.multipart.FormDataParam;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
@Path("form")
public class FormExampleResource
{
@GET
@Path("/example1")
@Produces({MediaType.TEXT_HTML})
public InputStream getExample1() throws Exception
{
File f = new File("src/main/resources/html/example1.html");
return new FileInputStream(f);
}
@GET
@Path("/example2")
@Produces({MediaType.TEXT_HTML})
public InputStream getExample2() throws Exception
{
File f = new File("src/main/resources/html/example2.html");
return new FileInputStream(f);
}
@POST
@Path("/example1")
public String example1(@FormParam("first_name") String firstName,
@FormParam("last_name") String lastName,
@FormParam("age") String age)
{
return "Got: First = " + firstName + ", Last = " + lastName + ", Age = " + age;
}
@POST
@Path("/example2")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public String example2(@FormDataParam("first_name") String firstName,
@FormDataParam("last_name") String lastName,
@FormDataParam("age") String age,
@FormDataParam("photo") InputStream photo)
throws Exception
{
int len;
int size = 1024;
byte[] buf;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
buf = new byte[size];
while ((len = photo.read(buf, 0, size)) != -1)
bos.write(buf, 0, len);
buf = bos.toByteArray();
return "Got: First = " + firstName + ", Last = " + lastName + ", Age = " + age + ", Photo (# of bytes) = " + buf.length;
}
}
@@ -0,0 +1,38 @@
package com.baeldung.jersey.server.http;
import java.io.IOException;
import java.net.URI;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.server.ResourceConfig;
import com.baeldung.jersey.server.config.ViewApplicationConfig;
public class EmbeddedHttpServer {
public static final URI BASE_URI = URI.create("http://localhost:8082/");
public static void main(String[] args) {
try {
final HttpServer server = GrizzlyHttpServerFactory.createHttpServer(BASE_URI, new ViewApplicationConfig(), false);
Runtime.getRuntime().addShutdownHook(new Thread(server::shutdownNow));
server.start();
System.out.println(String.format("Application started.\nTry out %s\nStop the application using CTRL+C", BASE_URI + "fruit"));
} catch (IOException ex) {
Logger.getLogger(EmbeddedHttpServer.class.getName())
.log(Level.SEVERE, null, ex);
}
}
public static HttpServer startServer(URI url) {
final ResourceConfig rc = new ResourceConfig().packages("com.baeldung.jersey.server");
return GrizzlyHttpServerFactory.createHttpServer(URI.create(url.toString()), rc);
}
}
@@ -0,0 +1,36 @@
package com.baeldung.jersey.server.interceptor;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.ext.Provider;
import jakarta.ws.rs.ext.ReaderInterceptor;
import jakarta.ws.rs.ext.ReaderInterceptorContext;
@Provider
public class RequestServerReaderInterceptor implements ReaderInterceptor {
private static final Logger LOG = LoggerFactory.getLogger(RequestServerReaderInterceptor.class);
@Override
public Object aroundReadFrom(ReaderInterceptorContext context) throws IOException, WebApplicationException {
LOG.info("Request reader interceptor in the server side");
InputStream is = context.getInputStream();
String body = new BufferedReader(new InputStreamReader(is)).lines()
.collect(Collectors.joining("\n"));
context.setInputStream(new ByteArrayInputStream((body + " message added in server reader interceptor").getBytes()));
return context.proceed();
}
}
@@ -0,0 +1,62 @@
package com.baeldung.jersey.server.model;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.Size;
import jakarta.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Fruit {
@Min(value = 10, message = "Fruit weight must be 10 or greater")
private Integer weight;
@Size(min = 5, max = 200)
private String name;
@Size(min = 5, max = 200)
private String colour;
private String serial;
public Fruit() {
}
public Fruit(String name, String colour) {
this.name = name;
this.colour = colour;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setColour(String colour) {
this.colour = colour;
}
public String getColour() {
return colour;
}
public Integer getWeight() {
return weight;
}
public void setWeight(Integer weight) {
this.weight = weight;
}
public String getSerial() {
return serial;
}
public void setSerial(String serial) {
this.serial = serial;
}
@Override
public String toString() {
return "Fruit [name: " + getName() + " colour: " + getColour() + "]";
}
}
@@ -0,0 +1,32 @@
package com.baeldung.jersey.server.model;
public class Person {
String name;
String address;
public Person(String name, String address) {
this.name = name;
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Person [name: " + getName() + " address: " + getAddress() + "]";
}
}
@@ -0,0 +1,26 @@
package com.baeldung.jersey.server.providers;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
public class FruitExceptionMapper implements ExceptionMapper<ConstraintViolationException> {
@Override
public Response toResponse(final ConstraintViolationException exception) {
return Response.status(Response.Status.BAD_REQUEST)
.entity(prepareMessage(exception))
.type("text/plain")
.build();
}
private String prepareMessage(ConstraintViolationException exception) {
final StringBuilder message = new StringBuilder();
for (ConstraintViolation<?> cv : exception.getConstraintViolations()) {
message.append(cv.getPropertyPath() + " " + cv.getMessage() + "\n");
}
return message.toString();
}
}
@@ -0,0 +1,119 @@
package com.baeldung.jersey.server.rest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.glassfish.jersey.server.mvc.ErrorTemplate;
import org.glassfish.jersey.server.mvc.Template;
import org.glassfish.jersey.server.mvc.Viewable;
import com.baeldung.jersey.server.constraints.SerialNumber;
import com.baeldung.jersey.server.model.Fruit;
import com.baeldung.jersey.service.SimpleStorageService;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.FormParam;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
@Path("/fruit")
public class FruitResource {
@GET
public Viewable get() {
return new Viewable("/index.ftl", "Fruit Index Page");
}
@GET
@Template(name = "/all.ftl")
@Path("/all")
@Produces(MediaType.TEXT_HTML)
public Map<String, Object> getAllFruit() {
final List<Fruit> fruits = new ArrayList<>();
fruits.add(new Fruit("banana", "yellow"));
fruits.add(new Fruit("apple", "red"));
fruits.add(new Fruit("kiwi", "green"));
final Map<String, Object> model = new HashMap<String, Object>();
model.put("items", fruits);
return model;
}
@GET
@ErrorTemplate(name = "/error.ftl")
@Template(name = "/named.ftl")
@Path("{name}")
@Produces(MediaType.TEXT_HTML)
public String getFruitByName(@PathParam("name") String name) {
if (!"banana".equalsIgnoreCase(name)) {
throw new IllegalArgumentException("Fruit not found: " + name);
}
return name;
}
@POST
@Path("/create")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public void createFruit(
@NotNull(message = "Fruit name must not be null") @FormParam("name") String name,
@NotNull(message = "Fruit colour must not be null") @FormParam("colour") String colour) {
Fruit fruit = new Fruit(name, colour);
SimpleStorageService.storeFruit(fruit);
}
@PUT
@Path("/update")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public void updateFruit(@SerialNumber @FormParam("serial") String serial) {
Fruit fruit = new Fruit();
fruit.setSerial(serial);
SimpleStorageService.storeFruit(fruit);
}
@POST
@Path("/create")
@Consumes(MediaType.APPLICATION_JSON)
public void createFruit(@Valid Fruit fruit) {
SimpleStorageService.storeFruit(fruit);
}
@POST
@Path("/created")
@Consumes(MediaType.APPLICATION_JSON)
public Response createNewFruit(@Valid Fruit fruit) {
String result = "Fruit saved : " + fruit;
return Response.status(Response.Status.CREATED.getStatusCode())
.entity(result)
.build();
}
@GET
@Valid
@Produces(MediaType.APPLICATION_JSON)
@Path("/search/{name}")
public Fruit findFruitByName(@PathParam("name") String name) {
return SimpleStorageService.findByName(name);
}
@GET
@Produces(MediaType.TEXT_HTML)
@Path("/exception")
@Valid
public Fruit exception() {
Fruit fruit = new Fruit();
fruit.setName("a");
fruit.setColour("b");
return fruit;
}
}
@@ -0,0 +1,25 @@
package com.baeldung.jersey.service;
import java.util.HashMap;
import java.util.Map;
import com.baeldung.jersey.server.model.Fruit;
public class SimpleStorageService {
private static final Map<String, Fruit> fruits = new HashMap<>();
public static void storeFruit(final Fruit fruit) {
fruits.put(fruit.getName(), fruit);
}
public static Fruit findByName(final String name) {
return fruits.entrySet()
.stream()
.filter(map -> name.equals(map.getKey()))
.map(Map.Entry::getValue)
.findFirst()
.get();
}
}
@@ -0,0 +1,16 @@
<html>
<head>
<title>Example 1 using @FormParam</title>
</head>
<body>
<form method="post" action="/form/example1">
<label for="first_name">First Name</label>
<input id="first_name" name="first_name" type="text">
<label for="last_name">Last Name</label>
<input id="last_name" name="last_name" type="text">
<label for="age">Age</label>
<input id="age" name="age" type="text">
<input type="submit">
</form>
</body>
</html>
@@ -0,0 +1,18 @@
<html>
<head>
<title>Example 2 using @FormDataParam</title>
</head>
<body>
<form method="post" action="/form/example2" enctype="multipart/form-data">
<label for="first_name">First Name</label>
<input id="first_name" name="first_name" type="text">
<label for="last_name">Last Name</label>
<input id="last_name" name="last_name" type="text">
<label for="age">Age</label>
<input id="age" name="age" type="text">
<label for="photo">Profile Photo</label>
<input id="photo" name="photo" type="file">
<input type="submit">
</form>
</body>
</html>
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>
@@ -0,0 +1,14 @@
<html>
<head>
<title>All fruit!</title>
</head>
<body>
<h1>All fruit!</h1>
<p>Fruits:</p>
<ul>
<#list items as fruit>
<li>${fruit.name}</li>
</#list>
</ul>
</body>
</html>
@@ -0,0 +1,8 @@
<html>
<head>
<title>Welcome!</title>
</head>
<body>
<h1>Error - ${model.message}!</h1>
</body>
</html>
@@ -0,0 +1,8 @@
<html>
<head>
<title>Welcome!</title>
</head>
<body>
<h1>Welcome ${model}!</h1>
</body>
</html>
@@ -0,0 +1,8 @@
<html>
<head>
<title>Welcome!</title>
</head>
<body>
<h1>Found fruit - ${model}!</h1>
</body>
</html>
@@ -0,0 +1,53 @@
package com.baeldung.jersey.client;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.net.URI;
import org.glassfish.grizzly.http.server.HttpServer;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import com.baeldung.jersey.server.http.EmbeddedHttpServer;
import jakarta.ws.rs.core.Response;
public class JerseyClientIntegrationTest {
private static int HTTP_OK = 200;
private static HttpServer httpServer;
@BeforeAll
public static void beforeAllTests() {
httpServer = EmbeddedHttpServer.startServer(URI.create("http://localhost:8080/jersey"));
}
@AfterAll
public static void afterAllTests() {
httpServer.stop();
}
@Test
public void givenGreetingResource_whenCallingHelloGreeting_thenHelloReturned() {
String response = JerseyClient.getHelloGreeting();
assertEquals("hello", response);
}
@Test
public void givenGreetingResource_whenCallingHiGreeting_thenHiReturned() {
String response = JerseyClient.getHiGreeting();
assertEquals("hi", response);
}
@Test
public void givenGreetingResource_whenCallingCustomGreeting_thenCustomGreetingReturned() {
Response response = JerseyClient.getCustomGreeting();
assertEquals(HTTP_OK, response.getStatus());
}
}
@@ -0,0 +1,57 @@
package com.baeldung.jersey.client.listdemo;
import static org.junit.Assert.assertEquals;
import java.net.URI;
import java.util.Arrays;
import java.util.List;
import org.glassfish.jersey.test.JerseyTest;
import org.glassfish.jersey.test.TestProperties;
import org.junit.Test;
import jakarta.ws.rs.core.Application;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.UriBuilder;
public class JerseyListDemoUnitTest extends JerseyTest {
@Override
protected Application configure() {
enable(TestProperties.LOG_TRAFFIC);
enable(TestProperties.DUMP_ENTITY);
return new ListDemoApp();
}
@Test
public void givenList_whenUsingQueryParam_thenPassParamsAsList() {
Response response = target("/")
.queryParam("items", "item1", "item2")
.request()
.get();
assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
assertEquals("Received items: [item1, item2]", response.readEntity(String.class));
}
@Test
public void givenList_whenUsingCommaSeparatedString_thenPassParamsAsList() {
Response response = target("/")
.queryParam("items", "item1,item2")
.request()
.get();
assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
assertEquals("Received items: [item1,item2]", response.readEntity(String.class));
}
@Test
public void givenList_whenUsingUriBuilder_thenPassParamsAsList() {
List<String> itemsList = Arrays.asList("item1", "item2");
UriBuilder builder = UriBuilder.fromUri("/");
for (String item : itemsList) {
builder.queryParam("items", item);
}
URI uri = builder.build();
String expectedUri = "/?items=item1&items=item2";
assertEquals(expectedUri, uri.toString());
}
}
@@ -0,0 +1,105 @@
package com.baeldung.jersey.exceptionhandling.rest;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.startsWith;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.HashMap;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.glassfish.jersey.test.TestProperties;
import org.junit.jupiter.api.Test;
import com.baeldung.jersey.exceptionhandling.data.Stock;
import com.baeldung.jersey.exceptionhandling.data.Wallet;
import com.baeldung.jersey.exceptionhandling.rest.exceptions.IllegalArgumentExceptionMapper;
import com.baeldung.jersey.exceptionhandling.rest.exceptions.RestErrorResponse;
import com.baeldung.jersey.exceptionhandling.rest.exceptions.ServerExceptionMapper;
import jakarta.ws.rs.client.Entity;
import jakarta.ws.rs.client.Invocation;
import jakarta.ws.rs.core.Application;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
public class StocksResourceIntegrationTest extends JerseyTest {
private static final Entity<String> EMPTY_BODY = Entity.json("");
private static final Stock STOCK = new Stock("BAEL", 51.57);
private static final String MY_WALLET = "MY-WALLET";
private static final Wallet WALLET = new Wallet(MY_WALLET);
private static final int INSUFFICIENT_AMOUNT = (int) (Wallet.MIN_CHARGE - 1);
@Override
protected Application configure() {
final ResourceConfig resourceConfig = new ResourceConfig();
resourceConfig.register(StocksResource.class);
resourceConfig.register(WalletsResource.class);
resourceConfig.register(IllegalArgumentExceptionMapper.class);
resourceConfig.register(ServerExceptionMapper.class);
resourceConfig.packages("com.baeldung.jersey.exceptionhandling.rest");
return resourceConfig;
}
private Invocation.Builder stocks(String path) {
return target("/stocks" + path).request();
}
private Invocation.Builder wallets(String path, Object... args) {
return target("/wallets" + String.format(path, args)).request();
}
private Entity<?> entity(Object object) {
return Entity.entity(object, MediaType.APPLICATION_JSON_TYPE);
}
@Test
public void whenMethodNotAllowed_thenCustomMessage() {
Response response = stocks("").get();
assertEquals(Response.Status.METHOD_NOT_ALLOWED.getStatusCode(), response.getStatus());
String content = response.readEntity(String.class);
assertThat(content, containsString(ServerExceptionMapper.HTTP_405_MESSAGE));
}
@Test
public void whenTickerNotExists_thenRestErrorResponse() {
Response response = stocks("/TEST").get();
assertEquals(Response.Status.EXPECTATION_FAILED.getStatusCode(), response.getStatus());
RestErrorResponse content = response.readEntity(RestErrorResponse.class);
assertThat(content.getMessage(), startsWith(IllegalArgumentExceptionMapper.DEFAULT_MESSAGE));
}
@Test
public void givenAmountLessThanMinimum_whenAddingToWallet_thenInvalidTradeException() {
wallets("").post(entity(WALLET));
Response response = wallets("/%s/%d", MY_WALLET, INSUFFICIENT_AMOUNT).put(EMPTY_BODY);
assertEquals(Response.Status.NOT_ACCEPTABLE.getStatusCode(), response.getStatus());
String content = response.readEntity(String.class);
assertThat(content, containsString(Wallet.MIN_CHARGE_MSG));
}
@Test
public void givenInsifficientFunds_whenBuyingStock_thenWebApplicationException() {
stocks("").post(entity(STOCK));
wallets("").post(entity(WALLET));
Response response = wallets("/%s/buy/%s", MY_WALLET, STOCK.getId()).post(EMPTY_BODY);
assertEquals(Response.Status.NOT_ACCEPTABLE.getStatusCode(), response.getStatus());
RestErrorResponse content = response.readEntity(RestErrorResponse.class);
assertNotNull(content.getSubject());
HashMap<?, ?> subject = (HashMap<?, ?>) content.getSubject();
assertEquals(subject.get("id"), WALLET.getId());
assertTrue(WALLET.getBalance() < Wallet.MIN_CHARGE);
}
}
@@ -0,0 +1,197 @@
package com.baeldung.jersey.server;
import com.baeldung.jersey.client.JerseyClientHeaders;
import com.baeldung.jersey.client.filter.AddHeaderOnRequestFilter;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import jakarta.ws.rs.core.Application;
import jakarta.ws.rs.core.Response;
public class EchoHeadersIntegrationTest extends JerseyTest {
private static final String SIMPLE_HEADER_KEY = "my-header-key";
private static final String SIMPLE_HEADER_VALUE = "my-header-value";
private static final String USERNAME = "baeldung";
private static final String PASSWORD = "super-secret";
private static final String AUTHORIZATION_HEADER_KEY = "authorization";
private static final String BEARER_TOKEN_VALUE = "my-token";
private static final String BEARER_CONSUMER_KEY_VALUE = "my-consumer-key";
private static final String BEARER_REQUEST_TOKEN_VALUE = "my-request-token";
@Test
public void whenCallingSimpleHeader_thenHeadersReturnedBack() {
Response response = JerseyClientHeaders.simpleHeader(SIMPLE_HEADER_KEY, SIMPLE_HEADER_VALUE);
assertEquals(response.getHeaderString(SIMPLE_HEADER_KEY), SIMPLE_HEADER_VALUE);
}
@Test
public void whenCallingSimpleHeaderFluently_thenHeadersReturnedBack() {
Response response = JerseyClientHeaders.simpleHeaderFluently(SIMPLE_HEADER_KEY, SIMPLE_HEADER_VALUE);
assertEquals(response.getHeaderString(SIMPLE_HEADER_KEY), SIMPLE_HEADER_VALUE);
}
@Test
public void whenCallingBasicAuthenticationAtClientLevel_thenHeadersReturnedBack() {
Response response = JerseyClientHeaders.basicAuthenticationAtClientLevel(USERNAME, PASSWORD);
assertBasicAuthenticationHeaders(response);
}
@Test
public void whenCallingBasicAuthenticationAtRequestLevel_thenHeadersReturnedBack() {
Response response = JerseyClientHeaders.basicAuthenticationAtRequestLevel(USERNAME, PASSWORD);
assertBasicAuthenticationHeaders(response);
}
@Test
public void whenCallingDigestAuthenticationAtClientLevel_thenHeadersReturnedBack() {
Response response = JerseyClientHeaders.digestAuthenticationAtClientLevel(USERNAME, PASSWORD);
Map<String, String> subHeadersMap = parseAuthenticationSubHeader(response, 7);
assertDigestAuthenticationHeaders(subHeadersMap);
}
@Test
public void whenCallingDigestAuthenticationAtRequestLevel_thenHeadersReturnedBack() {
Response response = JerseyClientHeaders.digestAuthenticationAtRequestLevel(USERNAME, PASSWORD);
Map<String, String> subHeadersMap = parseAuthenticationSubHeader(response, 7);
assertDigestAuthenticationHeaders(subHeadersMap);
}
@Test
public void whenCallingBearerAuthenticationWithOAuth1AtClientLevel_thenHeadersReturnedBack() {
Response response = JerseyClientHeaders.bearerAuthenticationWithOAuth1AtClientLevel(BEARER_TOKEN_VALUE, BEARER_CONSUMER_KEY_VALUE);
Map<String, String> subHeadersMap = parseAuthenticationSubHeader(response, 6);
assertBearerAuthenticationHeaders(subHeadersMap);
}
@Test
public void whenCallingBearerAuthenticationWithOAuth1AtRequestLevel_thenHeadersReturnedBack() {
Response response = JerseyClientHeaders.bearerAuthenticationWithOAuth1AtRequestLevel(BEARER_TOKEN_VALUE, BEARER_CONSUMER_KEY_VALUE);
Map<String, String> subHeadersMap = parseAuthenticationSubHeader(response, 6);
assertBearerAuthenticationHeaders(subHeadersMap);
}
@Test
public void whenCallingBearerAuthenticationWithOAuth2AtClientLevel_thenHeadersReturnedBack() {
Response response = JerseyClientHeaders.bearerAuthenticationWithOAuth2AtClientLevel(BEARER_TOKEN_VALUE);
assertEquals("Bearer " + BEARER_TOKEN_VALUE, response.getHeaderString(AUTHORIZATION_HEADER_KEY));
}
@Test
public void whenCallingBearerAuthenticationWithOAuth2AtRequestLevel_thenHeadersReturnedBack() {
Response response = JerseyClientHeaders.bearerAuthenticationWithOAuth2AtRequestLevel(BEARER_TOKEN_VALUE, BEARER_REQUEST_TOKEN_VALUE);
assertEquals("Bearer " + BEARER_REQUEST_TOKEN_VALUE, response.getHeaderString(AUTHORIZATION_HEADER_KEY));
}
@Test
public void whenCallingFilter_thenHeadersReturnedBack() {
Response response = JerseyClientHeaders.filter();
assertEquals(AddHeaderOnRequestFilter.FILTER_HEADER_VALUE, response.getHeaderString(AddHeaderOnRequestFilter.FILTER_HEADER_KEY));
}
@Test
public void whenCallingSendRestrictedHeaderThroughDefaultTransportConnector_thenHeadersReturnedBack() {
Response response = JerseyClientHeaders.sendRestrictedHeaderThroughDefaultTransportConnector("keep-alive", "keep-alive-value");
assertEquals("keep-alive-value", response.getHeaderString("keep-alive"));
}
@Test
public void whenCallingSimpleSSEHeader_thenHeadersReturnedBack() throws InterruptedException {
String sseHeaderBackValue = JerseyClientHeaders.simpleSSEHeader();
assertEquals(AddHeaderOnRequestFilter.FILTER_HEADER_VALUE, sseHeaderBackValue);
}
private void assertBearerAuthenticationHeaders(Map<String, String> subHeadersMap) {
assertEquals(BEARER_TOKEN_VALUE, subHeadersMap.get("oauth_token"));
assertEquals(BEARER_CONSUMER_KEY_VALUE, subHeadersMap.get("oauth_consumer_key"));
assertNotNull(subHeadersMap.get("oauth_nonce"));
assertNotNull(subHeadersMap.get("oauth_signature"));
assertNotNull(subHeadersMap.get("oauth_callback"));
assertNotNull(subHeadersMap.get("oauth_signature_method"));
assertNotNull(subHeadersMap.get("oauth_version"));
assertNotNull(subHeadersMap.get("oauth_timestamp"));
}
private void assertDigestAuthenticationHeaders(Map<String, String> subHeadersMap) {
assertEquals(EchoHeaders.NONCE_VALUE, subHeadersMap.get(EchoHeaders.NONCE_KEY));
assertEquals(EchoHeaders.OPAQUE_VALUE, subHeadersMap.get(EchoHeaders.OPAQUE_KEY));
assertEquals(EchoHeaders.QOP_VALUE, subHeadersMap.get(EchoHeaders.QOP_KEY));
assertEquals(EchoHeaders.REALM_VALUE, subHeadersMap.get(EchoHeaders.REALM_KEY));
assertEquals(USERNAME, subHeadersMap.get("username"));
assertEquals("/echo-headers/digest", subHeadersMap.get("uri"));
assertNotNull(subHeadersMap.get("cnonce"));
assertEquals("00000001", subHeadersMap.get("nc"));
assertNotNull(subHeadersMap.get("response"));
}
private Map<String, String> parseAuthenticationSubHeader(Response response, int startAt) {
String authorizationHeader = response.getHeaderString(AUTHORIZATION_HEADER_KEY);
// The substring(startAt) is used to cut off the authentication schema part from the value returned.
String[] subHeadersKeyValue = authorizationHeader.substring(startAt).split(",");
Map<String, String> subHeadersMap = new HashMap<>();
for (String subHeader : subHeadersKeyValue) {
String[] keyValue = subHeader.split("=");
if (keyValue[1].startsWith("\"")) {
keyValue[1] = keyValue[1].substring(1, keyValue[1].length() - 1);
}
subHeadersMap.put(keyValue[0].trim(), keyValue[1].trim());
}
return subHeadersMap;
}
private void assertBasicAuthenticationHeaders(Response response) {
String base64Credentials = response.getHeaderString(AUTHORIZATION_HEADER_KEY);
// The substring(6) is used to cut the "Basic " part of the value returned,
// as it's used to indicates the authentication schema and does not belong to the credentials
byte[] credentials = Base64.getDecoder().decode(base64Credentials.substring(6));
String[] credentialsParsed = new String(credentials).split(":");
assertEquals(credentialsParsed[0], USERNAME);
assertEquals(credentialsParsed[1], PASSWORD);
}
@Override
protected Application configure() {
return new ResourceConfig()
.register(EchoHeaders.class);
}
@Override
public void setUp() throws Exception {
super.setUp();
// We need this definition here, because if you are running
// the complete suit test the sendingRestrictedHeaderThroughDefaultTransportConnector_shouldReturnThanBack
// will fail if only defined on the client method, since the JerseyTest is created once.
System.setProperty("sun.net.http.allowRestrictedHeaders", "true");
}
}
@@ -0,0 +1,32 @@
package com.baeldung.jersey.server;
import static org.junit.Assert.assertEquals;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
import jakarta.ws.rs.core.Application;
import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
public class GreetingsResourceIntegrationTest extends JerseyTest {
@Override
protected Application configure() {
return new ResourceConfig(Greetings.class);
}
@Test
public void givenGetHiGreeting_whenCorrectRequest_thenResponseIsOkAndContainsHi() {
Response response = target("/greetings/hi").request()
.get();
assertEquals("Http Response should be 200: ", Response.Status.OK.getStatusCode(), response.getStatus());
assertEquals("Http Content-Type should be: ", MediaType.TEXT_HTML, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
String content = response.readEntity(String.class);
assertEquals("Content of ressponse is: ", "hi", content);
}
}
@@ -0,0 +1,53 @@
package com.baeldung.jersey.server;
import static com.baeldung.jersey.server.http.EmbeddedHttpServer.BASE_URI;
import static org.junit.Assert.assertEquals;
import org.glassfish.grizzly.http.server.HttpServer;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.baeldung.jersey.server.http.EmbeddedHttpServer;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.client.WebTarget;
public class ItemsUnitTest {
private HttpServer server;
private WebTarget target;
@Before
public void setUp() {
server = EmbeddedHttpServer.startServer(BASE_URI);
target = ClientBuilder.newClient().target(BASE_URI.toString());
}
@After
public void tearDown() {
server.stop();
}
@Test
public void givenCookieParameter_whenGet_thenReturnsExpectedText() {
String paramValue = "1";
String responseText = target.path("items/cookie").request().cookie("cookieParamToRead", paramValue).get(String.class);
assertEquals("Cookie parameter value is [" + paramValue + "]", responseText);
}
@Test
public void givenHeaderParameter_whenGet_thenReturnsExpectedText() {
String paramValue = "2";
String responseText = target.path("items/header").request().header("headerParamToRead", paramValue).get(String.class);
assertEquals("Header parameter value is [" + paramValue + "]", responseText);
}
@Test
public void givenPathParameter_whenGet_thenReturnsExpectedText() {
String paramValue = "3";
String responseText = target.path("items/path/" + paramValue).request().get(String.class);
assertEquals("Path parameter value is [" + paramValue + "]", responseText);
}
}
@@ -0,0 +1,144 @@
package com.baeldung.jersey.server.rest;
import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import org.glassfish.jersey.test.JerseyTest;
import org.glassfish.jersey.test.TestProperties;
import org.junit.Test;
import com.baeldung.jersey.server.config.ViewApplicationConfig;
import com.baeldung.jersey.server.model.Fruit;
import com.baeldung.jersey.server.providers.FruitExceptionMapper;
import jakarta.ws.rs.client.Entity;
import jakarta.ws.rs.core.Application;
import jakarta.ws.rs.core.Form;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
public class FruitResourceIntegrationTest extends JerseyTest {
@Override
protected Application configure() {
enable(TestProperties.LOG_TRAFFIC);
enable(TestProperties.DUMP_ENTITY);
forceSet(TestProperties.CONTAINER_PORT, "0");
ViewApplicationConfig config = new ViewApplicationConfig();
config.register(FruitExceptionMapper.class);
return config;
}
@Test
public void givenGetAllFruit_whenCorrectRequest_thenAllTemplateInvoked() {
final String response = target("/fruit/all").request()
.get(String.class);
assertThat(response, allOf(containsString("banana"), containsString("apple"), containsString("kiwi")));
}
@Test
public void givenGetFruit_whenCorrectRequest_thenIndexTemplateInvoked() {
final String response = target("/fruit").request()
.get(String.class);
assertThat(response, containsString("Welcome Fruit Index Page!"));
}
@Test
public void givenGetFruitByName_whenFruitUnknown_thenErrorTemplateInvoked() {
final String response = target("/fruit/orange").request()
.get(String.class);
assertThat(response, containsString("Error - Fruit not found: orange!"));
}
@Test
public void givenCreateFruit_whenFormContainsNullParam_thenResponseCodeIsBadRequest() {
Form form = new Form();
form.param("name", "apple");
form.param("colour", null);
Response response = target("fruit/create").request(MediaType.APPLICATION_FORM_URLENCODED)
.post(Entity.form(form));
assertEquals("Http Response should be 400 ", 400, response.getStatus());
assertThat(response.readEntity(String.class), containsString("Fruit colour must not be null"));
}
@Test
public void givenCreateFruit_whenJsonIsCorrect_thenResponseCodeIsCreated() {
Response response = target("fruit/created").request()
.post(Entity.json("{\"name\":\"strawberry\",\"weight\":20}"));
assertEquals("Http Response should be 201 ", Response.Status.CREATED.getStatusCode(), response.getStatus());
assertThat(response.readEntity(String.class), containsString("Fruit saved : Fruit [name: strawberry colour: null]"));
}
@Test
public void givenUpdateFruit_whenFormContainsBadSerialParam_thenResponseCodeIsBadRequest() {
Form form = new Form();
form.param("serial", "2345-2345");
Response response = target("fruit/update").request(MediaType.APPLICATION_FORM_URLENCODED)
.put(Entity.form(form));
assertEquals("Http Response should be 400 ", 400, response.getStatus());
assertThat(response.readEntity(String.class), containsString("Fruit serial number is not valid"));
}
@Test
public void givenCreateFruit_whenFruitIsInvalid_thenResponseCodeIsBadRequest() {
Fruit fruit = new Fruit("Blueberry", "purple");
fruit.setWeight(1);
Response response = target("fruit/create").request(MediaType.APPLICATION_JSON_TYPE)
.post(Entity.entity(fruit, MediaType.APPLICATION_JSON_TYPE));
assertEquals("Http Response should be 400 ", 400, response.getStatus());
assertThat(response.readEntity(String.class), containsString("Fruit weight must be 10 or greater"));
}
@Test
public void givenFruitExists_whenSearching_thenResponseContainsFruit() {
Fruit fruit = new Fruit();
fruit.setName("strawberry");
fruit.setWeight(20);
Response response = target("fruit/create").request(MediaType.APPLICATION_JSON_TYPE)
.post(Entity.entity(fruit, MediaType.APPLICATION_JSON_TYPE));
assertEquals("Http Response should be 204 ", 204, response.getStatus());
final String json = target("fruit/search/strawberry").request()
.get(String.class);
assertThat(json, containsString("{\"name\":\"strawberry\",\"weight\":20}"));
}
@Test
public void givenFruitExists_whenSearching_thenResponseContainsFruitEntity() {
Fruit fruit = new Fruit();
fruit.setName("strawberry");
fruit.setWeight(20);
Response response = target("fruit/create").request(MediaType.APPLICATION_JSON_TYPE)
.post(Entity.entity(fruit, MediaType.APPLICATION_JSON_TYPE));
assertEquals("Http Response should be 204 ", 204, response.getStatus());
final Fruit entity = target("fruit/search/strawberry").request()
.get(Fruit.class);
assertEquals("Fruit name: ", "strawberry", entity.getName());
assertEquals("Fruit weight: ", Integer.valueOf(20), entity.getWeight());
}
@Test
public void givenFruit_whenFruitIsInvalid_thenReponseContainsCustomExceptions() {
final Response response = target("fruit/exception").request()
.get();
assertEquals("Http Response should be 400 ", 400, response.getStatus());
String responseString = response.readEntity(String.class);
assertThat(responseString, containsString("exception.<return value>.colour size must be between 5 and 200"));
assertThat(responseString, containsString("exception.<return value>.name size must be between 5 and 200"));
}
}