When you write custom code in Elements (an Element), you’ll be using two important Java libraries: Guice and Jakarta. These libraries help structure your code, manage dependencies, and expose endpoints for your game or application.
Don’t worry if you’ve never used them before — you don’t need to be a backend expert. This overview will get you familiar with the basic concepts and show you the minimal syntax you’ll need.
Guice (Dependency Injection) #
What it is:
Google Guice is a dependency injection (DI) framework. That’s a fancy way of saying it helps you manage how different pieces of your code fit together without having to manually wire everything yourself.
Instead of writing code like this:
WeaponService service = new WeaponService(new WeaponDao());
Guice lets you declare what you need, and it will provide it for you:
@Inject
WeaponService service;
Guice figures out how to build WeaponService and its dependencies (WeaponDao) automatically.
Why it matters in Elements #
- Makes your code cleaner and less repetitive.
- You don’t have to worry about the order of object creation.
- Encourages modular, testable code.
How it looks in practice #
You declare bindings (rules for how to build classes) in a Module:
public class WeaponModule extends AbstractModule {
@Override
protected void configure() {
bind(WeaponDao.class).to(MongoWeaponDao.class);
bind(WeaponService.class);
}
}
This means: “Whenever someone asks for WeaponDao, give them a MongoWeaponDao.”
And in your service:
public class WeaponService {
private final WeaponDao dao;
@Inject
public WeaponService(WeaponDao dao) {
this.dao = dao;
}
}
You don’t create the WeaponDao yourself — Guice does it for you.
Jakarta (REST Endpoints) #
What it is:
Jakarta EE is a collection of APIs for building Java applications. In Elements, the most important part is Jakarta REST (JAX-RS). It lets you define web endpoints (APIs) with simple annotations.
Instead of writing low-level HTTP handling, you just declare methods with annotations like @GET or @POST.
Example Endpoint #
@Path("/weapons")
public class WeaponEndpoint {
private final WeaponService service =
ElementSupplier
.getElementLocal(WeaponEndpoint.class)
.get()
.getServiceLocator()
.getInstance(WeaponService.class);
@GET
@Path("/{id}")
@Produces(MediaType.APPLICATION_JSON)
public Weapon getWeapon(@PathParam("id") String id) {
return service.getWeapon(id);
}
}
What this does:
@Path("/weapons")→ Defines the base URL (/weapons).@GET→ This method runs when a GET request is made.@Path("/{id}")→ The{id}part of the URL becomes a method parameter.@Produces(MediaType.APPLICATION_JSON)→ Response will be JSON.
So if you hit:
GET app/rest/weapons/123
You’ll get back the weapon with ID 123 as JSON.
How this works: #
In Elements, Guice services don’t live in the same context as Jakarta endpoints.
That means this won’t work inside an endpoint:
@Inject
ExampleInterface example; // ❌ Won’t be injected automatically
Instead, you must use the ElementSupplier to fetch your Guice-managed services.
ElementSupplier.getElementLocal(MyEndpoint.class)→ gets the current Element context for this endpoint..getServiceLocator()→ allows you to search and instantiate service classes that have been exposed or registered to this Element..getInstance(ExampleInterface.class)→ fetches (and injects into) your service implementation.
The first time you request it, Guice will call @Inject on the implementation (ExampleInterfaceImplementation in this case). After that, the same instance is reused as per your binding scope.
Recommended Practice #
- Bind services in a Guice module (
bind(A.class).to(B.class)). - Fetch them in endpoints via
ElementSupplier. - Keep endpoints thin — let services hold most of your business logic.
- Think of endpoints as API facades, and services/DAOs as the real workhorses.
How They Work Together in Elements #
- Guice wires up your services and DAOs (your application logic).
- Jakarta exposes those services to the outside world through REST endpoints.
So you might have this flow:
- Player calls
GET app/rest/weapons/123. - Jakarta routes that request to
WeaponEndpoint. - Guice injects a
WeaponServiceinto the endpoint. WeaponServiceuses aWeaponDaoto fetch data.- Jakarta returns the result as JSON.
You just focus on your code — Guice and Jakarta take care of the plumbing.
Quick Recap #
- Guice: Handles dependencies. You declare what you need, and Guice gives it to you.
- Jakarta: Handles endpoints. You annotate classes and methods to turn them into APIs.
Together, they let you build modular, structured, and clean backend code inside Elements without worrying about low-level details.

