Steps to Defining a Jakarta RS Element
The following example walks through the necessary files to define a simple endpoint for CRUD (Create, Read, Update, Delete) operations for a message based service.
Step 1: Define the Element
Copy @ElementDefinition
package dev.getelements.elements.sdk.test.element.rs;
import dev.getelements.elements.sdk.annotation.ElementDefinition;
Step 2: Define the Application
Copy package dev.getelements.elements.sdk.test.element.rs;
import com.fasterxml.jackson.jakarta.rs.json.JacksonJsonProvider;
import dev.getelements.elements.sdk.annotation.ElementDefaultAttribute;
import dev.getelements.elements.sdk.annotation.ElementServiceExport;
import dev.getelements.elements.sdk.annotation.ElementServiceImplementation;
import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.core.Application;
import java.util.Set;
@ApplicationPath("/")
@ElementServiceImplementation
@ElementServiceExport(Application.class)
public class TestApplication extends Application {
@ElementDefaultAttribute("myapp")
public static final String APP_SERVE_PREFIX = "dev.getelements.elements.app.serve.prefix";
@Override
public Set<Class<?>> getClasses() {
return Set.of(
MessageEndpoint.class,
JacksonJsonProvider.class
);
}
}
Step 3: Define the Endpoint Code
Copy package dev.getelements.elements.sdk.test.element.rs;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.Response;
import java.util.Map;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.atomic.AtomicInteger;
@Path("/message")
public class MessageEndpoint {
private static final AtomicInteger counter = new AtomicInteger();
private static final Map<Integer, Message> messages = new ConcurrentSkipListMap<>();
@POST
public Response createMessage(
final CreateMessageRequest createMessageRequest) {
if (createMessageRequest.getMessage() == null) {
return Response.status(Response.Status.BAD_REQUEST).build();
}
final int id = counter.incrementAndGet();
final long now = System.currentTimeMillis();
final var message = new Message();
message.setId(id);
message.setMessage(createMessageRequest.getMessage());
message.setCreated(now);
message.setUpdated(now);
if (messages.putIfAbsent(id, message) != null) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
}
return Response
.status(Response.Status.CREATED)
.entity(message).build();
}
@PUT
@Path("{messageId}")
public Response updateMessage(
@PathParam("messageId")
final String messageId,
final UpdateMessageRequest updateMessageRequest) {
final int id;
try {
id = Integer.parseInt(messageId);
} catch (NumberFormatException ex) {
return Response.status(Response.Status.NOT_FOUND).build();
}
final var result = messages.computeIfPresent(id, (_id, existing) -> {
final var updated = new Message();
updated.setId(_id);
updated.setCreated(existing.getCreated());
updated.setUpdated(System.currentTimeMillis());
updated.setMessage(updateMessageRequest.getMessage());
return updated;
});
return result == null
? Response.status(Response.Status.NOT_FOUND).build()
: Response.status(Response.Status.OK).entity(result).build();
}
@GET
public Response getMessages() {
return Response
.status(Response.Status.OK)
.entity(messages.values())
.build();
}
@GET
@Path("{messageId}")
public Response getMessage(
@PathParam("messageId")
final String messageId) {
final int id;
try {
id = Integer.parseInt(messageId);
} catch (NumberFormatException ex) {
return Response.status(Response.Status.NOT_FOUND).build();
}
final var message = messages.get(id);
return message == null
? Response.status(Response.Status.NOT_FOUND).build()
: Response.status(Response.Status.OK).entity(message).build();
}
@DELETE
@Path("{messageId}")
public Response deleteMessage(
@PathParam("messageId")
final String messageId) {
final int id;
try {
id = Integer.parseInt(messageId);
} catch (NumberFormatException ex) {
return Response.status(Response.Status.NOT_FOUND).build();
}
final var removed = messages.remove(id);
return removed == null
? Response.status(Response.Status.NOT_FOUND).build()
: Response.status(Response.Status.NO_CONTENT).entity(removed).build();
}
}
Step 4: Ensure all Dependencies are Included
Copy <?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>dev.getelements.elements</groupId>
<artifactId>eci-elements</artifactId>
<version>2.2.0-SNAPSHOT</version>
</parent>
<artifactId>sdk-test-element-rs</artifactId>
<version>2.2.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>dev.getelements.elements</groupId>
<artifactId>sdk</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jakarta.ws.rs</groupId>
<artifactId>jakarta.ws.rs-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jakarta.rs</groupId>
<artifactId>jackson-jakarta-rs-json-provider</artifactId>
<version>2.18.3</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.6.0</version> <!-- Use the latest version -->
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/libs</outputDirectory>
<includeScope>runtime</includeScope>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>