java
44 lines · 7 steps
Loading typed config into a Java record
A record models server settings and a set of static factory methods parse them safely from a properties file.
Explained by
highlit
1public record ServerConfig(
2 String host,
3 int port,
4 Duration timeout,
5 boolean tlsEnabled,
6 List<String> allowedOrigins) {
7
8 public static ServerConfig load(Path file) {
9 Properties props = new Properties();
10 try (InputStream in = Files.newInputStream(file)) {
11 props.load(in);
12 } catch (IOException e) {
13 throw new UncheckedIOException("Failed to read config: " + file, e);
14 }
15 return fromProperties(props);
16 }
17
18 public static ServerConfig fromProperties(Properties props) {
19 return new ServerConfig(
20 require(props, "server.host"),
21 Integer.parseInt(require(props, "server.port")),
22 Duration.ofSeconds(Long.parseLong(props.getProperty("server.timeoutSeconds", "30"))),
23 Boolean.parseBoolean(props.getProperty("server.tls.enabled", "false")),
24 parseList(props.getProperty("server.allowedOrigins", "")));
25 }
26
27 private static String require(Properties props, String key) {
28 String value = props.getProperty(key);
29 if (value == null || value.isBlank()) {
30 throw new IllegalStateException("Missing required config key: " + key);
31 }
32 return value.trim();
33 }
34
35 private static List<String> parseList(String raw) {
36 if (raw.isBlank()) {
37 return List.of();
38 }
39 return Arrays.stream(raw.split(","))
40 .map(String::trim)
41 .filter(s -> !s.isEmpty())
42 .toList();
43 }
44}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Records give you an immutable, self-documenting data carrier with almost no boilerplate.
- 2Static factory methods keep parsing and validation logic beside the type they build.
- 3Fail loudly on missing required values but fall back to sensible defaults for optional ones.
Related explainers
php
<?php namespace App\Services\Checkout;
Validating coupons with Laravel's Pipeline
pipeline
chain of responsibility
transactions
Intermediate
7 steps
ruby
class UserAgentParser BROWSERS = [ [/Edg\/([\d.]+)/, "Edge"], [/OPR\/([\d.]+)/, "Opera"],
Parsing user-agent strings in Ruby
regex
pattern-matching
lookup-tables
Intermediate
8 steps
java
@Component @Converter public class EncryptedStringConverter implements AttributeConverter<String, String> {
Transparent column encryption in Spring & JPA
encryption
aes-gcm
jpa-converter
Advanced
10 steps
javascript
function evaluate(expression) { const tokens = tokenize(expression); let pos = 0;
Building a recursive descent calculator
parsing
recursion
operator-precedence
Intermediate
8 steps
php
<?php namespace App\Services;
How a password strength validator works in PHP
validation
regular-expressions
data-driven
Intermediate
8 steps
java
package com.acme.billing.config; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.ConfigurationProperties;
Feature-flagged beans with Spring @ConditionalOnProperty
feature-flags
conditional-beans
strategy-pattern
Intermediate
5 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/loading-typed-config-into-a-java-record-explained-java-d725/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.