如何将指定YAML文件转换为Java对象(基于Jackson依赖)
First, let's address the key challenge in your YAML: duplicate keys (Input 1 and Input 2 appear twice). By default, Jackson's YAML parser will overwrite the first occurrence of a key with the second one, which isn't what you want. We'll cover two approaches here: fixing the YAML structure (recommended, since duplicate keys are non-standard in YAML 1.2) and configuring Jackson to preserve duplicates.
Approach 1: Fix the YAML Structure (Recommended)
Your YAML seems to have a syntax quirk where each input's properties are split into separate list items. A more standard approach is to group properties for each input entry into a single list item. This eliminates duplicate keys and makes parsing cleaner:
Network: Input 1: - profile: "1" size: 2 - profile: "2" size: 100 Input 2: - profile: "1" size: 3 - name: "N" source: "test"
Step 1: Define Java Classes
Create type-safe classes that map to this structure. Since input entries can have varying properties, we'll use optional fields:
import java.util.List; import java.util.Map; // Top-level configuration class public class NetworkConfig { private Map<String, List<InputEntry>> network; // Getters and setters public Map<String, List<InputEntry>> getNetwork() { return network; } public void setNetwork(Map<String, List<InputEntry>> network) { this.network = network; } } // Class to represent individual input entries public class InputEntry { private String profile; private Integer size; private String name; private String source; // Getters and setters for all fields public String getProfile() { return profile; } public void setProfile(String profile) { this.profile = profile; } public Integer getSize() { return size; } public void setSize(Integer size) { this.size = size; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSource() { return source; } public void setSource(String source) { this.source = source; } }
Step 2: Parse with Jackson
No special configuration needed here—Jackson will handle the structure out of the box:
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; public class YamlParser { public static void main(String[] args) throws Exception { String yamlContent = """ Network: Input 1: - profile: "1" size: 2 - profile: "2" size: 100 Input 2: - profile: "1" size: 3 - name: "N" source: "test" """; ObjectMapper mapper = new ObjectMapper(new YAMLFactory()); NetworkConfig config = mapper.readValue(yamlContent, NetworkConfig.class); // Access parsed data List<InputEntry> input1Entries = config.getNetwork().get("Input 1"); System.out.println("First Input 1 Profile: " + input1Entries.get(0).getProfile()); // Output: 1 System.out.println("Second Input 1 Size: " + input1Entries.get(1).getSize()); // Output: 100 List<InputEntry> input2Entries = config.getNetwork().get("Input 2"); System.out.println("Input 2 Source: " + input2Entries.get(1).getSource()); // Output: test } }
Approach 2: Handle Duplicate Keys in Original YAML
If you can't modify the YAML, you'll need to configure Jackson to preserve duplicate keys by collecting them into lists. We'll use SnakeYAML's (Jackson's underlying YAML parser) duplicate key handler for this:
Step 1: Configure Jackson for Duplicate Keys
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import com.fasterxml.jackson.dataformat.yaml.YAMLParser; import org.yaml.snakeyaml.Constructor; import java.util.ArrayList; import java.util.List; public class DuplicateKeyYamlParser { public static void main(String[] args) throws Exception { String yamlContent = """ Network: Input 1: - profile : "1" - size: 2 Input 2: - profile : "1" - size: 3 Input 1: - profile :"2" - size:100 Input 2: - name :"N" - source: "test" """; // Configure YAML factory to allow duplicates and collect them into lists YAMLFactory yamlFactory = new YAMLFactory(); yamlFactory.enable(YAMLParser.Feature.ALLOW_DUPLICATE_KEYS); // Set up SnakeYAML's constructor to handle duplicate keys Constructor snakeYamlConstructor = yamlFactory.getSnakeYAML().getConstructor(); snakeYamlConstructor.setAllowDuplicateKeys(true); snakeYamlConstructor.setDuplicateKeyHandler((key, oldValue, newValue) -> { if (oldValue instanceof List) { ((List<?>) oldValue).add(newValue); return oldValue; } else { List<Object> list = new ArrayList<>(); list.add(oldValue); list.add(newValue); return list; } }); ObjectMapper mapper = new ObjectMapper(yamlFactory); NetworkConfigDuplicate config = mapper.readValue(yamlContent, NetworkConfigDuplicate.class); // Access parsed data (note the nested list structure) List<List<java.util.Map<String, Object>>> input1Entries = config.getNetwork().get("Input 1"); String firstProfile = (String) input1Entries.get(0).get(0).get("profile"); System.out.println("First Input 1 Profile: " + firstProfile); // Output: 1 } } // Class to handle nested lists from duplicate keys class NetworkConfigDuplicate { private java.util.Map<String, List<List<java.util.Map<String, Object>>>> network; public java.util.Map<String, List<List<java.util.Map<String, Object>>>> getNetwork() { return network; } public void setNetwork(java.util.Map<String, List<List<java.util.Map<String, Object>>>> network) { this.network = network; } }
This approach preserves all duplicate entries, but the resulting structure is more nested and less type-safe—hence why fixing the YAML is recommended.
内容的提问来源于stack exchange,提问作者Rama

