`Global tag is not allowed` exception in SnakeYAML 2.0
Asked Answered
R

3

5

I'm using SnakeYAML 2.0 to parse YAML files in Java. But I face a problem here. This is my User class:

package ir.sharif;

import java.util.ArrayList;
import java.util.List;

public class User {
    int id;
    String username;
    String password;
    List<User> friends = new ArrayList<>();

    public User(int id, String username, String password) {
        this.id = id;
        this.username = username;
        this.password = password;
    }

    public User() {
    }

    // getters and setters
}

I use this code to serialize a User object:

package ir.sharif;

import org.yaml.snakeyaml.Yaml;

import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) throws IOException {
        User user = new User();
        user.setId(10);
        user.setUsername("Jack");
        user.setPassword("jackSparrow2023");
        List<User> friends = new ArrayList<>();
        friends.add(new User(1, "Trent", "FCB"));
        friends.add(new User(2, "Jordan", "LFC"));
        user.setFriends(friends);

        Yaml yaml = new Yaml();
        yaml.dump(user, new FileWriter("src/main/resources/sample.yml"));
    }
}

And this is how my sample.yml file looks like after running main method:

!!ir.sharif.User
friends:
- friends: []
  id: 1
  password: FCB
  username: Trent
- friends: []
  id: 2
  password: LFC
  username: Jordan
id: 10
password: jackSparrow2023
username: Jack

Now I want to deserialize this data and load it as a new User object:

package ir.sharif;

import org.yaml.snakeyaml.Yaml;

import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

public class Main {
    public static void main(String[] args) throws IOException {
        Yaml yaml = new Yaml();
        try (Reader reader = new FileReader("src/main/resources/sample.yml")) {
            User user = yaml.load(reader);
            System.out.println(user);
        }
    }
}

But after running, I get this exception:

Exception in thread "main" Global tag is not allowed: tag:yaml.org,2002:ir.sharif.User
 in 'reader', line 1, column 1:
    !!ir.sharif.User
    ^

How can I solve it?

As I searched, I'm doing it right but I think the problem is caused because in version 2.0 there are some changes. I tried loading my object like this (I deleted !!ir.sharif.User line from YAML file):

package ir.sharif;

import org.yaml.snakeyaml.Yaml;

import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

public class Main {
    public static void main(String[] args) throws IOException {
        Yaml yaml = new Yaml();
        try (Reader reader = new FileReader("src/main/resources/sample.yml")) {
            User user = yaml.loadAs(reader, User.class);
            System.out.println(user);
        }
    }
}

And it works fine. But if I want to deserialize the object serialized by SnakeYAML itself, I can't use this method. What should I do? I appreciate any helps.

Rumney answered 19/7, 2023 at 2:9 Comment(0)
W
6

You'll need to register a TagInspector that allows your tag:

var loaderoptions = new LoaderOptions();
TagInspector taginspector = 
    tag -> tag.getClassName().equals(User.class.getName());
loaderoptions.setTagInspector(taginspector);
Yaml yaml = new Yaml(new Constructor(User.class, loaderoptions));
Wellrounded answered 19/7, 2023 at 7:10 Comment(0)
M
3

An alternative solution that allows to load any class, so it makes SnakeYAML 2.0 unsafe again.

Use at your own risk!

LoaderOptions loaderOptions = new LoaderOptions();
loaderOptions.setTagInspector(tag -> true);
Yaml yaml = new Yaml(loaderOptions);
User user = yaml.loadAs(inputStream, User.class);

It uses TagInspector imlementation (tag -> true lambda) that accepts any class.

Genrally, you should perfer other solutions with more granular control. But sometimes you can't know beforehand which classes you will need to construct (e.g. in a library), but at the same time the .yaml source is 100% trusted. In this case this solution is acceptable. But still, consider it as a last resort.

Murex answered 30/1, 2024 at 16:5 Comment(0)
S
0

I was looking to solve this same issue with the library and the solution from the first answer worked for me but with a small adjustment:

LoaderOptions loaderOptions = new LoaderOptions();
TagInspector tagInspector =
              tag -> tag.getClassName().equals(User.class.getName());
loaderOptions.setTagInspector(tagInspector);

InputStream inputStream = Files.newInputStream(new File("thefile.yml").toPath());
Yaml yaml = new Yaml(new Constructor(loaderOptions));
Map<String, Object> object = yaml.load(inputStream);
System.out.println(object);
Sard answered 5/8, 2024 at 17:25 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.