Skip to content

Commit

Permalink
docs: document the serializer and parser classes
Browse files Browse the repository at this point in the history
  • Loading branch information
DaubieMatthieu committed May 7, 2023
1 parent cfcc9b2 commit 93aa85c
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 8 deletions.
54 changes: 47 additions & 7 deletions src/main/java/io/github/mdaubie/subtitlesparser/Parser.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,30 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* A class to parse the content of a subtitles file into a SubtitlesFile object.
* The constructor requires a Format object, corresponding to the type of SubtitlesFile to parse.
* @see Format
* @param <SF> The type of SubtitlesFile to parse
*/
public record Parser<SF extends SubtitlesFile>(Format<SF> format) {

/**
* Parse the provided file into a SubtitlesFile object
*
* @param file The file to parse
* @throws IOException If the provided file is not valid or an I/O error occurs
*/
@SuppressWarnings("unused")
public SF parseFile(File file) throws IOException {
return parse(Files.readString(file.toPath()));
}

/**
* Parse the provided String into a SubtitlesFile object
*
* @param text The file content to parse
* @throws UnexpectedException If the file content is not structured as expected by the defined format
*/
public SF parse(String text) throws UnexpectedException {
Matcher matcher = PatternHolder.getPattern(format.baseClass()).matcher(text);
if (!matcher.matches())
Expand All @@ -42,25 +60,47 @@ private <T extends PatternedObject> T dynamicParse(Matcher matcher, Class<T> typ
}
return object;
} catch (ReflectiveOperationException e) {
e.printStackTrace();
return null;
throw new UnexpectedException("Reflective operation unexpectedly failed", e);
}
}

/**
* Parse the provided text into an object corresponding to the type of the field specified
*
* @param value The text to parse
* @param field The field in which the parsed object will be injected
* @return The parsed object
* @throws UnexpectedException If the field type is not handled by the parser
*/
//TODO we might want to register some Functions<> to handle the types
private Object parseObject(String value, Field field) throws UnexpectedException {
Class<?> type = field.getType();
if (type == String.class) return value;
if (type == Integer.class) return Integer.parseInt(value);
if (type == LocalTime.class) return LocalTime.parse(value, format.timestampsFormat());
if (type == List.class) return parseList(value, (ParameterizedType) field.getGenericType());
if (type == List.class)
return parseList(value, ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0]);
throw new UnexpectedException(String.format("Type %s is not handled by parser", type));
}

private <T extends PatternedObject> List<T> parseList(String value, ParameterizedType type) throws UnexpectedException {
Type elementType = type.getActualTypeArguments()[0];
/**
* Parse the provided String into a list of the specified type (expected to be a PatternedObject)
*
* @param value The text to parse
* @param type The type of the list elements
* @param <T> The generic type of the lists elements
* @return The parsed list
* @throws UnexpectedException If the specified type does not correspond to the generic type of if a parsing exception happens recursively
*/
private <T extends PatternedObject> List<T> parseList(String value, Type type) throws UnexpectedException {
//TODO might need to implement basic types handling for some of the formats
@SuppressWarnings("unchecked") Class<T> elementClass = (Class<T>) elementType;
Class<T> elementClass;
try {
//noinspection unchecked
elementClass = (Class<T>) type;
} catch (ClassCastException e) {
throw new UnexpectedException(String.format("Provided type %s does not correspond to expected PatternedObject class", type));
}
Pattern pattern = PatternHolder.getPattern(elementClass);
Matcher matcher = pattern.matcher(value);
List<T> list = new ArrayList<>();
Expand Down
43 changes: 42 additions & 1 deletion src/main/java/io/github/mdaubie/subtitlesparser/Serializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,34 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* A class to serialize a SubtitlesFile object into a text, ready to be written to a file.
* The constructor requires a Format object, corresponding to the type of SubtitlesFile to serialize.
* @see Format
* @param <SF> The type of SubtitlesFile to serialize
*/
public record Serializer<SF extends SubtitlesFile>(Format<SF> format) {
/**
* Serialize the provided SubtitlesFile and write it to the provided File
*
* @param subtitlesFile Subtitles file to serialize
* @param file File to which to write the serialized result
* @throws IOException If the provided file is not valid or an I/O error occurs
*/
@SuppressWarnings("unused")
public void writeToFile(SF subtitlesFile, File file) throws IOException {
BufferedWriter writer = new BufferedWriter(new FileWriter(file));
writer.append(serialize(subtitlesFile));
writer.close();
}

/**
* Serialize a SubtitlesFile object into a ready-to-write String
*
* @param sf The subtitles file object to serialize
* @return The serialized file, ready to be written to a file
* @throws UnexpectedException If
*/
public String serialize(SF sf) throws UnexpectedException {
return dynamicSerialize(sf);
}
Expand All @@ -34,6 +55,14 @@ private String dynamicSerialize(PatternedObject object) throws UnexpectedExcepti
return template;
}

/**
* Serialize the specified field of a given patterned object
*
* @param patternedObject The object being serialized
* @param field The field to serialize
* @return The serialized field
* @throws UnexpectedException If the type of the field is not supported by the serializer (can happen if you are using custom patterned objects)
*/
private String serializeAttribute(PatternedObject patternedObject, Field field) throws UnexpectedException {
Class<?> type = field.getType();
Object fieldObject;
Expand All @@ -52,6 +81,13 @@ private String serializeAttribute(PatternedObject patternedObject, Field field)
throw new UnexpectedException(String.format("Type %s is not handled by serializer when serializing class %s", type, fieldObject.getClass()));
}

/**
* Cast the provided object into a list and serialize its elements (for now only list of PatternedObject are supported)
*
* @param object The object to serialize as a list
* @return The serialized object
* @throws UnexpectedException If the type of the list elements is not PatternedObject
*/
private String serializeList(Object object) throws UnexpectedException {
StringBuilder content = new StringBuilder();
List<?> list = (List<?>) object;
Expand All @@ -65,7 +101,12 @@ private String serializeList(Object object) throws UnexpectedException {
return content.toString();
}

// method to transform regex Pattern into corresponding String template, with placeholders to be replaced by actual values
/**
* Reverse engineer a regex Pattern into its corresponding String template, with placeholders to be replaced by actual values
*
* @param pattern The pattern to convert into a template
* @return The template
*/
// TODO we should actually use something similar as the pattern holder, to not reprocess it everytime
public static String patternToStringTemplate(Pattern pattern) {
String regex = "(\\(\\?<(?<groupName>.*?)>.*?\\))";
Expand Down

0 comments on commit 93aa85c

Please sign in to comment.