Carleslc / Simple-YAML

This Java API provides an easy-to-use way to store data and provide configurations using the YAML format.
https://carleslc.me/Simple-YAML
GNU General Public License v3.0
130 stars 38 forks source link

Resetting lists #46

Closed bi3her closed 3 years ago

bi3her commented 3 years ago

I have a data.yml file that contains some questions with their answers, etc. The answers are in a list, but I've noticed that whenever a question gets picked, some weird behavior happens.

image

What I do with this is: 1- check if get questions.1.used is false (continue), else return 2- get questions.1.question and store in a variable 3- getList questions.1.answers and store in another variable 4- get questions.1.extra and store in another variable 5- set questions.1.used true 6- The rest is just java code

Here the only thing I'm setting is questions.1.used but it turns into this:

image

Two unexpected things happened: 1- questions.1.answers changed to an empty list, without me setting it to anything or changing it. 2- questions.1.extra is reformatted a little, this is not major and doesn't affect anything though.

This is not because of the IDE I'm using or anything, I've tried on different devices and it acts the same.

Carleslc commented 3 years ago

It may be something related to flow-style lists. Have you tried using a sequence with indentation?

questions:
  '1':
    answers:
      - Sojourner
      - Spirit
      - Opportunity
      - Curiosity
      - Perseverance
bi3her commented 3 years ago

It may be something related to flow-style lists. Have you tried using a sequence with indentation?

questions:
  '1':
    answers:
      - Sojourner
      - Spirit
      - Opportunity
      - Curiosity
      - Perseverance

I have. In fact, I tried that first and then switched to what I'm using now thinking it would solve the problem, and it didn't. Even though I dont set or change anything in the answers, I think my code later may be a problem, because if you do steps 1-5 it's completely fine, but for some reason, the later code is what makes the difference. I'll reply with it once I can, and please excuse how inefficient it may be.

Carleslc commented 3 years ago

Do you get the non-empty list of answers in your code when loading the file and reading answers?

Provide the relevant parts of your code to reproduce the situation, where you load the yaml, read values, change questions.1.used and save the yaml again (is with the save where the yml file changes).

bi3her commented 3 years ago

I found out the issue. I'm sorry if I wasted your time due to my lack of experience, but here it is: I experimented with my code and found what's causing it. Here's data.yml for the experiment: image Nothing new, now here's the code: image Basically, get the answers, store them in a list, then use some code to rearrange them randomly (because the first answer is the correct one). But I made one mistake that I didn't realize, and it's that I removed the answers from the list when rearranging them (using answers.remove()), and this caused them to be removed from data.yml itself, which is new to me and mainly why I was confused because I thought it would only remove it from the variable answers. (The experiment is that I used different code without answers.remove() and it worked fine)

Carleslc commented 3 years ago

Glad to see you were able to address the issue.

This is a side-effect of using getList method, which returns the internal list as is (the same happens with the raw get method). In case it is a List or Map then mutating the object will mutate the internal list, which will be reflected in the yml file on save.

I suggest you to use getStringList instead, which returns a copy of the internal list, already casted to List<String>. That copy can be mutated without affecting the yml file.

So, your issue would be resolved changing

List<String> answers = (List<String>) DataYML.getYML().getList("test.answers");

to

List<String> answers = DataYML.getYML().getStringList("test.answers");

I guess DataYML.getYML() is either a YamlFile or YamlConfiguration instance.

Casting the getList to (List<String>) directly can lead to such side-effects. If you want to use getList and mutate the list without affecting the yml state then you should first get a copy of the list using new ArrayList<String>((List<String>) DataYML.getYML().getList("test.answers")). But I still suggest you to use getStringList which handles the copy ensuring items are actually strings, something it is not handled by casting to (List<String>) directly so it could lead to other unexpected behaviour. getList method is intended to be used when you do not know the type of the items, or they are of different types.

Another suggestion, apart from the issue: you can use Collections.shuffle(answers) method from the Java API to rearrange the list randomly (just make sure you are using getStringList or the new random order will be reflected to the yml file as well).

bi3her commented 3 years ago

That's awesome to know! Thank you for letting me know about them, and I guess I shouldn't use .get since it would have the same effect. Very helpful!