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

This commit is contained in:
anuragkumawat
2024-01-01 21:27:05 +02:00
committed by GitHub
parent 76bde3ff46
commit 2096eac575
209 changed files with 472 additions and 222 deletions
+15
View File
@@ -0,0 +1,15 @@
## Jersey
This module contains articles about Jersey.
### Relevant Articles
- [Jersey Filters and Interceptors](https://www.baeldung.com/jersey-filters-interceptors)
- [Jersey MVC Support](https://www.baeldung.com/jersey-mvc)
- [Bean Validation in Jersey](https://www.baeldung.com/jersey-bean-validation)
- [Set a Response Body in JAX-RS](https://www.baeldung.com/jax-rs-response)
- [Exploring the Jersey Test Framework](https://www.baeldung.com/jersey-test)
- [Explore Jersey Request Parameters](https://www.baeldung.com/jersey-request-parameters)
- [Add a Header to a Jersey SSE Client Request](https://www.baeldung.com/jersey-sse-client-request-headers)
- [Exception Handling With Jersey](https://www.baeldung.com/java-exception-handling-jersey)
- [@FormDataParam vs. @FormParam in Jersey](https://www.baeldung.com/jersey-formdataparam-vs-formparam)
- [Add a List as Query Parameter in Jersey](https://www.baeldung.com/java-jersey-list-query-param)
+110
View File
@@ -0,0 +1,110 @@
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>jersey</artifactId>
<name>jersey</name>
<packaging>war</packaging>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>web-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.bundles</groupId>
<artifactId>jaxrs-ri</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-grizzly2-servlet</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-mvc-freemarker</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-bean-validation</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.security</groupId>
<artifactId>oauth1-client</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.security</groupId>
<artifactId>oauth2-client</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-sse</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.test-framework</groupId>
<artifactId>jersey-test-framework-core</artifactId>
<version>${jersey.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<version>${jersey.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.connectors</groupId>
<artifactId>jersey-apache-connector</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>${jersey.version}</version>
</dependency>
</dependencies>
<build>
<finalName>jersey</finalName>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>${maven-war-plugin.version}</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<configuration>
<mainClass>com.baeldung.jersey.server.http.EmbeddedHttpServer</mainClass>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<jersey.version>3.1.1</jersey.version>
</properties>
</project>
@@ -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");
}
}

Some files were not shown because too many files have changed in this diff Show More