Хранение JSON класса со ссылкой на объект того же класса - PullRequest
0 голосов
/ 17 мая 2018

У меня есть что-то похожее на это:

public class Person {
    public String name;
    public List<Person> family;
}
List<Person> people;

И я хочу сохранить people в виде строки JSON на диске.И я хочу следовать хорошему шаблону дизайна.Например, делает все правильно .

Я не хочу, чтобы в конечном итоге

[{"name":"John Doe", "family": [{"name": "Mary", "family": [{"name": "Mary's mother", "family": [{.........

Также можно было бы закончить тем, что Мэри тоже будет с Джоном Доу в семье., создавая бесконечную рекурсию.

Я хотел бы закончить с чем-то вроде этого:

[{"name":"John Doe", "family": [(reference to Mary)]}, {"name": "Mary", "family": [(reference to Mary's Mother), (reference to John Doe)]}, ...]

Я не хочу принимать имя уникальный.

Является ли добавление «ID» для Person хорошей реализацией / шаблоном?Потому что в моем классе Человек с идентификатором не имеет смысла (он не имеет / не нужен)

Идея, которую я имею в виду (я думаю, будет хорошим шаблоном дизайна) - это иметьдругой "приватный" класс

private class PersonWithId extends Person {
    private int id;
}

и сохраните этот PersonWithId в JSON, чтобы при сохранении списка семейства я мог сохранить идентификатор в качестве ссылки, чтобы не было рекурсии.

Какие параметрыу меня есть?

Спасибо.

Ответы [ 2 ]

0 голосов
/ 17 мая 2018

Вы могли бы сделать что-то вроде этого.

public class Person {

private static Map<UUID, Person> persons = new HashMap<>();

//some dummy data
static {
    final UUID uuidMax = UUID.randomUUID();
    persons.put(uuidMax, new Person("Max", null));
    persons.put(UUID.randomUUID(), new Person("John", Arrays.asList(uuidMax)));
}

public static String saveAsJSON() {
    Gson gson = new Gson();
    return gson.toJson(persons); 
    //or write right away gson.toJson(obj, new FileWriter("D:\\file.json"));
}

public static void addFromJSON(String json) {
    Gson gson = new GsonBuilder().create();
    persons = gson.fromJson(json, Map.class); 
    //plug in JsonReader reader = new JsonReader(new FileReader(filename)) to read directly from file
}

private String name;
private List<UUID> family;

public Person(String name, List<UUID> family) {
    this.name = name;
    this.family = family;
}

//returns family member if it exists
public Person getFamilyMember(UUID id) {
    if(persons.containsKey(id))
        return persons.get(id);
    return null;
}

//returns the entire family
public List<Person> getFamilyMembers() {
    List<Person> family = new LinkedList<>();
    if(this.family != null) {
        for (var cur : this.family) {
            var person = getFamilyMember(cur);
            if(person != null)
                family.add(person);
            else
                this.family.remove(cur); //person no longer exists

        }
    }
    return family;
}

}

Для этого использовал библиотеку GSON

<dependencies>
    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.8.4</version>
    </dependency>
</dependencies>

UUID великолепен, потому что вам не нужно беспокоиться о генерации уникальных идентификаторов, так как они, как правило, уникальны, вот и все. Теоретически вы можете получить дубликаты, но это очень маловероятно.

Строка, которую он выплевывает, выглядит так

{"bced5dcf-102c-4d18-9f92-bb10d7a5b212":{"name":"Max"},"e40710b4-55b5-4e97-a280-6d07ae160e3b":{"name":"John","family":["bced5dcf-102c-4d18-9f92-bb10d7a5b212"]}}

Вы, вероятно, хотите поместить материал Save / Read в другой класс, но я просто привел все это в качестве примера.

0 голосов
/ 17 мая 2018

Я ограничиваю область своего ответа прямым вопросом о добавлении уникального идентификатора в сериализованные экземпляры и избегании циклических ссылок.

Библиотека Джексона поддерживает циклические ссылки.Вы можете управлять генерацией уникального идентификатора и указать Джексону ссылаться на него, или позволить Джексону генерировать уникальный идентификатор в json.Библиотека сможет загрузить такой json обратно в память:

// annotation that tells jackson to generate sequantial int unique id
// and add it as "@id" property
// this will also be used in de-serialization
@JsonIdentityInfo(
    generator = ObjectIdGenerators.IntSequenceGenerator.class,
    property="@id")
public class Person {
    public String name;
    public List<Person> family = new ArrayList<>();
}

метод тестирования:

public static void main(String[] args) {
    Person john = new Person();
    john.name = "John Doe";
    Person mary = new Person();
    mary.name = "Mary";
    john.family.add(mary);
    mary.family.add(john);
    List<Person> people = new ArrayList<>();
    people.add(john);
    people.add(mary);

    ObjectMapper mapper = new ObjectMapper();
    try {
        // serialize the list into json
        String json = mapper.writeValueAsString(people);
        System.out.println(json);

        // de-serialize the json into list of persons
        people = mapper.readValue(json, new TypeReference<List<Person>>(){});
        people.forEach(p -> System.out.println(p.name));
    } catch (Exception e) {
        e.printStackTrace();
    }
}

вывод:

[{"@id":1,"name":"John Doe","family":[{"@id":2,"name":"Mary","family":[1]}]},2]
John Doe
Mary
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...