DynamicJsonMapper is a lightweight Java library for rendering JSON output from template files with runtime placeholder data.
- Keep API response shapes in JSON template files.
- Replace placeholder tokens (for example
${name},${city}) at runtime. - Link parent and child templates for object/array rendering via
$template_refand$source. - Support nested objects and arrays with recursive traversal.
- Reuse parsed templates with in-memory cache for better performance.
src/main/java/com/thanhlv/dynamicjsonmapper/: library source (JsonTemplateMapper,TemplateRenderer,TemplateReferenceResolver,TemplateRepository,CachingClasspathTemplateRepository).src/test/java/com/thanhlv/dynamicjsonmapper/: JUnit test suites.src/test/resources/templates/: template fixtures used by tests and usage examples.docs/FEATURES.md: behavior-focused feature list.AGENTS.md: repository contribution and AI workflow guidelines.
- Java 17 (Gradle toolchain)
- Jackson Databind
3.1.3 - JUnit 5
./gradlew clean build
./gradlew test
./gradlew classesimport com.thanhlv.dynamicjsonmapper.JsonTemplateMapper;
import tools.jackson.databind.JsonNode;
import java.util.Map;
JsonTemplateMapper mapper = JsonTemplateMapper.defaultInstance();
JsonNode output = mapper.render("templates/user-template.json", Map.of(
"${name}", "Thanh",
"${tuoi}", 23,
"${noio}", "Ha Noi"
));
String pretty = mapper.jsonNodeToString(output);import com.thanhlv.dynamicjsonmapper.JsonTemplateMapper;
import com.thanhlv.dynamicjsonmapper.TemplateRepository;
import tools.jackson.databind.JsonNode;
import tools.jackson.databind.ObjectMapper;
ObjectMapper objectMapper = new ObjectMapper();
TemplateRepository repository = new TemplateRepository() {
@Override
public JsonNode getTemplate(String templatePath) {
try {
return objectMapper.readTree("{\"message\": \"${message}\"}");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
};
JsonTemplateMapper mapper = new JsonTemplateMapper(objectMapper, repository);
JsonNode result = mapper.render("ignored", Map.of("${message}", "hello"));mapper.refreshCache();- Workflow file:
.github/workflows/publish-central.yml. - Trigger methods:
- Push tag release:
v*(example:v1.2.3). - Manual run via GitHub Actions (
workflow_dispatch) withrelease_versioninput. - Required GitHub repository secrets:
MAVEN_CENTRAL_USERNAMEMAVEN_CENTRAL_PASSWORDMAVEN_CENTRAL_GPG_PRIVATE_KEYMAVEN_CENTRAL_GPG_PASSPHRASE- Build uses Gradle task:
publishToMavenCentralwith-PreleaseVersion=....
- Script file:
scripts/publish-central.sh - Usage:
export MAVEN_CENTRAL_USERNAME=...
export MAVEN_CENTRAL_PASSWORD=...
export MAVEN_GPG_PRIVATE_KEY=...
export MAVEN_GPG_PASSPHRASE=...
./scripts/publish-central.sh 1.2.3- You can also provide the same values via Gradle property env vars:
ORG_GRADLE_PROJECT_mavenCentralUsernameORG_GRADLE_PROJECT_mavenCentralPasswordORG_GRADLE_PROJECT_signingInMemoryKeyORG_GRADLE_PROJECT_signingInMemoryKeyPassword
Current repository examples are executable tests:
./gradlew test --tests com.thanhlv.dynamicjsonmapper.DynamicJsonMapperTest
./gradlew test --tests com.thanhlv.dynamicjsonmapper.DeepNestedMapperTest
./gradlew test --tests com.thanhlv.dynamicjsonmapper.PaginatedListMapperTest- Keep commits focused and descriptive (
type(scope): summary). - Update
docs/FEATURES.mdin the same change whenever behavior or API usage changes.
skills/code-doc-sync: reconcile docs and implementation (docs-firstorcode-first).skills/code-test-sync: keep implementation and JUnit tests synchronized when behavior changes.