CategoryManager.java
/*******************************************************************************
* Copyright (c) 2025 Carsten Hammer.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Carsten Hammer
*******************************************************************************/
package org.sandbox.mining.core.category;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
/**
* Manages the set of commit evaluation categories.
*
* <p>Loads initial categories from the bundled {@code categories.json}
* resource and supports dynamic addition of new categories discovered
* during Gemini evaluation.</p>
*/
public class CategoryManager {
private final List<String> categories;
private final Gson gson;
/**
* Creates a CategoryManager and loads initial categories from resources.
*/
public CategoryManager() {
this.gson = new GsonBuilder().setPrettyPrinting().create();
this.categories = new ArrayList<>(loadInitialCategories());
}
/**
* Creates a CategoryManager with the given categories.
*
* @param categories initial category list
*/
public CategoryManager(List<String> categories) {
this.gson = new GsonBuilder().setPrettyPrinting().create();
this.categories = new ArrayList<>(categories);
}
/**
* Adds a new category if it doesn't already exist.
*
* @param category the category to add
* @return true if the category was added
*/
public boolean addCategory(String category) {
if (category == null || category.isBlank()) {
return false;
}
String normalized = category.trim();
if (categories.stream().anyMatch(c -> c.equalsIgnoreCase(normalized))) {
return false;
}
categories.add(normalized);
return true;
}
/**
* Returns all categories.
*
* @return unmodifiable list of categories
*/
public List<String> getCategories() {
return List.copyOf(categories);
}
/**
* Returns the categories formatted as a JSON array string.
*
* @return JSON array of categories
*/
public String getCategoriesJson() {
return gson.toJson(categories);
}
private static List<String> loadInitialCategories() {
try (InputStream is = CategoryManager.class.getResourceAsStream("/categories.json")) {
if (is == null) {
return getDefaultCategories();
}
String json = new String(is.readAllBytes(), StandardCharsets.UTF_8);
List<String> loaded = new Gson().fromJson(json, new TypeToken<List<String>>() {}.getType());
return loaded != null ? loaded : getDefaultCategories();
} catch (IOException e) {
return getDefaultCategories();
}
}
private static List<String> getDefaultCategories() {
return List.of(
"Collections",
"Java-Modernization",
"Performance",
"Null-Safety",
"JUnit5-Migration",
"Try-with-Resources",
"Lambda-Simplification",
"Encoding",
"String-API");
}
}