0

Goal: I have a YAML file that needed to remove some key: value properties from. Then I want to create a new YAML file with doesn't exist removed key: value properties. The required key should be removed from the whole YAML file.

Expected Result: Should Iterate through the YAML File and identify the required key: value to be removed and then remove and continue searching for such key: value properties.

Actual Result: Even though iterating through the YAML file desired key: value property won't' remove from the YAML File.

Errors: No Compile or Runtime errors, there seems to be a logical error.

What I have tried:

  • Use Jackson ObjectMapper to read the YAML file.
  • Put all the properties into LinkedHashMap such that I can preserve the order and I can remove items

My Logic: Implement two methods

  • one is to iterate the LinkedHashMap and ArrayList object
  • another one it to check whether a specific key is removable
  • If a removable key is found and remove from the LinkedHashMap and continues searching the same key in other items in the YAML file.

for example I want to remove "originalRef": "Conditions" (the key is String data type) from the YAML file. This key can contain in a LinkedHashMap. Also, There could be ArrayLists which contains multiple LinkedHashMaps.

Code: Below are the YAML file I'm using for these purpose. api-test.yml this only contains a small portion of my big YAML file.

---
swagger: '2.0'
info:
  description: |-
    Planner application is a proposal system enables user to create, manage plan .  
    It also enables network user to publish plan 
  version: '1.0'
  title: Planner API
  contact:
    name: API team
    email: apiteam@test.com
  license:
    name: Copyright © 2020 test
host: aos-dev.test.com
basePath: /unifiedplanner
tags:
  - name: Additional Fee APIs
    description: Additional Fee Controller
  - name: Condition APIs
    description: Condition Controller
  - name: Conditions Status APIs
paths:
  '/v1/{apiKey}/entity/{entityId}':
    post:
      tags:
        - Condition APIs
      summary: Save New Conditions Entity
      operationId: saveNewConditions
      consumes:
        - application/json
      produces:
        - application/json
      parameters:
        - name: Authorization
          in: header
          description: Authorization
          required: true
          type: string
        - name: apiKey
          in: path
          description: API Key
          required: true
          type: string
        - in: body
          name: conditions
          description: Conditions Entity that needs to be saved
          required: true
          schema:
            $ref: '#/definitions/Conditions'
            originalRef: Conditions
        - name: entityId
          in: path
          description: Entity ID
          required: true
          type: string
      responses:
        '200':
          description: OK
          schema:
            $ref: '#/definitions/Conditions'
            originalRef: Conditions
      deprecated: false
    put:
      tags:
        - Condition APIs
      summary: Modify / Overwrite existing Conditions Entity
      operationId: modifyConditions
      consumes:
        - application/json
      produces:
        - application/json
      parameters:
        - name: Authorization
          in: header
          description: Authorization
          required: true
          type: string
        - name: apiKey
          in: path
          description: API Key
          required: true
          type: string
        - in: body
          name: conditions
          description: Conditions Entity that needs to be updated
          required: true
          schema:
            $ref: '#/definitions/Conditions'
            originalRef: Conditions
        - name: entityId
          in: path
          description: Entity ID
          required: true
          type: string
      responses:
        '200':
          description: OK
          schema:
            $ref: '#/definitions/Conditions'
            originalRef: Conditions
      deprecated: false


below is the Java class for parsing above the YAML file and doing the needful.

package com.aos.tools.aostool.yaml;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.util.*;

@Service
public class YamlProcessorGeneric {

    Logger logger = LoggerFactory.getLogger(YamlProcessorGeneric.class);

    public YamlProcessorGeneric() throws IOException {
        process();
    }

    public void process() throws IOException {
        final ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory());

        final Map<String, Object> api = objectMapper.readValue(new File("api-test.yaml"),
                new TypeReference<Map<String, Object>>() {
                });

        final Map<String, Object> path = (Map<String, Object>) api.get("paths");
        extractLinkedHashMap(path);

        // write YAML file
        final Date date = Calendar.getInstance().getTime();
        objectMapper.writeValue(new File(date.toString() + "api-updated.yaml"), api);
    }

    private void extractLinkedHashMap(final Map<String,Object> itemMap) {
        itemMap.entrySet().forEach(k -> {

            // if k is a linkedhashmap and again iterate through
            if(k.getValue() instanceof LinkedHashMap) {
                extractLinkedHashMap((Map<String, Object>) k.getValue());
            }

            // if k is an arraylist then iterate through to till I find a linkedhashmap
            // so that I can remove an item.
            if(k.getValue() instanceof ArrayList) {
                ((ArrayList<?>) k.getValue()).forEach(singleItem -> {
                   if(!(singleItem instanceof String)) {
                       extractLinkedHashMap((Map<String, Object>) singleItem);
                   }
                });
            }

            // check for a specific key , if found remove from the linkedhashmap
            // but this doesn't work
            if(isRemovable(k.getKey())) {
                itemMap.remove(k);
            }

        });
    }

    private boolean isRemovable(final String key) {
        // eg:- I want to remove key with originalRef
        String removableString = "originalRef";
        return key.equals(removableString);
    }
}

for the demonstration process I will attach a screenshot when I was debugging the application. All the values of itemMap .

enter image description here

I'm currently out of options trying out. Please Can anyone give me direction where I'm doing wrong here. Any help would be very much appreciated. Good day!

Nadee
  • 342
  • 1
  • 6
  • 18

1 Answers1

0

If still relevant or somebody want to know, how to do.

First, lets say we have Yaml object:

public class Project  {

    private String name;
    private String description;
    private long lastUpdate;

    public Project() {
    }

    // getter, setter
}

now we want to remove lastUpdate field from data.

  1. Remove getter from Project (update UI to not use getter of property)
  2. Start project
  3. Save the Yaml object again -> lastUpdate property from file is gone
  4. Now you can remove lastUpdate and setter from Project

If the project is already in use by many people:

  1. Remove getter from Project and clean UI
  2. After some time in use can remove the property from file (if all users have ones saved new Yaml object)
anatoli
  • 1,663
  • 1
  • 17
  • 43