Skip to content

Commit

Permalink
Add javadoc for vision and parameter tools (#68)
Browse files Browse the repository at this point in the history
* Added Javadocs for all of vision.

* Added Javadocs for all of parameter_tools
  • Loading branch information
sleepyghost-zzz authored Dec 9, 2024
1 parent 1ad04a3 commit ddc04e0
Show file tree
Hide file tree
Showing 15 changed files with 459 additions and 85 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
Loading

0 comments on commit ddc04e0

Please sign in to comment.