Stream API Java удаление поля

Не могу понять как убрать поле из объекта. Есть два класса:

public class PatientSubCategory {

    private String id;
    private String code;
    private String description;
    private PatientCategory category;
}
public class PatientCategoryDTO {
    private String id;
    private String code;
    private String description;
    private List<PatientSubCategory> subCategories;
}

Мне нужно удалить поле PatientCategory category; из элементов объекта List<PatientSubCategory> subCategories;

Делаю я это следующим образом, но это не совсем то, что мне нужно:

public PatientCategoryDTO(PatientCategory patientCategory)
    {
        ArrayList<PatientSubCategory> localSubCategories = new ArrayList<PatientSubCategory>();

        this.id = patientCategory.getId();
        this.code = patientCategory.getCode();
        this.description = patientCategory.getDescription();
        if (patientCategory.getSubCategories() != null)
        {
            for (PatientSubCategory patientSubCategory: patientCategory.getSubCategories())
            {
                patientSubCategory.setCategory(null);
                localSubCategories.add(patientSubCategory);
            }
            this.subCategories = localSubCategories;
        }
    }

Получаю такой вывод:

[
    {
        "id": "1",
        "code": "1",
        "description": "Работники ОАО",
        "subCategories": [
            {
                "id": "1||1",
                "code": "1",
                "description": " Работники группы машинистов, водителей и их помощников",
                "category": null
            },
            {
                "id": "1||3",
                "code": "3",
                "description": " Работники станционно-маневровой группы",
                "category": null
            },
            {
                "id": "1||4",
                "code": "4",
                "description": " Работники группы, обслуживающей поезда в пути следования",
                "category": null
            }
        ]
    },
    {
        "id": "2",
        "code": "2",
        "description": "Пенсионеры",
        "subCategories": []
    }
]

А нужно, чтобы поле "category": null вообще не было.

Подскажите, пожалуйста, как это сделать?


Ответы (1 шт):

Автор решения: Nowhere Man

Проще/правильнее было бы использовать корректный DTO объект для подкатегорий, не содержащий ссылки на родительскую категорию.

Возможное решение:

  • добавляется DTO-класс PatientSubCategoryDTO без ссылки на родительскую категорию, с конструктором, принимающим сущность-подкатегорию PatientSubCategory
@Data
@AllArgsConstructor
public class PatientSubCategoryDTO {
    private String id;
    private String code;
    private String description;

    public PatientSubCategoryDTO(PatientSubCategory subcategory) {
        this(subcategory.getId(), subcategory.getCode(), subcategory.getDescription());
    }
}
  • тип элементов списка в PatientCategoryDTO меняется на новый DTO-класс
  • переписывается конструктор в DTO-классе PatientCategoryDTO, чтобы правильно преобразовать List<PatientSubCategory> в List<PatientSubCategoryDTO>
@Data
@AllArgsConstructor
public class PatientCategoryDTO {
    private String id;
    private String code;
    private String description;
    private List<PatientSubCategoryDTO> subCategories;

    public PatientCategoryDTO(PatientCategory category) {
        this(category.getId(), category.getCode(), category.getDescription(),
            Optional.ofNullable(category.getSubcategories())
                .map(subs -> subs.stream().map(PatientSubCategoryDTO::new).toList())
                .orElse(null)
        );
    }
}

Таким образом, не будут смешиваться классы DTO и соответствующих сущностей, и не возникнет необходимости устанавливать в null поле в сущности PatientSubCategory.


Другие варианты решения, без создания отдельного DTO класса, могут опираться на использование стандартных Jackson аннотаций для управления сериализацией полей:

  • Использовать @JsonBackReference для поля-ссылки на родительскую категорию и @JsonManagedReference для коллекции подкатегорий:
public class PatientSubCategory {
    private String id;
    private String code;
    private String description;
    @JsonBackReference
    private PatientCategory category;
}

public class PatientCategoryDTO {
    private String id;
    private String code;
    private String description;
    @JsonManagedReference
    private List<PatientSubCategory> subCategories;
}

Это в частности позволит избежать рекурсивной зависимости и StackOverflowError при сериализации.

  • Использовать @JsonIgnore для поля-ссылки на родительскую категорию:
public class PatientSubCategory {
    private String id;
    private String code;
    private String description;
    @JsonIgnore
    private PatientCategory category;
}

Простой запрет сериализации указанного поля.

  • Использовать @JsonIgnoreProperties для поля-ссылки на родительскую категорию на уровне класса, аналог @JsonIgnore:
@JsonIgnoreProperies(value = {"category"})
public class PatientSubCategory {
    private String id;
    private String code;
    private String description;
    private PatientCategory category;
}

Такие варианты позволят "сэкономить" на создании новых DTO-объектов, благодаря переиспользованию сущности PatientSubCategory, но такой подход немного грязный по сравнению с предыдущим.

→ Ссылка