Skip to content

Commit

Permalink
Added Javadocs for all of parameter_tools
Browse files Browse the repository at this point in the history
  • Loading branch information
sleepyghost-zzz committed Dec 8, 2024
1 parent 28bf63c commit 1f31fb7
Show file tree
Hide file tree
Showing 4 changed files with 199 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,24 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Annotation to exclude fields from being serialized or deserialized in JSON.
*
* <p>When applied to a field, the field will be ignored during both the serialization and
* deserialization processes. Useful for marking fields that should not be part of the JSON
* representation.
*
* <p>Usage example:
*
* <pre>{@code
* public class Example {
* private String includedField;
*
* @JSONExclude
* private String excludedField;
* }
* }</pre>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface JSONExclude {}
141 changes: 112 additions & 29 deletions parameter_tools/src/main/java/coppercore/parameter_tools/JSONSync.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,44 +11,43 @@
import java.io.FileWriter;
import java.io.IOException;

/**
* A utility class for synchronizing Java objects with JSON files. Provides functionality for
* loading and saving data to a JSON file using the Gson library.
*/
public class JSONSync<T> {

private final Gson gson;

private T instance;

private String file;

private final JSONSyncConfig config;
private final Gson gson; // Gson instance for serialization and deserialization
private T instance; // The object being synchronized
private String file; // File path for the JSON file
private final JSONSyncConfig config; // Configuration for Gson

/**
* Retrieves the object synchronized with the JSON file.
*
* @return The synchronized object.
*/
public T getObject() {
return instance;
}

private FileReader getFileReader(String path) {
try {
return new FileReader(path);
} catch (FileNotFoundException e) {
throw new RuntimeException("File not found " + path, e);
}
}

private FileWriter getFileWriter(String path) {
try {
return new FileWriter(path);
} catch (IOException e) {
throw new RuntimeException("IOException " + path, e);
}
}

/**
* Loads the data from the JSON file into the object.
*
* @throws RuntimeException if the JSON file cannot be read or parsed.
*/
@SuppressWarnings("unchecked")
public void loadData() {
instance = gson.fromJson(getFileReader(file), (Class<T>) instance.getClass());
}

/**
* Saves the current state of the object to the JSON file.
*
* @throws RuntimeException if the JSON file cannot be written.
*/
public void saveData() {
String json = gson.toJson(instance);
// System.out.println(json);
FileWriter writer = getFileWriter(file);
try {
writer.write(json);
Expand All @@ -58,10 +57,34 @@ public void saveData() {
}
}

/**
* Sets the file path for the JSON file.
*
* @param newFilePath The new file path for the JSON file.
*/
public void setFile(String newFilePath) {
file = newFilePath;
}

/**
* Constructs a new JSONSync instance.
*
* @param instance The object to synchronize with the JSON file.
* @param file The file path for the JSON file.
* @param config Configuration for the Gson instance; uses defaults if null.
*/
public JSONSync(T instance, String file, JSONSyncConfig config) {
this.instance = instance;
this.config = (config == null) ? new JSONSyncConfigBuilder().build() : config;
this.gson = generateGson();
this.file = file;
}

/**
* Generates a Gson instance with the current configuration.
*
* @return A configured Gson instance.
*/
private Gson generateGson() {
ExclusionStrategy strategy =
new ExclusionStrategy() {
Expand All @@ -88,13 +111,37 @@ public boolean shouldSkipClass(Class<?> clazz) {
return builder.create();
}

public JSONSync(T instance, String file, JSONSyncConfig config) {
this.instance = instance;
this.config = (config == null) ? new JSONSyncConfigBuilder().build() : config;
this.gson = generateGson();
this.file = file;
/**
* Provides a FileReader for the given file path.
*
* @param path The file path.
* @return A FileReader for the specified file.
* @throws RuntimeException if the file cannot be found.
*/
private FileReader getFileReader(String path) {
try {
return new FileReader(path);
} catch (FileNotFoundException e) {
throw new RuntimeException("File not found " + path, e);
}
}

/**
* Provides a FileWriter for the given file path.
*
* @param path The file path.
* @return A FileWriter for the specified file.
* @throws RuntimeException if the file cannot be created or written to.
*/
private FileWriter getFileWriter(String path) {
try {
return new FileWriter(path);
} catch (IOException e) {
throw new RuntimeException("IOException " + path, e);
}
}

/** Configuration class for customizing Gson behavior. */
private static record JSONSyncConfig(
boolean serializeNulls,
boolean prettyPrinting,
Expand All @@ -111,40 +158,76 @@ public JSONSyncConfig(JSONSyncConfigBuilder builder) {
}
}

/** Builder class for creating a JSONSyncConfig instance. */
public static class JSONSyncConfigBuilder {
public boolean serializeNulls = false;
public boolean prettyPrinting = false;
public boolean excludeFieldsWithoutExposeAnnotation = false;
public FieldNamingPolicy namingPolicy = FieldNamingPolicy.IDENTITY;
public LongSerializationPolicy longSerializationPolicy = LongSerializationPolicy.DEFAULT;

/**
* Sets whether null fields should be serialized.
*
* @param serializeNulls True to serialize null fields, false otherwise.
* @return The builder instance.
*/
public JSONSyncConfigBuilder setSerializeNulls(boolean serializeNulls) {
this.serializeNulls = serializeNulls;
return this;
}

/**
* Sets whether the JSON output should use pretty printing.
*
* @param prettyPrinting True to enable pretty printing, false otherwise.
* @return The builder instance.
*/
public JSONSyncConfigBuilder setPrettyPrinting(boolean prettyPrinting) {
this.prettyPrinting = prettyPrinting;
return this;
}

/**
* Sets whether fields without @Expose annotations should be excluded.
*
* @param excludeFieldsWithoutExposeAnnotation True to exclude fields, false otherwise.
* @return The builder instance.
*/
public JSONSyncConfigBuilder setExcludeFieldsWithoutExposeAnnotation(
boolean excludeFieldsWithoutExposeAnnotation) {
this.excludeFieldsWithoutExposeAnnotation = excludeFieldsWithoutExposeAnnotation;
return this;
}

/**
* Sets the naming policy for fields in the JSON output.
*
* @param namingPolicy The field naming policy.
* @return The builder instance.
*/
public JSONSyncConfigBuilder setNamingPolicy(FieldNamingPolicy namingPolicy) {
this.namingPolicy = namingPolicy;
return this;
}

/**
* Sets the serialization policy for long values.
*
* @param longSerializationPolicy The serialization policy for long values.
* @return The builder instance.
*/
public JSONSyncConfigBuilder setLongSerializationPolicy(
LongSerializationPolicy longSerializationPolicy) {
this.longSerializationPolicy = longSerializationPolicy;
return this;
}

/**
* Builds the configuration object.
*
* @return A JSONSyncConfig instance.
*/
public JSONSyncConfig build() {
return new JSONSyncConfig(this);
}
Expand Down
32 changes: 31 additions & 1 deletion parameter_tools/src/test/java/ExampleJsonSyncClass.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,53 @@

import coppercore.parameter_tools.JSONSync;

/**
* Example class to demonstrate the usage of the {@link JSONSync} utility for saving and loading
* data in JSON format.
*
* <p>This class showcases how fields can be serialized and deserialized, including nested objects,
* using the {@link JSONSync} functionality.
*
* <p>Key features:
*
* <ul>
* <li>Defines several fields of various types to demonstrate JSON serialization.
* <li>Includes a nested class {@code BasicMotorDataHolder} to demonstrate handling nested data
* structures.
* <li>Utilizes {@link JSONSync} to manage serialization and deserialization with the associated
* JSON file.
* </ul>
*/
public class ExampleJsonSyncClass {

/**
* Static {@link JSONSync} instance for managing the serialization and deserialization of this
* class.
*/
public static JSONSync<ExampleJsonSyncClass> synced =
new JSONSync<ExampleJsonSyncClass>(
new JSONSync<>(
new ExampleJsonSyncClass(),
"filePath",
new JSONSync.JSONSyncConfigBuilder().build());

public final String testText = "";

public final Double testDouble = 0.0;

public Integer testInt = 0;

public final BasicMotorDataHolder motorData = null;

/** Nested class to represent motor-related data. */
public class BasicMotorDataHolder {

public final Double maxVoltage = 0.0;

public final Double minVoltage = 0.0;

public Double currentVoltage = 0.0;

@Override
public String toString() {
return "minVoltage: "
+ minVoltage
Expand All @@ -30,6 +59,7 @@ public String toString() {
}
}

@Override
public String toString() {
return "testText: "
+ testText
Expand Down
49 changes: 38 additions & 11 deletions parameter_tools/src/test/java/JSONSyncTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,50 +6,77 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

/**
* Unit tests for the {@link JSONSync} class to validate its functionality, including data loading,
* file setting, and data saving.
*
* <p>This test class uses JUnit 5 to ensure that {@link JSONSync} correctly serializes and
* deserializes objects to and from JSON files. It also verifies that {@link JSONSync} updates files
* when data changes.
*/
public class JSONSyncTests {

/** Directory paths for storing and accessing test JSON files. */
public static final String DIRECTORY = new File("").getAbsolutePath();

public static final String BUILD_DIRECTORY = DIRECTORY + "/build";
public static final String RESOURCE_DIRECTORY = BUILD_DIRECTORY + "/resources/test";

/**
* Prepares a new {@link JSONSync} instance with a predefined configuration and file path before
* each test.
*/
@BeforeEach
public void TestPrep() {
ExampleJsonSyncClass.synced =
new JSONSync<ExampleJsonSyncClass>(
new JSONSync<>(
new ExampleJsonSyncClass(),
RESOURCE_DIRECTORY + "/ExampleJsonSyncClass.json",
new JSONSync.JSONSyncConfigBuilder().setPrettyPrinting(true).build());
}

/**
* Tests the {@link JSONSync#loadData} method to ensure data is correctly loaded from a JSON
* file.
*/
@Test
public void JsonSyncLoadDataTest() {
ExampleJsonSyncClass.synced.loadData();
ExampleJsonSyncClass instance = ExampleJsonSyncClass.synced.getObject();

Assertions.assertEquals(10.0, instance.testDouble);
Assertions.assertEquals(2, instance.testInt);
Assertions.assertNull(instance.motorData);
Assertions.assertEquals(10.0, instance.testDouble, "testDouble should be 10.0");
Assertions.assertEquals(2, instance.testInt, "testInt should be 2");
Assertions.assertNull(instance.motorData, "motorData should be null");
}

/**
* Tests the {@link JSONSync#setFile} method to verify it properly updates the file path and
* loads data from the newly specified file.
*/
@Test
public void JsonSyncSetFileTest() {
ExampleJsonSyncClass.synced.setFile(RESOURCE_DIRECTORY + "/SetFileTest.json");
ExampleJsonSyncClass.synced.loadData();
ExampleJsonSyncClass instance = ExampleJsonSyncClass.synced.getObject();

Assertions.assertEquals(10.0, instance.testDouble);
Assertions.assertEquals(2, instance.testInt);
Assertions.assertNotNull(instance.motorData);
Assertions.assertEquals(-12.3, instance.motorData.minVoltage);
Assertions.assertEquals(16.4, instance.motorData.maxVoltage);
Assertions.assertEquals(0.0, instance.motorData.currentVoltage);
Assertions.assertEquals(10.0, instance.testDouble, "testDouble should be 10.0");
Assertions.assertEquals(2, instance.testInt, "testInt should be 2");
Assertions.assertNotNull(instance.motorData, "motorData should not be null");
Assertions.assertEquals(-12.3, instance.motorData.minVoltage, "minVoltage should be -12.3");
Assertions.assertEquals(16.4, instance.motorData.maxVoltage, "maxVoltage should be 16.4");
Assertions.assertEquals(
0.0, instance.motorData.currentVoltage, "currentVoltage should be 0.0");
}

/**
* Tests the {@link JSONSync#saveData} method to ensure changes to an object are serialized and
* saved to a JSON file correctly.
*/
@Test
public void JsonSyncSaveFileTest() {
ExampleJsonSyncClass.synced.loadData();
ExampleJsonSyncClass instance = ExampleJsonSyncClass.synced.getObject();
instance.testInt = 10;
instance.testInt = 10; // Modify a value in the object
ExampleJsonSyncClass.synced.setFile(RESOURCE_DIRECTORY + "/SaveFileTest.json");
ExampleJsonSyncClass.synced.saveData();
}
Expand Down

0 comments on commit 1f31fb7

Please sign in to comment.