Add @ConfigProperties prefix-scoped config binding with RestContext pilot (TODO-311) Introduces @ConfigProperties(prefix=...) and its underlying ConfigPropertiesBinder engine in juneau-commons -- Juneau's analog of Spring's @ConfigurationProperties -- which binds an entire property prefix onto a POJO's fields in one pass using relaxed key matching, the same source-chain precedence @Value already documents, and recursive nesting under sub-prefixes. Resolution is wired into BeanInstantiator between field injection and @PostConstruct via a new ClassInfo.inject(bean, store, Runnable) seam, with the bound instance auto-registered into the bean store as a non-clobbering default supplier. Fields owned by @Value/@Inject are never touched by the whole-object bind. As the pilot, RestContext's 15 same-prefix RestContext.* env-driven-default @Value fields collapse into a single public RestContextProperties bean reachable via RestContext.getRestContextProperties(); the bean carries raw strings and RestContext retains ownership of SVL resolution and typing so every existing public getter keeps its exact signature and @Rest-blending behavior. The uriAuthority/uriContext Optional<String> pair and the unrelated juneau.restLogger.level setting remain plain @Value fields. One intentional behavior change: a present-but-empty boolean RestContext.* value now resolves leniently to false instead of throwing. Also includes incidental test-suite cleanups (resource-leak suppressions matching the codebase idiom, ExecutorService shutdown, an unused import) and a Brain-Method suppression on the pre-existing findBuilderType() multi-strategy resolver. Co-authored-by: Cursor <cursoragent@cursor.com>
📢 Documentation Update
This README has been updated to reflect our new Docusaurus-based documentation site. For the most current documentation, please visit the official Apache Juneau website.
Apache Juneau™ is a single cohesive Java ecosystem consisting of a comprehensive toolkit for marshalling POJOs to a wide variety of content types using a common framework, along with universal REST server and client APIs for creating Swagger-based self-documenting REST interfaces.
Note: The documentation is automatically updated and provides the most current project information.
Apache Juneau™ excels in the following scenarios:
<dependency> <groupId>org.apache.juneau</groupId> <artifactId>juneau-shaded-all</artifactId> <version>9.1.0</version> </dependency>
import org.apache.juneau.json.*; public class QuickStart { public static void main(String[] args) { // Create a simple POJO Person person = new Person("John", 30); // Serialize to JSON String json = Json.of(person); System.out.println(json); // Output: {"name":"John","age":30} } public static class Person { public String name; public int age; public Person(String name, int age) { this.name = name; this.age = age; } } }
// Parse JSON back to POJO Person parsed = Json.to(json, Person.class); System.out.println(parsed.name); // Output: John
import org.apache.juneau.rest.*; import org.apache.juneau.rest.servlet.*; @Rest( title="Hello World API", description="Simple REST API example" ) public class HelloWorldResource extends BasicRestServlet { @RestGet("/hello/{name}") public String sayHello(@Path String name) { return "Hello " + name + "!"; } @RestGet("/person") public Person getPerson() { return new Person("Jane", 25); } }
import org.apache.juneau.rest.mock.*; public class ApiTest { @Test public void testHello() throws Exception { String response = MockRestClient .create(HelloWorldResource.class) .json5() .build() .get("/hello/World") .run() .assertStatus().is(200) .getContent().asString(); assertEquals("Hello World!", response); } }
That's it! You now have:
juneau-config for INI-style configsjuneau-rest-server-springbootimport org.apache.juneau.xml.*; // Serialize to XML String xml = Xml.of(person); System.out.println(xml); // Output: <object><name>John</name><age>30</age></object> // Parse XML back to POJO Person parsed = Xml.to(xml, Person.class);
import org.apache.juneau.html.*; // Serialize to HTML table String html = Html.of(person); System.out.println(html); // Output: <table><tr><th>name</th><td>John</td></tr><tr><th>age</th><td>30</td></tr></table>
import org.apache.juneau.config.*; // Create configuration Config config = Config.create() .set("database.host", "localhost") .set("database.port", 5432) .set("features.enabled", true) .build(); // Read configuration String host = config.get("database.host"); int port = config.get("database.port", Integer.class); boolean enabled = config.get("features.enabled", Boolean.class);
import org.apache.juneau.rest.client.*; import org.apache.juneau.http.*; // Define REST interface @Remote("http://api.example.com") public interface UserService { @Get("/users/{id}") User getUser(@Path String id); @Post("/users") User createUser(@Body User user); } // Use as regular Java interface UserService service = RestClient.create().build().getRemote(UserService.class); User user = service.getUser("123");
import org.apache.juneau.rest.mock.*; // Test without starting a server @Test public void testUserAPI() throws Exception { String response = MockRestClient .create(UserResource.class) .json5() .build() .get("/users/123") .run() .assertStatus().is(200) .getContent().asString(); assertThat(response).contains("John"); }
import org.apache.juneau.microservice.*; // Create microservice Microservice microservice = Microservice.create() .servlet(UserResource.class) .port(8080) .build(); // Start server microservice.start();
Apache Juneau™ is a single cohesive Java ecosystem consisting of the following parts:
Questions via email to dev@juneau.apache.org are always welcome.
Juneau is packed with features that may not be obvious at first. Users are encouraged to ask for code reviews by providing links to specific source files such as through GitHub. Not only can we help you with feedback, but it helps us understand usage patterns to further improve the product.
This repository uses multiple branches to separate different concerns:
master - Contains the main source code for Apache Juneaudocs - Contains the Docusaurus-based documentation siteasf-staging - Contains the staging/preview version of the websiteasf-site - Contains the production version of the websiteWhen working with the repository, ensure you're on the correct branch for your task:
master branchdocs branchasf-staging and asf-site branches are automatically updated during the release processBuilding requires: