Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to get Map<String,List<Data>> from yaml using snakeyaml

Tags:

java

snakeyaml

trying to load data from yaml and creating the following object:

Problem: Not able map yaml to Object, When I try to it is always throwing exception: java.util.LinkedHashMap cannot be cast to com.heraizen.DataConfig$Data

Map<String,List<Data>> map;

Code Snippet:

public class DataConfig {
private Map<String, List<Data>> heros = new HashMap<String, List<Data>>();

public static class Data {
    private String name;
    private String uri;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getUri() {
        return uri;
    }

    public void setUri(String uri) {
        this.uri = uri;
    }

    @Override
    public String toString() {
        return "Data [name=" + name + ", uri=" + uri + "]";
    }

}

public Map<String, List<Data>> getHeros() {
    return heros;
}

public void setHeros(Map<String, List<Data>> heros) {
    this.heros = heros;
}

Yaml:

  --- 
 heros: 
   one:

     - name: h1
       url: hu2
     - name: h2
       url: hu22
  two: 
    - name: h3
      url: hu3

Constructing Object:

   Yaml yaml = new Yaml(new Constructor(DataConfig.class));

   DataConfig retValue = (DataConfig) yaml.load(new FileInputStream("one.yaml"));
   retValue.getHeros().entrySet().forEach(ele->{
       System.out.println(ele.getKey()+" "+ele.getValue().get(0).getName());
   });
    System.out.println(retValue);
like image 384
Lakshman Miani Avatar asked Nov 28 '25 08:11

Lakshman Miani


1 Answers

May use custom constructor

public class MyDataConstructor extends Constructor {
    private static final String MY_DATA_CONSTRUCTOR_NAME = MyDataConstructor.class.getSimpleName();

    public MyDataConstructor(LoaderOptions loadingConfig) {
        super(loadingConfig);
        this.rootTag = new Tag(MY_DATA_CONSTRUCTOR_NAME);
    }

    @Override
    protected Object constructObject(Node node) {
        if (MY_DATA_CONSTRUCTOR_NAME.equals(node.getTag().getValue()) && node instanceof MappingNode mNode) {
            return mNode.getValue().stream().collect(
                    Collectors.toMap(
                            t -> super.constructObject(t.getKeyNode()),
                            t -> {
                                Node child = t.getValueNode();
                                if (child instanceof SequenceNode sNode) {
                                    sNode.setListType(Data.class);
                                }
                                return super.constructObject(child);
                            }
                    )
            );
        }
        return super.constructObject(node);
    }

    @lombok.Data
    public static class Data {
        private String name;
        private String uri;
    }

    public static void main(String[] args) {
        try {
            Yaml yl = new Yaml(new MyDataConstructor(new LoaderOptions()));
            String ylStr =
                    "custom-xxx:\n" +
                    "  - name: qwe\n" +
                    "    uri: wwww\n" +
                    "  - name: asd\n" +
                    "    uri: xxxx\n" +
                    "  - name: zxc\n" +
                    "    uri: rrr";
            Map<String, List<Data>> my = yl.load(ylStr);

            for (String key : my.keySet()){
                for(Data item: my.get(key)){
                    System.out.println(item.getName());
                    System.out.println(item.getUri());
                    System.out.println(item.getClass().getName());
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

output:

> Task :MyDataConstructor.main()
qwe
wwww
xxx.MyDataConstructor$Data
asd
xxxx
xxx.MyDataConstructor$Data
zxc
rrr
xxx.MyDataConstructor$Data

ps:

dependencies {
    implementation "org.yaml:snakeyaml:2.0"
}

ref Constructor

like image 158
z.x Avatar answered Nov 30 '25 22:11

z.x