Java中JSON请求体(JSON-payload)的结构化与修改优化方案咨询
Great question—string-based JSON templates like the one you're using quickly become unmanageable, especially as the payload grows or other team members need to work with it. Let's look at three far better approaches that'll make your code more readable, maintainable, and less error-prone:
1. Use POJO Classes + JSON Serialization Library (Recommended)
This is the best long-term solution because it’s type-safe, enables compile-time checks, and makes the JSON structure explicit through Java objects. We’ll use Jackson (one of the most popular JSON libraries for Java), but Gson works just as well.
Step 1: Define POJO Classes
Create classes that mirror your JSON structure:
import com.fasterxml.jackson.annotation.JsonProperty; import java.util.List; // Root level of the payload public class RequestRoot { @JsonProperty("request") private JsonRequest request; // Getters and setters (or use Lombok to auto-generate them) public JsonRequest getRequest() { return request; } public void setRequest(JsonRequest request) { this.request = request; } } public class JsonRequest { @JsonProperty("jsonRequest") private Alpha alpha; public Alpha getAlpha() { return alpha; } public void setAlpha(Alpha alpha) { this.alpha = alpha; } } public class Alpha { @JsonProperty("Bravo") private List<BravoItem> bravo; @JsonProperty("Desert") private List<DesertItem> desert; public List<BravoItem> getBravo() { return bravo; } public void setBravo(List<BravoItem> bravo) { this.bravo = bravo; } public List<DesertItem> getDesert() { return desert; } public void setDesert(List<DesertItem> desert) { this.desert = desert; } } public class BravoItem { @JsonProperty("Delta") private String delta; public String getDelta() { return delta; } public void setDelta(String delta) { this.delta = delta; } } public class DesertItem { private int id; private String name; private String age; private String city; private String street; // Getters and setters public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAge() { return age; } public void setAge(String age) { this.age = age; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getStreet() { return street; } public void setStreet(String street) { this.street = street; } }
Step 2: Build and Serialize the Payload
Create instances of these classes, set your dynamic values, then convert to JSON:
import com.fasterxml.jackson.databind.ObjectMapper; public class PayloadGenerator { public String generateDynamicPayload(String lenaStreet, String moaStreet) throws Exception { // Initialize the fixed parts of the payload RequestRoot root = new RequestRoot(); JsonRequest jsonRequest = new JsonRequest(); Alpha alpha = new Alpha(); BravoItem bravoItem = new BravoItem(); bravoItem.setDelta("something"); alpha.setBravo(List.of(bravoItem)); // Populate dynamic and fixed Desert items DesertItem lena = new DesertItem(); lena.setId(1); lena.setName("Lena"); lena.setAge("25"); lena.setCity("Florida"); lena.setStreet(lenaStreet); // Dynamic value DesertItem moa = new DesertItem(); moa.setId(2); moa.setName("Moa"); moa.setAge("21"); moa.setCity("Mexico"); moa.setStreet(moaStreet); // Dynamic value DesertItem nils = new DesertItem(); nils.setId(3); nils.setName("Nils"); nils.setAge("29"); nils.setCity("Tampas"); nils.setStreet("Tampas Street"); // Fixed value alpha.setDesert(List.of(lena, moa, nils)); jsonRequest.setAlpha(alpha); root.setRequest(jsonRequest); // Convert to pretty-printed JSON ObjectMapper mapper = new ObjectMapper(); return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(root); } }
Usage
PayloadGenerator generator = new PayloadGenerator(); String payload = generator.generateDynamicPayload("Florida Street", "Mexico Street");
Why this works:
- No more messy string concatenation or format placeholders
- Compile-time validation of fields (typos in field names will throw errors immediately)
- Easy to update the payload structure (just modify the POJOs)
- Team members can quickly understand the JSON structure from the classes
2. Directly Manipulate JSON Nodes (For Quick Modifications)
If you don’t want to write full POJOs, you can use Jackson’s ObjectNode to parse a base JSON string and modify only the dynamic fields. This is great for one-off changes.
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; public class DynamicNodePayloadGenerator { public String generatePayload(String lenaStreet, String moaStreet) throws Exception { ObjectMapper mapper = new ObjectMapper(); // Base payload with placeholder values for dynamic fields String baseJson = "{ \"request\": { \"jsonRequest\": { \"Alpha\": { \"Bravo\": [ { \"Delta\": \"something\" } ], \"Desert\": [ { \"id\": 1, \"name\": \"Lena\", \"age\": \"25\", \"city\": \"Florida\", \"street\": \"\" }, { \"id\": 2, \"name\": \"Moa\", \"age\": \"21\", \"city\": \"Mexico\", \"street\": \"\" }, { \"id\": 3, \"name\": \"Nils\", \"age\": \"29\", \"city\": \"Tampas\", \"street\": \"Tampas Street\" } ] } } }"; // Parse base JSON into a mutable ObjectNode ObjectNode root = (ObjectNode) mapper.readTree(baseJson); // Navigate to the Desert array and update dynamic fields ArrayNode desertArray = (ArrayNode) root.path("request") .path("jsonRequest") .path("Alpha") .path("Desert"); ((ObjectNode) desertArray.get(0)).put("street", lenaStreet); ((ObjectNode) desertArray.get(1)).put("street", moaStreet); return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(root); } }
Pros:
- No need to write POJOs
- Fast to implement for small changes
Cons:
- No type safety (typos in field names will only be caught at runtime)
- Harder to follow for complex nested structures
3. Use a Template Engine (Freemarker)
If you prefer a template-based approach but want something cleaner than String.format(), use a dedicated template engine like Freemarker.
Step 1: Create a JSON Template File (payload.ftl)
Place this file in your classpath:
{ "request": { "jsonRequest": { "Alpha": { "Bravo": [ { "Delta": "something" } ], "Desert": [ { "id": 1, "name": "Lena", "age": "25", "city": "Florida", "street": "${lenaStreet}" }, { "id": 2, "name": "Moa", "age": "21", "city": "Mexico", "street": "${moaStreet}" }, { "id": 3, "name": "Nils", "age": "29", "city": "Tampas", "street": "Tampas Street" } ] } } } }
Step 2: Load and Process the Template
import freemarker.template.Configuration; import freemarker.template.Template; import java.io.StringWriter; import java.util.HashMap; import java.util.Map; public class FreemarkerPayloadGenerator { public String generatePayload(String lenaStreet, String moaStreet) throws Exception { Configuration cfg = new Configuration(Configuration.VERSION_2_3_32); cfg.setClassForTemplateLoading(FreemarkerPayloadGenerator.class, "/"); Template template = cfg.getTemplate("payload.ftl"); Map<String, Object> data = new HashMap<>(); data.put("lenaStreet", lenaStreet); data.put("moaStreet", moaStreet); StringWriter writer = new StringWriter(); template.process(data, writer); return writer.toString(); } }
Pros:
- JSON structure is visually identical to the final payload
- Easy to modify the template without touching Java code
Cons:
- Adds an extra dependency
- No type safety for dynamic values
Final Recommendation
Stick with the POJO + Jackson/Gson approach for most cases—it’s the most maintainable and robust option. Use the JSON node approach for quick fixes, and the template engine only if you need non-developers to edit the payload structure.
内容的提问来源于stack exchange,提问作者klabbaparn

