mirror of
https://github.com/JHUAPL/jsqrl.git
synced 2026-01-06 19:03:58 -05:00
Initial import of metadata code moved from crucible-crust.
This commit is contained in:
21
.classpath
Normal file
21
.classpath
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry exported="true" kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-16">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/5"/>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
2
.factorypath
Normal file
2
.factorypath
Normal file
@@ -0,0 +1,2 @@
|
||||
<factorypath>
|
||||
</factorypath>
|
||||
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target/
|
||||
24
.project
Normal file
24
.project
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>jsqrl</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.apache.ivyde.eclipse.ivynature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
4
.settings/org.eclipse.core.resources.prefs
Normal file
4
.settings/org.eclipse.core.resources.prefs
Normal file
@@ -0,0 +1,4 @@
|
||||
eclipse.preferences.version=1
|
||||
encoding//Users/steelrj1/git_pristine/saavtk=UTF-8
|
||||
encoding/<project>=UTF-8
|
||||
encoding/src=UTF-8
|
||||
513
.settings/org.eclipse.jdt.core.prefs
Normal file
513
.settings/org.eclipse.jdt.core.prefs
Normal file
@@ -0,0 +1,513 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled
|
||||
org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
|
||||
org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
|
||||
org.eclipse.jdt.core.compiler.annotation.nonnull.secondary=
|
||||
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
|
||||
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault.secondary=
|
||||
org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
|
||||
org.eclipse.jdt.core.compiler.annotation.nullable.secondary=
|
||||
org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=16
|
||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||
org.eclipse.jdt.core.compiler.compliance=16
|
||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||
org.eclipse.jdt.core.compiler.problem.APILeak=warning
|
||||
org.eclipse.jdt.core.compiler.problem.annotatedTypeArgumentToUnannotated=info
|
||||
org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
|
||||
org.eclipse.jdt.core.compiler.problem.deadCode=warning
|
||||
org.eclipse.jdt.core.compiler.problem.deprecation=warning
|
||||
org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
|
||||
org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
|
||||
org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||
org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
|
||||
org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
|
||||
org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
|
||||
org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
|
||||
org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.missingSerialVersion=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
|
||||
org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
|
||||
org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning
|
||||
org.eclipse.jdt.core.compiler.problem.nonnullTypeVariableFromLegacyInvocation=warning
|
||||
org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
|
||||
org.eclipse.jdt.core.compiler.problem.nullReference=warning
|
||||
org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
|
||||
org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
|
||||
org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
|
||||
org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.pessimisticNullAnalysisForFreeTypeVariables=warning
|
||||
org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
|
||||
org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
|
||||
org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
|
||||
org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
|
||||
org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.suppressWarningsNotFullyAnalysed=info
|
||||
org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.terminalDeprecation=warning
|
||||
org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning
|
||||
org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentType=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentTypeStrict=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unlikelyEqualsArgumentType=info
|
||||
org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unstableAutoModuleName=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedImport=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
|
||||
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
|
||||
org.eclipse.jdt.core.compiler.release=enabled
|
||||
org.eclipse.jdt.core.compiler.source=16
|
||||
org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false
|
||||
org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
|
||||
org.eclipse.jdt.core.formatter.align_selector_in_method_invocation_on_expression_first_line=false
|
||||
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
|
||||
org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns=false
|
||||
org.eclipse.jdt.core.formatter.align_with_spaces=false
|
||||
org.eclipse.jdt.core.formatter.alignment_for_additive_operator=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_enum_constant=49
|
||||
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_field=49
|
||||
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_local_variable=49
|
||||
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_method=49
|
||||
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_package=49
|
||||
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_parameter=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type=49
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=48
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_assertion_message=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_assignment=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_compact_if=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_compact_loops=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_enum_constants=48
|
||||
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_arrow=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_colon=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_logical_operator=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_module_statements=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_permitted_types_in_type_declaration=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_record_components=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_relational_operator=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_shift_operator=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_string_concatenation=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_record_declaration=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_switch_case_with_arrow=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_type_annotations=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_after_package=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_field=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_method=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_package=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=next_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_block=next_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=next_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=next_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=next_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=next_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=next_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_record_constructor=next_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_record_declaration=next_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_switch=next_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=next_line
|
||||
org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped=false
|
||||
org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions=false
|
||||
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
|
||||
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
|
||||
org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_block_comments=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_header=false
|
||||
org.eclipse.jdt.core.formatter.comment.format_html=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_line_comments=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_source_code=true
|
||||
org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
|
||||
org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
|
||||
org.eclipse.jdt.core.formatter.comment.indent_tag_description=false
|
||||
org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
|
||||
org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags=do not insert
|
||||
org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
|
||||
org.eclipse.jdt.core.formatter.comment.line_length=132
|
||||
org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
|
||||
org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
|
||||
org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
|
||||
org.eclipse.jdt.core.formatter.compact_else_if=true
|
||||
org.eclipse.jdt.core.formatter.continuation_indentation=2
|
||||
org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
|
||||
org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
|
||||
org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
|
||||
org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=false
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_record_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
|
||||
org.eclipse.jdt.core.formatter.indent_empty_lines=false
|
||||
org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
|
||||
org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
|
||||
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
|
||||
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
|
||||
org.eclipse.jdt.core.formatter.indentation.size=4
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_additive_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_permitted_types=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_record_components=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_logical_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_not_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_record_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_relational_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_shift_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_additive_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_record_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_permitted_types=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_record_components=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_logical_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_constructor=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_record_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_relational_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_shift_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.join_lines_in_comments=true
|
||||
org.eclipse.jdt.core.formatter.join_wrapped_lines=false
|
||||
org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line=one_line_if_empty
|
||||
org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line=one_line_if_empty
|
||||
org.eclipse.jdt.core.formatter.keep_code_block_on_one_line=one_line_if_empty
|
||||
org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line=one_line_if_empty
|
||||
org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line=one_line_if_empty
|
||||
org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line=one_line_if_empty
|
||||
org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line=one_line_if_empty
|
||||
org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line=one_line_if_empty
|
||||
org.eclipse.jdt.core.formatter.keep_method_body_on_one_line=one_line_if_empty
|
||||
org.eclipse.jdt.core.formatter.keep_record_constructor_on_one_line=one_line_if_empty
|
||||
org.eclipse.jdt.core.formatter.keep_record_declaration_on_one_line=one_line_if_empty
|
||||
org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_switch_body_block_on_one_line=one_line_never
|
||||
org.eclipse.jdt.core.formatter.keep_switch_case_with_arrow_on_one_line=one_line_never
|
||||
org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line=one_line_if_empty
|
||||
org.eclipse.jdt.core.formatter.lineSplit=132
|
||||
org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
|
||||
org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
|
||||
org.eclipse.jdt.core.formatter.number_of_blank_lines_after_code_block=0
|
||||
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block=0
|
||||
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
|
||||
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block=0
|
||||
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body=0
|
||||
org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block=0
|
||||
org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_record_declaration=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines
|
||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines
|
||||
org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
|
||||
org.eclipse.jdt.core.formatter.tabulation.char=space
|
||||
org.eclipse.jdt.core.formatter.tabulation.size=4
|
||||
org.eclipse.jdt.core.formatter.text_block_indentation=0
|
||||
org.eclipse.jdt.core.formatter.use_on_off_tags=false
|
||||
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
|
||||
org.eclipse.jdt.core.formatter.wrap_before_additive_operator=true
|
||||
org.eclipse.jdt.core.formatter.wrap_before_assertion_message_operator=true
|
||||
org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false
|
||||
org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator=true
|
||||
org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true
|
||||
org.eclipse.jdt.core.formatter.wrap_before_logical_operator=true
|
||||
org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator=true
|
||||
org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
|
||||
org.eclipse.jdt.core.formatter.wrap_before_relational_operator=true
|
||||
org.eclipse.jdt.core.formatter.wrap_before_shift_operator=true
|
||||
org.eclipse.jdt.core.formatter.wrap_before_string_concatenation=true
|
||||
org.eclipse.jdt.core.formatter.wrap_before_switch_case_arrow_operator=false
|
||||
org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
|
||||
org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
|
||||
144
.settings/org.eclipse.jdt.ui.prefs
Normal file
144
.settings/org.eclipse.jdt.ui.prefs
Normal file
@@ -0,0 +1,144 @@
|
||||
eclipse.preferences.version=1
|
||||
editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
|
||||
formatter_profile=_SBMT
|
||||
formatter_settings_version=23
|
||||
sp_cleanup.add_all=false
|
||||
sp_cleanup.add_default_serial_version_id=true
|
||||
sp_cleanup.add_generated_serial_version_id=false
|
||||
sp_cleanup.add_missing_annotations=true
|
||||
sp_cleanup.add_missing_deprecated_annotations=true
|
||||
sp_cleanup.add_missing_methods=false
|
||||
sp_cleanup.add_missing_nls_tags=false
|
||||
sp_cleanup.add_missing_override_annotations=true
|
||||
sp_cleanup.add_missing_override_annotations_interface_methods=true
|
||||
sp_cleanup.add_serial_version_id=false
|
||||
sp_cleanup.always_use_blocks=true
|
||||
sp_cleanup.always_use_parentheses_in_expressions=false
|
||||
sp_cleanup.always_use_this_for_non_static_field_access=false
|
||||
sp_cleanup.always_use_this_for_non_static_method_access=false
|
||||
sp_cleanup.array_with_curly=false
|
||||
sp_cleanup.arrays_fill=false
|
||||
sp_cleanup.bitwise_conditional_expression=false
|
||||
sp_cleanup.boolean_literal=false
|
||||
sp_cleanup.boolean_value_rather_than_comparison=false
|
||||
sp_cleanup.break_loop=false
|
||||
sp_cleanup.collection_cloning=false
|
||||
sp_cleanup.comparing_on_criteria=false
|
||||
sp_cleanup.comparison_statement=false
|
||||
sp_cleanup.controlflow_merge=false
|
||||
sp_cleanup.convert_functional_interfaces=false
|
||||
sp_cleanup.convert_to_enhanced_for_loop=false
|
||||
sp_cleanup.convert_to_enhanced_for_loop_if_loop_var_used=false
|
||||
sp_cleanup.convert_to_switch_expressions=false
|
||||
sp_cleanup.correct_indentation=false
|
||||
sp_cleanup.do_while_rather_than_while=false
|
||||
sp_cleanup.double_negation=false
|
||||
sp_cleanup.else_if=false
|
||||
sp_cleanup.embedded_if=false
|
||||
sp_cleanup.evaluate_nullable=false
|
||||
sp_cleanup.extract_increment=false
|
||||
sp_cleanup.format_source_code=true
|
||||
sp_cleanup.format_source_code_changes_only=false
|
||||
sp_cleanup.hash=false
|
||||
sp_cleanup.if_condition=false
|
||||
sp_cleanup.insert_inferred_type_arguments=false
|
||||
sp_cleanup.instanceof=false
|
||||
sp_cleanup.instanceof_keyword=false
|
||||
sp_cleanup.invert_equals=false
|
||||
sp_cleanup.join=false
|
||||
sp_cleanup.lazy_logical_operator=false
|
||||
sp_cleanup.make_local_variable_final=true
|
||||
sp_cleanup.make_parameters_final=false
|
||||
sp_cleanup.make_private_fields_final=true
|
||||
sp_cleanup.make_type_abstract_if_missing_method=false
|
||||
sp_cleanup.make_variable_declarations_final=false
|
||||
sp_cleanup.map_cloning=false
|
||||
sp_cleanup.merge_conditional_blocks=false
|
||||
sp_cleanup.multi_catch=false
|
||||
sp_cleanup.never_use_blocks=false
|
||||
sp_cleanup.never_use_parentheses_in_expressions=true
|
||||
sp_cleanup.no_string_creation=false
|
||||
sp_cleanup.no_super=false
|
||||
sp_cleanup.number_suffix=false
|
||||
sp_cleanup.objects_equals=false
|
||||
sp_cleanup.on_save_use_additional_actions=false
|
||||
sp_cleanup.one_if_rather_than_duplicate_blocks_that_fall_through=false
|
||||
sp_cleanup.operand_factorization=false
|
||||
sp_cleanup.organize_imports=true
|
||||
sp_cleanup.overridden_assignment=false
|
||||
sp_cleanup.overridden_assignment_move_decl=true
|
||||
sp_cleanup.plain_replacement=false
|
||||
sp_cleanup.precompile_regex=false
|
||||
sp_cleanup.primitive_comparison=false
|
||||
sp_cleanup.primitive_parsing=false
|
||||
sp_cleanup.primitive_rather_than_wrapper=false
|
||||
sp_cleanup.primitive_serialization=false
|
||||
sp_cleanup.pull_out_if_from_if_else=false
|
||||
sp_cleanup.pull_up_assignment=false
|
||||
sp_cleanup.push_down_negation=false
|
||||
sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
|
||||
sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
|
||||
sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
|
||||
sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
|
||||
sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
|
||||
sp_cleanup.reduce_indentation=false
|
||||
sp_cleanup.redundant_comparator=false
|
||||
sp_cleanup.redundant_falling_through_block_end=false
|
||||
sp_cleanup.remove_private_constructors=true
|
||||
sp_cleanup.remove_redundant_modifiers=false
|
||||
sp_cleanup.remove_redundant_semicolons=false
|
||||
sp_cleanup.remove_redundant_type_arguments=false
|
||||
sp_cleanup.remove_trailing_whitespaces=false
|
||||
sp_cleanup.remove_trailing_whitespaces_all=true
|
||||
sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
|
||||
sp_cleanup.remove_unnecessary_array_creation=false
|
||||
sp_cleanup.remove_unnecessary_casts=true
|
||||
sp_cleanup.remove_unnecessary_nls_tags=false
|
||||
sp_cleanup.remove_unused_imports=false
|
||||
sp_cleanup.remove_unused_local_variables=false
|
||||
sp_cleanup.remove_unused_method_parameters=false
|
||||
sp_cleanup.remove_unused_private_fields=true
|
||||
sp_cleanup.remove_unused_private_members=false
|
||||
sp_cleanup.remove_unused_private_methods=true
|
||||
sp_cleanup.remove_unused_private_types=true
|
||||
sp_cleanup.return_expression=false
|
||||
sp_cleanup.simplify_lambda_expression_and_method_ref=false
|
||||
sp_cleanup.single_used_field=false
|
||||
sp_cleanup.sort_members=false
|
||||
sp_cleanup.sort_members_all=false
|
||||
sp_cleanup.standard_comparison=false
|
||||
sp_cleanup.static_inner_class=false
|
||||
sp_cleanup.strictly_equal_or_different=false
|
||||
sp_cleanup.stringbuffer_to_stringbuilder=false
|
||||
sp_cleanup.stringbuilder=false
|
||||
sp_cleanup.stringbuilder_for_local_vars=true
|
||||
sp_cleanup.stringconcat_to_textblock=false
|
||||
sp_cleanup.substring=false
|
||||
sp_cleanup.switch=false
|
||||
sp_cleanup.system_property=false
|
||||
sp_cleanup.system_property_boolean=false
|
||||
sp_cleanup.system_property_file_encoding=false
|
||||
sp_cleanup.system_property_file_separator=false
|
||||
sp_cleanup.system_property_line_separator=false
|
||||
sp_cleanup.system_property_path_separator=false
|
||||
sp_cleanup.ternary_operator=false
|
||||
sp_cleanup.try_with_resource=false
|
||||
sp_cleanup.unlooped_while=false
|
||||
sp_cleanup.unreachable_block=false
|
||||
sp_cleanup.use_anonymous_class_creation=false
|
||||
sp_cleanup.use_autoboxing=false
|
||||
sp_cleanup.use_blocks=false
|
||||
sp_cleanup.use_blocks_only_for_return_and_throw=false
|
||||
sp_cleanup.use_directly_map_method=false
|
||||
sp_cleanup.use_lambda=true
|
||||
sp_cleanup.use_parentheses_in_expressions=false
|
||||
sp_cleanup.use_string_is_blank=false
|
||||
sp_cleanup.use_this_for_non_static_field_access=false
|
||||
sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
|
||||
sp_cleanup.use_this_for_non_static_method_access=false
|
||||
sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
|
||||
sp_cleanup.use_unboxing=false
|
||||
sp_cleanup.use_var=false
|
||||
sp_cleanup.useless_continue=false
|
||||
sp_cleanup.useless_return=false
|
||||
sp_cleanup.valueof_rather_than_instantiation=false
|
||||
4
.settings/org.eclipse.m2e.core.prefs
Normal file
4
.settings/org.eclipse.m2e.core.prefs
Normal file
@@ -0,0 +1,4 @@
|
||||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
resolveWorkspaceProjects=true
|
||||
version=1
|
||||
2
.settings/org.jboss.ide.eclipse.as.core.prefs
Normal file
2
.settings/org.jboss.ide.eclipse.as.core.prefs
Normal file
@@ -0,0 +1,2 @@
|
||||
eclipse.preferences.version=1
|
||||
org.jboss.ide.eclipse.as.core.singledeployable.deployableList=
|
||||
222
pom.xml
Normal file
222
pom.xml
Normal file
@@ -0,0 +1,222 @@
|
||||
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>edu.jhuapl.ses.jsqrl</groupId>
|
||||
<artifactId>jsqrl</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>0.0.1</version>
|
||||
<name>jsqrl</name>
|
||||
<description>VTK Support library</description>
|
||||
<organization>
|
||||
<name>Johns Hopkins University Applied Physics Lab</name>
|
||||
<url>https://www.jhuapl.edu</url>
|
||||
</organization>
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>central</id>
|
||||
<name>surfshop-releases</name>
|
||||
<url>http://surfshop.jhuapl.edu:8081/artifactory/libs-release-local</url>
|
||||
</repository>
|
||||
<snapshotRepository>
|
||||
<id>central</id>
|
||||
<name>surfshop-snapshots</name>
|
||||
<url>http://surfshop.jhuapl.edu:8081/artifactory/libs-snapshot-local</url>
|
||||
</snapshotRepository>
|
||||
</distributionManagement>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<maven.compiler.source>16</maven.compiler.source>
|
||||
<maven.compiler.target>16</maven.compiler.target>
|
||||
<vtkVersion>1.0.0.25</vtkVersion>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>31.1-jre</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.8.6</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<scm>
|
||||
<connection>scm:git:http://hardin:8080/scm/git/vtk/saavtk</connection>
|
||||
<developerConnection>scm:git:http://hardin:8080/scm/git/vtk/saavtk</developerConnection>
|
||||
</scm>
|
||||
<!-- Issue Management - TO BE UPDATED -->
|
||||
<issueManagement>
|
||||
<system>Quiver</system>
|
||||
<url>https://quiver.jhuapl.edu/saavtk/issues</url>
|
||||
</issueManagement>
|
||||
<!-- Repositories, so can be built on checkout without settings.xml file in place -->
|
||||
<repositories>
|
||||
<repository>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
<id>thirdparty</id>
|
||||
<name>libs-3rdparty-local</name>
|
||||
<url>http://surfshop.jhuapl.edu:8081/artifactory/libs-3rdparty-local</url>
|
||||
</repository>
|
||||
|
||||
<repository>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
<id>central</id>
|
||||
<name>libs-release</name>
|
||||
<url>https://surfshop:8081/artifactory/libs-release</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<snapshots />
|
||||
<id>snapshots</id>
|
||||
<name>libs-snapshot</name>
|
||||
<url>https://surfshop:8081/artifactory/libs-snapshot</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
<id>OSGeo</id>
|
||||
<name>release</name>
|
||||
<url>https://repo.osgeo.org/repository/release/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
<id>central2</id>
|
||||
<name>libs-release</name>
|
||||
<url>https://repo1.maven.org/maven2/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<snapshots />
|
||||
<id>snapshots2</id>
|
||||
<name>libs-snapshot</name>
|
||||
<url>https://repo1.maven.org/maven2/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
<id>central</id>
|
||||
<name>libs-release</name>
|
||||
<url>https://surfshop:8081/artifactory/libs-release</url>
|
||||
</pluginRepository>
|
||||
<pluginRepository>
|
||||
<snapshots />
|
||||
<id>snapshots</id>
|
||||
<name>libs-snapshot</name>
|
||||
<url>https://surfshop:8081/artifactory/libs-snapshot</url>
|
||||
</pluginRepository>
|
||||
<pluginRepository>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
<id>central2</id>
|
||||
<name>plugins-release</name>
|
||||
<url>https://repo1.maven.org/maven2/</url>
|
||||
</pluginRepository>
|
||||
<pluginRepository>
|
||||
<snapshots />
|
||||
<id>snapshots2</id>
|
||||
<name>plugins-snapshot</name>
|
||||
<url>https://repo1.maven.org/maven2/</url>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
<build>
|
||||
<sourceDirectory>src</sourceDirectory>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<configuration>
|
||||
<release>16</release>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>3.2.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-sources</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<executions>
|
||||
<!--
|
||||
<execution>
|
||||
<?m2e execute onConfiguration,onIncremental?>
|
||||
<phase>compile</phase>
|
||||
<configuration>
|
||||
<target>
|
||||
<mkdir dir="${project.build.directory}/classes/edu/jhuapl/ses/jsqrl/data"/>
|
||||
<copy todir="${project.build.directory}/classes/edu/jhuapl/ses/jsqrl/data">
|
||||
<fileset dir="src/edu/jhuapl/ses/jsqrl/data"/>
|
||||
</copy>
|
||||
</target>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>toolbar_icons</id>
|
||||
<?m2e execute onConfiguration,onIncremental?>
|
||||
<phase>compile</phase>
|
||||
<configuration>
|
||||
<target>
|
||||
<mkdir dir="${project.build.directory}/classes/edu/jhuapl/jhuapl/ses/jsqrl/gui/render/toolbar" />
|
||||
<copy todir="${project.build.directory}/classes/edu/jhuapl/ses/jsqrl/gui/render/toolbar">
|
||||
<fileset dir="src/edu/jhuapl/ses/jsqrl/gui/render/toolbar/">
|
||||
<include name="*.png"/>
|
||||
</fileset>
|
||||
</copy>
|
||||
</target>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
-->
|
||||
<execution>
|
||||
<id>icons</id>
|
||||
<?m2e execute onConfiguration,onIncremental?>
|
||||
<phase>compile</phase>
|
||||
<configuration>
|
||||
<target>
|
||||
<mkdir dir="${project.build.directory}/classes/resources" />
|
||||
<copy todir="${project.build.directory}/classes/resources">
|
||||
<fileset dir="src/resources"/>
|
||||
</copy>
|
||||
</target>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
84
src/edu/jhuapl/ses/jsqrl/api/Key.java
Normal file
84
src/edu/jhuapl/ses/jsqrl/api/Key.java
Normal file
@@ -0,0 +1,84 @@
|
||||
package edu.jhuapl.ses.jsqrl.api;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @param <T> type of the object that may be associated with this key, used for compile-time safety
|
||||
* only
|
||||
*/
|
||||
public class Key<T> implements Comparable<Key<?>> {
|
||||
|
||||
private static final Pattern NoLeadingWhiteSpace = Pattern.compile("^\\S.*", Pattern.DOTALL);
|
||||
private static final Pattern NoTrailingWhiteSpace = Pattern.compile(".*\\S$", Pattern.DOTALL);
|
||||
|
||||
/**
|
||||
* Return a key based on the supplied identification string.
|
||||
*
|
||||
* @param keyId the identification string of the key to be returned.
|
||||
* @return the key
|
||||
*
|
||||
* @throws NullPointerException if argument is null
|
||||
*/
|
||||
public static <T> Key<T> of(String keyId) {
|
||||
return new Key<>(keyId);
|
||||
}
|
||||
|
||||
private final String keyId;
|
||||
|
||||
protected Key(String keyId) {
|
||||
checkNotNull(keyId);
|
||||
checkArgument(NoLeadingWhiteSpace.matcher(keyId).matches());
|
||||
checkArgument(NoTrailingWhiteSpace.matcher(keyId).matches());
|
||||
this.keyId = keyId;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return keyId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int compareTo(Key<?> that) {
|
||||
if (that == null) {
|
||||
return 1;
|
||||
}
|
||||
return this.getId().compareTo(that.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + getId().hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (other instanceof Key) {
|
||||
Key<?> that = (Key<?>) other;
|
||||
return this.getId().equals(that.getId());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return keyId;
|
||||
}
|
||||
|
||||
private static void checkNotNull(Object object) {
|
||||
if (object == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkArgument(boolean expression) {
|
||||
if (!expression) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
87
src/edu/jhuapl/ses/jsqrl/api/Metadata.java
Normal file
87
src/edu/jhuapl/ses/jsqrl/api/Metadata.java
Normal file
@@ -0,0 +1,87 @@
|
||||
package edu.jhuapl.ses.jsqrl.api;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Interface representing a heterogenous collection of objects that may be retrieved using keys,
|
||||
* similar to {@link java.util.Map}, but with significant differences, mainly in how nulls and
|
||||
* missing keys are treated, and in how type safety is (and is not) enforced.
|
||||
*/
|
||||
public interface Metadata {
|
||||
/**
|
||||
* Return the {@link Version} for the content of this collection of metadata (not different
|
||||
* versions of the Metadata interface or associated abstractions).
|
||||
*
|
||||
* @return the content version object
|
||||
*/
|
||||
Version getVersion();
|
||||
|
||||
/**
|
||||
* Get a collection of {@link Key}s contained in this metadata object. Implementors must guarantee
|
||||
* this method remains consistent with other methods on the class, as described in the get(Key<?>
|
||||
* key) method.
|
||||
*
|
||||
* @return the collection of keys
|
||||
*/
|
||||
Collection<Key<?>> getKeys();
|
||||
|
||||
/**
|
||||
* Check whether this metadata object has the supplied key. Implementors must guarantee this
|
||||
* method remains consistent with other methods on the class, as described in the get(Key<?> key)
|
||||
* method.
|
||||
*
|
||||
* @param key the key to check
|
||||
* @return true if this metadata object has a value associated with the provided key
|
||||
* @throws NullPointerException if the provided key parameter is null
|
||||
*/
|
||||
boolean hasKey(Key<?> key);
|
||||
|
||||
/**
|
||||
* Retrieve the value associated with the provided key, if that key-value pair is contained in
|
||||
* this metadata object. Keys may not be null, but implementors are required to support null
|
||||
* values associated with keys.
|
||||
* <p>
|
||||
*
|
||||
* This method provides compile-time type safety only. Because of type erasure, it is possible to
|
||||
* obtain a key that is present in the metadata, but which has the wrong parametrized type. This
|
||||
* will lead to a ClassCastException when this method is called. It is the caller's responsibility
|
||||
* to avoid and/or mitigate this contingency.
|
||||
* <p>
|
||||
*
|
||||
* Implementions are required to be self-consistent in the following ways:
|
||||
* <p>
|
||||
*
|
||||
* 1) For any metadata object, get(Key<?> key) must throw an IllegalArgumentException if and only
|
||||
* if hasKey(Key<?> key) would return false for that same key parameter.
|
||||
* <p>
|
||||
*
|
||||
* 2) For any metadata object, hasKey(Key<?> key) must return false if the key parameter would not
|
||||
* be contained in the Collection returned by getKeys(). Implementations may choose whether to
|
||||
* allow "private keys", i.e., keys not returned by getKeys, but for which hasKey returns true.
|
||||
* <p>
|
||||
*
|
||||
* @param key whose associated value to retrieve
|
||||
*
|
||||
* @return the value (possibly null) associated with the key
|
||||
*
|
||||
* @throws NullPointerException if the provided key parameter is null
|
||||
*
|
||||
* @throws IllegalArgumentException if this metadata does not contain a key-value pairing
|
||||
* associated with the key parameter
|
||||
*
|
||||
* @throws ClassCastException if the value associated with the key cannot be cast to the type
|
||||
* provided by the key's type parameter
|
||||
*/
|
||||
<V> V get(Key<V> key);
|
||||
|
||||
/**
|
||||
* Create a completely independent copy of this metadata object, i.e., a separate object whose
|
||||
* methods would return identical results to the current object immediately after this method is
|
||||
* called. Implementations are not required to return an object of the same type as the object on
|
||||
* which this method is invoked.
|
||||
*
|
||||
* @return the copy of the metadata object
|
||||
*/
|
||||
Metadata copy();
|
||||
|
||||
}
|
||||
26
src/edu/jhuapl/ses/jsqrl/api/MetadataManager.java
Normal file
26
src/edu/jhuapl/ses/jsqrl/api/MetadataManager.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package edu.jhuapl.ses.jsqrl.api;
|
||||
|
||||
/**
|
||||
* Abstraction representing a manager of {@link Metadata}, capable of storing/retrieving the content
|
||||
* or state of one or more objects to/from a single Metadata object.
|
||||
*/
|
||||
public interface MetadataManager extends RepresentableAsMetadata {
|
||||
/**
|
||||
* Return a (complete and self-consistent) set of metadata derived from the content or state of
|
||||
* one or more objects.
|
||||
*
|
||||
* @return destination object in which the metadata are stored
|
||||
*/
|
||||
@Override
|
||||
Metadata store();
|
||||
|
||||
/**
|
||||
* Retrieve a (complete and self-consistent) set of metadata in the provided source object. The
|
||||
* metadata retrieved will typically be used to create or restore the state of one or more
|
||||
* objects.
|
||||
*
|
||||
* @param source the source metadata object
|
||||
*/
|
||||
void retrieve(Metadata source);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package edu.jhuapl.ses.jsqrl.api;
|
||||
|
||||
/**
|
||||
* Functional interface whose method uses a supplied {@link Metadata} object to provide an object
|
||||
* instance of a particular parametrized type <T>. If <T> is an instantiable class, this
|
||||
* implies that the stored metadata must contain all information necessary to instantiate an object
|
||||
* of type <T>. For non-instantiable types (i.e. enumerations or other singletons), the
|
||||
* metadata object need only contain enough information to identify the object to return.
|
||||
* <p>
|
||||
* In general if one provides an implementation of this interface, one provides also a complementary
|
||||
* implementation of {@link ProvidesMetadataFromGenericObject} interface and registers both of these
|
||||
* implementations with an {@InstanceGetter}.
|
||||
*
|
||||
* @param <T> the object type that can be provided from suitable Metadata
|
||||
* @see {@link ProvidesMetadataFromGenericObject}
|
||||
*/
|
||||
public interface ProvidesGenericObjectFromMetadata<T> {
|
||||
|
||||
/**
|
||||
* Use the supplied {@link Metadata} to create (or get) an object of the appropriate instance
|
||||
* type.
|
||||
*
|
||||
* @param metadata the metadata to use to provide the instance
|
||||
* @return an instance of the object of the parametrized type T obtained based on the metadata
|
||||
*/
|
||||
T provide(Metadata metadata);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package edu.jhuapl.ses.jsqrl.api;
|
||||
|
||||
/**
|
||||
* Functional interface whose method uses a supplied object of the parametrized type <T> to
|
||||
* provide a {@link Metadata} object that encapsulates the identity and/or state of the original
|
||||
* object. An implementation of this interface is typically paired with an implementation of
|
||||
* {@link ProvidesGenericObjectFromMetadata}, an implementation of this interface may be used to
|
||||
* store all information needed to instantiate on object of type <T>.
|
||||
*
|
||||
* @param <T> the object type for which Metadata can be provided.
|
||||
* @see {@link ProvidesGenericObjectFromMetadata}
|
||||
*/
|
||||
public interface ProvidesMetadataFromGenericObject<T> {
|
||||
|
||||
/**
|
||||
* Use the supplied object to create a {@link Metadata} object that encapsulates the state of the
|
||||
* original object.
|
||||
*
|
||||
* @param object the object whose state will be encapsulated in Metadata.
|
||||
* @return the Metadata.
|
||||
* @see {@link ProvidesGenericObjectFromMetadata}
|
||||
*/
|
||||
Metadata provide(T object);
|
||||
|
||||
}
|
||||
19
src/edu/jhuapl/ses/jsqrl/api/RepresentableAsMetadata.java
Normal file
19
src/edu/jhuapl/ses/jsqrl/api/RepresentableAsMetadata.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package edu.jhuapl.ses.jsqrl.api;
|
||||
|
||||
/**
|
||||
* Abstraction that is capable of representing (storing) the content or state of one or more objects
|
||||
* as {@link Metadata}.
|
||||
*
|
||||
* Implementations may provide representations for themselves, or on behalf of other objects.
|
||||
*
|
||||
* @see {@link MetadataManager}
|
||||
*/
|
||||
public interface RepresentableAsMetadata {
|
||||
/**
|
||||
* Return a set of {@link Metadata} that represents the content or state of one or more objects.
|
||||
*
|
||||
* @return the metadata representing the object of the parameterized type
|
||||
*/
|
||||
Metadata store();
|
||||
|
||||
}
|
||||
36
src/edu/jhuapl/ses/jsqrl/api/Serializer.java
Normal file
36
src/edu/jhuapl/ses/jsqrl/api/Serializer.java
Normal file
@@ -0,0 +1,36 @@
|
||||
package edu.jhuapl.ses.jsqrl.api;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public interface Serializer {
|
||||
/**
|
||||
* Return the version of the serializer/stored file format itself.
|
||||
*
|
||||
* @return the version.
|
||||
*/
|
||||
Version getVersion();
|
||||
|
||||
/**
|
||||
* Register the provided manager to manage Metadata objects associated with the provided key.
|
||||
*
|
||||
* Managers are called in the order in which they were originally added. Call this method the very
|
||||
* first time a method is invoked that uses a Metadata object to save and/or restore the state of
|
||||
* an object. This may or may not be within a constructor.
|
||||
*
|
||||
* This is so that program execution will more-or-less preserve the natural order of operations
|
||||
* affecting objects whose metadata is serialized/deserialized.
|
||||
*
|
||||
* @param key the key identifying the Metadata objects this manager manages
|
||||
* @param manager the manager for Metadata objects associated with the key
|
||||
* @throws IllegalStateException if method is called more than once with the same key
|
||||
*/
|
||||
void register(Key<? extends Metadata> key, MetadataManager manager);
|
||||
|
||||
void deregister(Key<? extends Metadata> key);
|
||||
|
||||
void load(File file) throws IOException;
|
||||
|
||||
void save(File file) throws IOException;
|
||||
|
||||
}
|
||||
6
src/edu/jhuapl/ses/jsqrl/api/Spud.java
Normal file
6
src/edu/jhuapl/ses/jsqrl/api/Spud.java
Normal file
@@ -0,0 +1,6 @@
|
||||
package edu.jhuapl.ses.jsqrl.api;
|
||||
|
||||
public class Spud
|
||||
{
|
||||
|
||||
}
|
||||
24
src/edu/jhuapl/ses/jsqrl/api/StorableAsMetadata.java
Normal file
24
src/edu/jhuapl/ses/jsqrl/api/StorableAsMetadata.java
Normal file
@@ -0,0 +1,24 @@
|
||||
package edu.jhuapl.ses.jsqrl.api;
|
||||
|
||||
/**
|
||||
* A {@link RepresentableAsMetadata} that is restricted to representing a single object of one
|
||||
* particular type. This includes a {@link Key} providing a unique identifier of the type of object
|
||||
* that may be converted to {@link Metadata}.
|
||||
*
|
||||
* The existence of the Key identifier makes implementations suitable for serialization of objects
|
||||
* of the parametrized type.
|
||||
*
|
||||
* @param <T> the object type that can be converted to Metadata
|
||||
* @see {@link ProvidesMetadataFromGenericObject}
|
||||
*/
|
||||
public interface StorableAsMetadata<T> extends RepresentableAsMetadata {
|
||||
/**
|
||||
* Return a key that uniquely identifies the type of object being stored. This is used in lieu of
|
||||
* the object's Class to identify the type for purposes of saving (serializing) the
|
||||
* {@link Metadata}.
|
||||
*
|
||||
* @return the key
|
||||
*/
|
||||
Key<? extends T> getKey();
|
||||
|
||||
}
|
||||
88
src/edu/jhuapl/ses/jsqrl/api/Version.java
Normal file
88
src/edu/jhuapl/ses/jsqrl/api/Version.java
Normal file
@@ -0,0 +1,88 @@
|
||||
package edu.jhuapl.ses.jsqrl.api;
|
||||
|
||||
public final class Version implements Comparable<Version> {
|
||||
|
||||
// Release notes are now in the package-info file.
|
||||
|
||||
public static Version of(int major, int minor) {
|
||||
return new Version(major, minor);
|
||||
}
|
||||
|
||||
public static Version of(String versionString) {
|
||||
checkNotNull(versionString);
|
||||
checkArgument(versionString.matches("^\\d+\\.\\d+$"));
|
||||
String[] versionInfo = versionString.split("\\.", 2);
|
||||
if (versionInfo.length != 2) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return of(Integer.parseInt(versionInfo[0]), Integer.parseInt(versionInfo[1]));
|
||||
}
|
||||
|
||||
private final int major;
|
||||
private final int minor;
|
||||
|
||||
private Version(int major, int minor) {
|
||||
checkArgument(major >= 0 && minor >= 0);
|
||||
this.major = major;
|
||||
this.minor = minor;
|
||||
}
|
||||
|
||||
public int getMajor() {
|
||||
return major;
|
||||
}
|
||||
|
||||
public int getMinor() {
|
||||
return minor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Version that) {
|
||||
int result = 1;
|
||||
if (that != null) {
|
||||
result = Integer.compare(this.major, that.major);
|
||||
if (result == 0) {
|
||||
result = Integer.compare(this.minor, that.minor);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + major;
|
||||
result = prime * result + minor;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof Version)) {
|
||||
return false;
|
||||
}
|
||||
Version that = (Version) other;
|
||||
return (this.major == that.major && this.minor == that.minor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return major + "." + minor;
|
||||
}
|
||||
|
||||
private static void checkNotNull(Object object) {
|
||||
if (object == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkArgument(boolean expression) {
|
||||
if (!expression) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
150
src/edu/jhuapl/ses/jsqrl/impl/AbstractMetadata.java
Normal file
150
src/edu/jhuapl/ses/jsqrl/impl/AbstractMetadata.java
Normal file
@@ -0,0 +1,150 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import edu.jhuapl.ses.jsqrl.api.Key;
|
||||
import edu.jhuapl.ses.jsqrl.api.Metadata;
|
||||
import edu.jhuapl.ses.jsqrl.api.Version;
|
||||
|
||||
/**
|
||||
* Base implementation that assumes/requires all metadata keys to be stored in a standard
|
||||
* {@link java.util.Map}. Implementations are provided for all {@link Metadata} methods except copy.
|
||||
* An additional protected abtract method, getMap() is provided so that subclasses may provide the
|
||||
* map used by this impementation. To ensure invariants are preserved in sublasses, all methods that
|
||||
* rely on this implementation's contract are final.
|
||||
*/
|
||||
public abstract class AbstractMetadata implements Metadata {
|
||||
/**
|
||||
* Object used to represent null. By proxying null with this object, it is possible to use any
|
||||
* {@link java.util.Map} implementation for key-value pairs.
|
||||
*/
|
||||
private static final Object NULL_OBJECT = new Object() {
|
||||
@Override
|
||||
public String toString() {
|
||||
// Deliberately capitalizing this so that the astute debugger has a chance of
|
||||
// noticing that this object is not actually a null pointer.
|
||||
return "NULL";
|
||||
}
|
||||
};
|
||||
|
||||
private final Version version;
|
||||
|
||||
protected AbstractMetadata(Version version) {
|
||||
Preconditions.checkNotNull(version);
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide an immutable copy of the map of keys to values. Because the returned map does not
|
||||
* support nulls for keys or values, implementations must use the object returned by getNullObject
|
||||
* to represent all null values.
|
||||
*
|
||||
* @return the map of keys to values
|
||||
*/
|
||||
public abstract ImmutableMap<Key<?>, Object> getMap();
|
||||
|
||||
@Override
|
||||
public final Version getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean hasKey(Key<?> key) {
|
||||
Preconditions.checkNotNull(key);
|
||||
return getMap().containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <V> V get(Key<V> key) {
|
||||
Preconditions.checkNotNull(key);
|
||||
Object object = getMap().get(key);
|
||||
if (object == null) {
|
||||
throw new IllegalArgumentException("FixedMetadata does not contain key " + key);
|
||||
}
|
||||
if (getNullObject() == object) {
|
||||
return null;
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
V result = (V) object;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract AbstractMetadata copy();
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + getVersion().hashCode();
|
||||
result = prime * result + getMap().hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (other instanceof AbstractMetadata) {
|
||||
AbstractMetadata that = (AbstractMetadata) other;
|
||||
if (!this.getVersion().equals(that.getVersion())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ImmutableMap<Key<?>, Object> thisMap = this.getMap();
|
||||
ImmutableMap<Key<?>, Object> thatMap = that.getMap();
|
||||
for (Entry<Key<?>, Object> entry : thisMap.entrySet()) {
|
||||
Key<?> key = entry.getKey();
|
||||
if (!thatMap.containsKey(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Object thisValue = entry.getValue();
|
||||
Object thatValue = thatMap.get(key);
|
||||
try {
|
||||
int thisLength = Array.getLength(thisValue);
|
||||
int thatLength = Array.getLength(thatValue);
|
||||
if (thisLength != thatLength) {
|
||||
return false;
|
||||
}
|
||||
for (int index = 0; index < thisLength; ++index) {
|
||||
if (!Array.get(thisValue, index).equals(Array.get(thatValue, index))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch (@SuppressWarnings("unused") IllegalArgumentException e) {
|
||||
// One or both items are not arrays, so just fall back on native equals method.
|
||||
if (!thisValue.equals(thatValue)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder("(Metadata) version ");
|
||||
builder.append(getVersion());
|
||||
for (Key<?> key : getKeys()) {
|
||||
builder.append("\n");
|
||||
builder.append(key + " = " + get(key));
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
protected static Object getNullObject() {
|
||||
return NULL_OBJECT;
|
||||
}
|
||||
|
||||
}
|
||||
23
src/edu/jhuapl/ses/jsqrl/impl/AbstractMetadataManager.java
Normal file
23
src/edu/jhuapl/ses/jsqrl/impl/AbstractMetadataManager.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl;
|
||||
|
||||
import edu.jhuapl.ses.jsqrl.api.MetadataManager;
|
||||
import edu.jhuapl.ses.jsqrl.api.Version;
|
||||
import edu.jhuapl.ses.jsqrl.impl.SettableMetadata;
|
||||
|
||||
public abstract class AbstractMetadataManager implements MetadataManager {
|
||||
|
||||
private final Version version;
|
||||
|
||||
protected AbstractMetadataManager(int major, int minor) {
|
||||
this(Version.of(major, minor));
|
||||
}
|
||||
|
||||
protected AbstractMetadataManager(Version version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
protected SettableMetadata createMetadata() {
|
||||
return SettableMetadata.of(version);
|
||||
}
|
||||
|
||||
}
|
||||
46
src/edu/jhuapl/ses/jsqrl/impl/EmptyMetadata.java
Normal file
46
src/edu/jhuapl/ses/jsqrl/impl/EmptyMetadata.java
Normal file
@@ -0,0 +1,46 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import edu.jhuapl.ses.jsqrl.api.Key;
|
||||
import edu.jhuapl.ses.jsqrl.api.Metadata;
|
||||
import edu.jhuapl.ses.jsqrl.api.Version;
|
||||
|
||||
public final class EmptyMetadata implements Metadata {
|
||||
private static final EmptyMetadata INSTANCE = new EmptyMetadata();
|
||||
|
||||
public static EmptyMetadata instance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Version getVersion() {
|
||||
throw new UnsupportedOperationException("Empty metadata has no version");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Key<?>> getKeys() {
|
||||
throw new UnsupportedOperationException("Empty metadata has no keys");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasKey(Key<?> key) {
|
||||
throw new UnsupportedOperationException("Empty metadata does not have key " + key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> V get(Key<V> key) {
|
||||
throw new UnsupportedOperationException("Empty metadata has no value for key " + key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Metadata copy() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Empty metadata";
|
||||
}
|
||||
|
||||
}
|
||||
59
src/edu/jhuapl/ses/jsqrl/impl/FixedMetadata.java
Normal file
59
src/edu/jhuapl/ses/jsqrl/impl/FixedMetadata.java
Normal file
@@ -0,0 +1,59 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import edu.jhuapl.ses.jsqrl.api.Key;
|
||||
import edu.jhuapl.ses.jsqrl.api.Metadata;
|
||||
import edu.jhuapl.ses.jsqrl.api.Version;
|
||||
import edu.jhuapl.ses.jsqrl.impl.AbstractMetadata;
|
||||
|
||||
public class FixedMetadata extends AbstractMetadata {
|
||||
public static FixedMetadata of(Metadata metadata) {
|
||||
Preconditions.checkNotNull(metadata);
|
||||
|
||||
if (metadata instanceof FixedMetadata) {
|
||||
return (FixedMetadata) metadata;
|
||||
}
|
||||
|
||||
Version version = metadata.getVersion();
|
||||
ImmutableList<Key<?>> keys = ImmutableList.copyOf(metadata.getKeys());
|
||||
|
||||
ImmutableMap.Builder<Key<?>, Object> builder = ImmutableMap.builder();
|
||||
for (Key<?> key : keys) {
|
||||
Object object = metadata.get(key);
|
||||
if (object == null) {
|
||||
object = getNullObject();
|
||||
}
|
||||
builder.put(key, object);
|
||||
}
|
||||
|
||||
return new FixedMetadata(version, keys, builder.build());
|
||||
}
|
||||
|
||||
private final ImmutableList<Key<?>> keys;
|
||||
private final ImmutableMap<Key<?>, Object> map;
|
||||
|
||||
protected FixedMetadata(Version version, ImmutableList<Key<?>> keys,
|
||||
ImmutableMap<Key<?>, Object> map) {
|
||||
super(version);
|
||||
this.keys = keys;
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableList<Key<?>> getKeys() {
|
||||
return keys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FixedMetadata copy() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableMap<Key<?>, Object> getMap() {
|
||||
return map;
|
||||
}
|
||||
}
|
||||
260
src/edu/jhuapl/ses/jsqrl/impl/InstanceGetter.java
Normal file
260
src/edu/jhuapl/ses/jsqrl/impl/InstanceGetter.java
Normal file
@@ -0,0 +1,260 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.HashBiMap;
|
||||
import edu.jhuapl.ses.jsqrl.api.Key;
|
||||
import edu.jhuapl.ses.jsqrl.api.Metadata;
|
||||
import edu.jhuapl.ses.jsqrl.api.ProvidesGenericObjectFromMetadata;
|
||||
import edu.jhuapl.ses.jsqrl.api.ProvidesMetadataFromGenericObject;
|
||||
import edu.jhuapl.ses.jsqrl.impl.Utilities;
|
||||
|
||||
/**
|
||||
* A collection of {@link ProvidesGenericObjectFromMetadata}s that may be stored or retrieved using
|
||||
* an associated {@link Key}. Keys must be unique within one InstanceGetter.
|
||||
*
|
||||
* @param <T> the object type that can be gotten from the Metadata
|
||||
*/
|
||||
public final class InstanceGetter {
|
||||
|
||||
/**
|
||||
* Return a reference to the standard/global InstanceGetter. Most applications will use this so
|
||||
* that any code may gain access to the various types of available
|
||||
* {@link ProvidesGenericObjectFromMetadata} objects.
|
||||
*
|
||||
* @return the instance
|
||||
*/
|
||||
public static InstanceGetter defaultInstanceGetter() {
|
||||
return DEFAULT_INSTANCE_GETTER;
|
||||
}
|
||||
|
||||
private static final InstanceGetter DEFAULT_INSTANCE_GETTER = new InstanceGetter();
|
||||
|
||||
private final SortedMap<Key<?>, ProvidesGenericObjectFromMetadata<?>> fromMetadataMap;
|
||||
private final Map<Class<?>, ProvidesMetadataFromGenericObject<?>> toMetadataMap;
|
||||
private final BiMap<Class<?>, Key<?>> keyMap;
|
||||
private final List<Class<?>> abstractTypes;
|
||||
private final List<Class<?>> interfaceTypes;
|
||||
|
||||
/**
|
||||
* Create a new InstanceGetter. In general, it's best to use the standard/global InstanceGetter
|
||||
* supplied by the defaultInstanceGetter method. However, this constructor is public in case it
|
||||
* ever becomes necessary to stand up an independent one (say to override how objects of a
|
||||
* particular class are proxied by default).
|
||||
*/
|
||||
public InstanceGetter() {
|
||||
this.fromMetadataMap = new TreeMap<>();
|
||||
this.toMetadataMap = new HashMap<>();
|
||||
this.keyMap = HashBiMap.create();
|
||||
this.abstractTypes = new ArrayList<>();
|
||||
this.interfaceTypes = new ArrayList<>();
|
||||
}
|
||||
|
||||
public boolean isProvidableFromMetadata(Key<?> proxyTypeKey) {
|
||||
Preconditions.checkNotNull(proxyTypeKey);
|
||||
|
||||
return fromMetadataMap.containsKey(proxyTypeKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link ProvidesGenericObjectFromMetadata} object that matches the supplied key,
|
||||
* provided the InstanceGetter has access to one.
|
||||
*
|
||||
* @param proxyTypeKey the key uniquely identifying the type of the object to be handled by the
|
||||
* returned {@link ProvidesGenericObjectFromMetadata}
|
||||
* @return the helper object that may be used to create/get objects from {@link Metadata}
|
||||
* @throws IllegalArgumentException if this InstanceGetter does not have a
|
||||
* {@link ProvidesGenericObjectFromMetadata} object for the supplied key
|
||||
* @throws ClassCastException if the supplied key matches a
|
||||
* {@link ProvidesGenericObjectFromMetadata} object managed by this InstanceGetter, but
|
||||
* the key has the wrong type.
|
||||
*/
|
||||
public <T> ProvidesGenericObjectFromMetadata<T> providesGenericObjectFromMetadata(
|
||||
Key<T> proxyTypeKey) {
|
||||
Preconditions.checkNotNull(proxyTypeKey);
|
||||
Preconditions.checkArgument(fromMetadataMap.containsKey(proxyTypeKey),
|
||||
"Unable to provide proxied object from metadata for type " + proxyTypeKey);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
ProvidesGenericObjectFromMetadata<T> result =
|
||||
(ProvidesGenericObjectFromMetadata<T>) fromMetadataMap.get(proxyTypeKey);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean isStorableAsMetadata(Object object) {
|
||||
if (object == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isTypeStorableAsMetadata(object.getClass());
|
||||
}
|
||||
|
||||
public boolean isTypeStorableAsMetadata(Class<?> type) {
|
||||
return findBestMatchForType(type) != null;
|
||||
}
|
||||
|
||||
public <T> Key<T> getKeyForType(Class<?> objectType) {
|
||||
Preconditions.checkNotNull(objectType);
|
||||
|
||||
Class<?> matchingType = findBestMatchForType(objectType);
|
||||
|
||||
if (matchingType == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Key<T> result = (Key<T>) keyMap.get(matchingType);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public <T> Class<T> getTypeForKey(Key<?> typeKey) {
|
||||
Preconditions.checkNotNull(typeKey);
|
||||
BiMap<Key<?>, Class<?>> typeMap = keyMap.inverse();
|
||||
Preconditions.checkArgument(typeMap.containsKey(typeKey));
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<T> result = (Class<T>) typeMap.get(typeKey);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public <T> ProvidesMetadataFromGenericObject<T> providesMetadataFromGenericObject(
|
||||
Class<?> objectType) {
|
||||
Preconditions.checkNotNull(objectType);
|
||||
|
||||
Class<?> matchingType = findBestMatchForType(objectType);
|
||||
|
||||
Preconditions.checkArgument(matchingType != null);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
ProvidesMetadataFromGenericObject<T> result =
|
||||
(ProvidesMetadataFromGenericObject<T>) toMetadataMap.get(matchingType);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the 4-argument register method instead of this one.
|
||||
*
|
||||
* @param proxyTypeKey
|
||||
* @param fromMetadata
|
||||
*/
|
||||
@Deprecated
|
||||
public <T> void register(Key<T> proxyTypeKey,
|
||||
ProvidesGenericObjectFromMetadata<? extends T> fromMetadata) {
|
||||
Preconditions.checkNotNull(proxyTypeKey);
|
||||
Preconditions.checkNotNull(fromMetadata);
|
||||
|
||||
Preconditions.checkState(!fromMetadataMap.containsKey(proxyTypeKey),
|
||||
"Cannot register metadata proxy more than once for type " + proxyTypeKey);
|
||||
|
||||
fromMetadataMap.put(proxyTypeKey, fromMetadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register proxy metadata store and retrieve objects to work with the supplied key and type.
|
||||
*
|
||||
* @param proxyTypeKey the key identifying the type of object that may be obtained by the
|
||||
* {@link ProvidesGenericObjectFromMetadata}. This is encoded in the stored metadata.
|
||||
* @param fromMetadata the {@link ProvidesGenericObjectFromMetadata} object to associate with this
|
||||
* key and value type. This object is used to supply an instance when deserializing.
|
||||
* @param objectType the specific type of object that may be stored and retrieved to/from
|
||||
* metadata.
|
||||
* @param toMetadata the {@link ProvidesMetadataFromGenericObject} object to associate with this
|
||||
* key and value type. This object is used to encode an instance of the object as metadata.
|
||||
* @throws IllegalStateException if this InstanceGetter already was called with the supplied
|
||||
* proxyTypeKey or objectType.
|
||||
*/
|
||||
public <T> void register(Key<T> proxyTypeKey,
|
||||
ProvidesGenericObjectFromMetadata<? extends T> fromMetadata, Class<?> objectType,
|
||||
ProvidesMetadataFromGenericObject<? extends T> toMetadata) {
|
||||
Preconditions.checkNotNull(proxyTypeKey);
|
||||
Preconditions.checkNotNull(fromMetadata);
|
||||
Preconditions.checkNotNull(objectType);
|
||||
Preconditions.checkNotNull(toMetadata);
|
||||
|
||||
Preconditions.checkState(!fromMetadataMap.containsKey(proxyTypeKey),
|
||||
"Cannot register metadata proxy more than once for type " + proxyTypeKey);
|
||||
Preconditions.checkState(!toMetadataMap.containsKey(objectType),
|
||||
"Cannot register metadata proxies more than once for object type "
|
||||
+ Utilities.simpleName(objectType));
|
||||
Preconditions.checkState(!keyMap.containsKey(objectType),
|
||||
"Cannot register more than one proxy key for an object type");
|
||||
Preconditions.checkState(!keyMap.inverse().containsKey(proxyTypeKey),
|
||||
"Cannot register more than one object type with the same proxy key");
|
||||
|
||||
fromMetadataMap.put(proxyTypeKey, fromMetadata);
|
||||
toMetadataMap.put(objectType, toMetadata);
|
||||
keyMap.put(objectType, proxyTypeKey);
|
||||
|
||||
if ((objectType.getModifiers() & Modifier.ABSTRACT) != 0) {
|
||||
abstractTypes.add(objectType);
|
||||
}
|
||||
|
||||
if (objectType.isInterface()) {
|
||||
interfaceTypes.add(objectType);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deregister (remove/don't track or use) the {@link ProvidesGenericObjectFromMetadata} associated
|
||||
* with this key, if any.
|
||||
*
|
||||
* @param proxyTypeKey the key identifying the MetadataToObject to remove
|
||||
*/
|
||||
public void deRegister(Key<?> proxyTypeKey) {
|
||||
Preconditions.checkNotNull(proxyTypeKey);
|
||||
|
||||
fromMetadataMap.remove(proxyTypeKey);
|
||||
|
||||
Class<?> objectType = keyMap.inverse().get(proxyTypeKey);
|
||||
if (objectType != null) {
|
||||
toMetadataMap.remove(objectType);
|
||||
keyMap.remove(objectType);
|
||||
abstractTypes.remove(objectType);
|
||||
interfaceTypes.remove(objectType);
|
||||
}
|
||||
}
|
||||
|
||||
protected Class<?> findBestMatchForType(Class<?> objectType) {
|
||||
Preconditions.checkNotNull(objectType);
|
||||
|
||||
Class<?> result = null;
|
||||
|
||||
if (keyMap.containsKey(objectType)) {
|
||||
result = objectType;
|
||||
}
|
||||
|
||||
if (result == null) {
|
||||
// Search for match to a superclass.
|
||||
for (Class<?> abstractType : abstractTypes) {
|
||||
if (abstractType.isAssignableFrom(objectType)) {
|
||||
result = abstractType;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result == null) {
|
||||
// Search for first match to an interface.
|
||||
for (Class<?> interfaceType : interfaceTypes) {
|
||||
if (interfaceType.isAssignableFrom(objectType)) {
|
||||
result = interfaceType;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
63
src/edu/jhuapl/ses/jsqrl/impl/MetadataManagerCollection.java
Normal file
63
src/edu/jhuapl/ses/jsqrl/impl/MetadataManagerCollection.java
Normal file
@@ -0,0 +1,63 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import edu.jhuapl.ses.jsqrl.api.Key;
|
||||
import edu.jhuapl.ses.jsqrl.api.Metadata;
|
||||
import edu.jhuapl.ses.jsqrl.api.MetadataManager;
|
||||
|
||||
public class MetadataManagerCollection {
|
||||
public static MetadataManagerCollection of() {
|
||||
return new MetadataManagerCollection();
|
||||
}
|
||||
|
||||
private final List<Key<? extends Metadata>> keysInOrder;
|
||||
private final SortedMap<Key<? extends Metadata>, MetadataManager> managers;
|
||||
|
||||
private MetadataManagerCollection() {
|
||||
this.keysInOrder = new ArrayList<>();
|
||||
this.managers = new TreeMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a manager to this collection of managers. The manager will be associated with Metadata
|
||||
* identified by the supplied key.
|
||||
*
|
||||
* @param key the key to Metadata objects this manager will manage
|
||||
* @param manager the manager
|
||||
* @throws IllegalStateException if there is already a manager associated with the supplied key
|
||||
* @throws NullPointerException if any argument is null
|
||||
*/
|
||||
public void add(Key<? extends Metadata> key, MetadataManager manager) {
|
||||
Preconditions.checkNotNull(key);
|
||||
Preconditions.checkNotNull(manager);
|
||||
Preconditions.checkState(!managers.containsKey(key));
|
||||
|
||||
keysInOrder.add(key);
|
||||
managers.put(key, manager);
|
||||
}
|
||||
|
||||
public void remove(Key<? extends Metadata> key) {
|
||||
Preconditions.checkNotNull(key);
|
||||
|
||||
keysInOrder.remove(key);
|
||||
managers.remove(key);
|
||||
}
|
||||
|
||||
public ImmutableList<Key<? extends Metadata>> getKeys() {
|
||||
return ImmutableList.copyOf(keysInOrder);
|
||||
}
|
||||
|
||||
public MetadataManager getManager(Key<? extends Metadata> key) {
|
||||
Preconditions.checkNotNull(key);
|
||||
Preconditions.checkArgument(managers.containsKey(key));
|
||||
return managers.get(key);
|
||||
}
|
||||
|
||||
}
|
||||
181
src/edu/jhuapl/ses/jsqrl/impl/SerializableItem.java
Normal file
181
src/edu/jhuapl/ses/jsqrl/impl/SerializableItem.java
Normal file
@@ -0,0 +1,181 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.Base64;
|
||||
import java.util.Objects;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
import com.google.common.base.Preconditions;
|
||||
import edu.jhuapl.ses.jsqrl.api.Key;
|
||||
import edu.jhuapl.ses.jsqrl.api.Version;
|
||||
import edu.jhuapl.ses.jsqrl.impl.InstanceGetter;
|
||||
import edu.jhuapl.ses.jsqrl.impl.SettableMetadata;
|
||||
|
||||
/**
|
||||
* Adaptor to serialize/deserialize objects that do not explicitly cooperate with the metadata
|
||||
* framework, but that *do* implement {@link Serializable}. This adaptor uses byte array objects and
|
||||
* gzipping/gunzipping streams to serialize an object to a string, then saves that string using the
|
||||
* metadata framework. This adaptor can also do the reverse and create an object from a string that
|
||||
* holds the object's serialized form.
|
||||
* <p>
|
||||
* The purpose of this class is to make it easier to support hierarchies and complex objects with
|
||||
* the metadata framework without writing explicit instance-getting code. The trade-off is that the
|
||||
* strings written are long and not human readable, whereas writing instance-getting code for each
|
||||
* type allows thec caller to control how objects are written and read.
|
||||
*
|
||||
* @author James Peachey
|
||||
*
|
||||
* @param <S> the type of item, which must extend {@link Serializable}
|
||||
*/
|
||||
public final class SerializableItem<S extends Serializable> {
|
||||
|
||||
/**
|
||||
* Boilerplate metadata stuff.
|
||||
*/
|
||||
private static final Version MetadataVersion = Version.of(1, 0);
|
||||
private static final Key<Class<Serializable>> ItemTypeKey = Key.of("itemType");
|
||||
private static final Key<String> EncodedStringKey = Key.of("encodedString");
|
||||
|
||||
static {
|
||||
|
||||
/**
|
||||
* Add to the metadata framework the necessary code to handle encoding/decoding the item.
|
||||
*/
|
||||
InstanceGetter.defaultInstanceGetter().register(Key.of("SerializableItem"), //
|
||||
metadata -> {
|
||||
Class<Serializable> itemType = metadata.get(ItemTypeKey);
|
||||
String encodedString = metadata.get(EncodedStringKey);
|
||||
|
||||
Serializable serializable;
|
||||
try {
|
||||
serializable = decodeFromString(itemType, encodedString);
|
||||
} catch (Exception e) {
|
||||
serializable = null;
|
||||
}
|
||||
|
||||
return new SerializableItem<Serializable>(itemType, serializable);
|
||||
}, SerializableItem.class, settings -> {
|
||||
SettableMetadata metadata = SettableMetadata.of(MetadataVersion);
|
||||
|
||||
metadata.put(ItemTypeKey, settings.getItemType());
|
||||
String encodedString;
|
||||
try {
|
||||
encodedString = encodeToString(settings.getItem());
|
||||
} catch (Exception e) {
|
||||
encodedString = null;
|
||||
}
|
||||
metadata.put(EncodedStringKey, encodedString);
|
||||
|
||||
return metadata;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty static method that may be called to ensure static initialization blocks have executed.
|
||||
*/
|
||||
public static void init() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode an item that is encoded in the specified string and cast it to the specified item type.
|
||||
*
|
||||
* @param <S> generic type, which must extend {@link Serializable}
|
||||
* @param itemType type of item being decoded
|
||||
* @param encodedString the string
|
||||
* @return the decoded item
|
||||
* @throws IOException if the gunzipping/streaming operation(s) throw one
|
||||
* @throws ClassNotFoundException if the class of the object type being decoded cannot be found
|
||||
*/
|
||||
public static <S extends Serializable> S decodeFromString(Class<S> itemType, String encodedString)
|
||||
throws IOException, ClassNotFoundException {
|
||||
Preconditions.checkNotNull(itemType);
|
||||
|
||||
if (encodedString == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] data = Base64.getDecoder().decode(encodedString);
|
||||
|
||||
try (ObjectInputStream ois =
|
||||
new ObjectInputStream(new GZIPInputStream(new ByteArrayInputStream(data)))) {
|
||||
return itemType.cast(ois.readObject());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the specified {@link Serializable} item into a string.
|
||||
*
|
||||
* @param item the item to encode
|
||||
* @return the encoded string
|
||||
* @throws IOException if the gzipping/streaming operation(s) throw one
|
||||
*/
|
||||
public static String encodeToString(Serializable item) throws IOException {
|
||||
if (item == null || item instanceof String) {
|
||||
return (String) item;
|
||||
}
|
||||
|
||||
String encodedString = null;
|
||||
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
|
||||
try (ObjectOutputStream oos =
|
||||
new ObjectOutputStream(/* new GZIPOutputStream( */new GZIPOutputStream(baos))) {
|
||||
oos.writeObject(item);
|
||||
}
|
||||
encodedString = Base64.getEncoder().encodeToString(baos.toByteArray());
|
||||
}
|
||||
|
||||
return encodedString;
|
||||
}
|
||||
|
||||
private final Class<S> itemType;
|
||||
private final S item;
|
||||
|
||||
public SerializableItem(Class<S> itemType, S item) {
|
||||
this.itemType = itemType;
|
||||
this.item = item;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the concrete type of the serializable item
|
||||
*/
|
||||
public Class<S> getItemType() {
|
||||
return itemType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the item that can be serialized
|
||||
*/
|
||||
public S getItem() {
|
||||
return item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(item, itemType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof SerializableItem)) {
|
||||
return false;
|
||||
}
|
||||
SerializableItem<?> other = (SerializableItem<?>) obj;
|
||||
|
||||
return Objects.equals(item, other.item) && Objects.equals(itemType, other.itemType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return item != null ? item.toString() : null;
|
||||
}
|
||||
|
||||
}
|
||||
178
src/edu/jhuapl/ses/jsqrl/impl/SettableMetadata.java
Normal file
178
src/edu/jhuapl/ses/jsqrl/impl/SettableMetadata.java
Normal file
@@ -0,0 +1,178 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.SortedMap;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import edu.jhuapl.ses.jsqrl.api.Key;
|
||||
import edu.jhuapl.ses.jsqrl.api.Metadata;
|
||||
import edu.jhuapl.ses.jsqrl.api.Version;
|
||||
import edu.jhuapl.ses.jsqrl.impl.AbstractMetadata;
|
||||
import edu.jhuapl.ses.jsqrl.impl.Utilities;
|
||||
|
||||
public class SettableMetadata extends AbstractMetadata {
|
||||
|
||||
public static SettableMetadata of(Version version) {
|
||||
return new SettableMetadata(version, new ArrayList<>(), new HashMap<>());
|
||||
}
|
||||
|
||||
public static SettableMetadata of(Metadata metadata) {
|
||||
Preconditions.checkNotNull(metadata);
|
||||
SettableMetadata result = SettableMetadata.of(metadata.getVersion());
|
||||
for (Key<?> key : metadata.getKeys()) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Key<Object> objectKey = (Key<Object>) key;
|
||||
result.put(objectKey, metadata.get(key));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private final List<Key<?>> keys;
|
||||
private final Map<Key<?>, Object> map;
|
||||
|
||||
protected SettableMetadata(Version version, List<Key<?>> keys, Map<Key<?>, Object> map) {
|
||||
super(version);
|
||||
Preconditions.checkNotNull(keys);
|
||||
Preconditions.checkNotNull(map);
|
||||
this.keys = keys;
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableList<Key<?>> getKeys() {
|
||||
return ImmutableList.copyOf(keys);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SettableMetadata copy() {
|
||||
return new SettableMetadata(getVersion(), new ArrayList<>(keys), new HashMap<>(map));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableMap<Key<?>, Object> getMap() {
|
||||
return ImmutableMap.copyOf(map);
|
||||
}
|
||||
|
||||
public final <V> SettableMetadata put(Key<V> key, V value) {
|
||||
Preconditions.checkNotNull(key);
|
||||
Class<?> storedAsType = checkStorable(value);
|
||||
if (!hasKey(key)) {
|
||||
keys.add(key);
|
||||
}
|
||||
if (value == null) {
|
||||
map.put(key, getNullObject());
|
||||
} else {
|
||||
map.put(key, copyOrUse(storedAsType, value));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
keys.clear();
|
||||
map.clear();
|
||||
}
|
||||
|
||||
protected static void validateIterable(Iterable<?> iterable) {
|
||||
for (Object item : iterable) {
|
||||
checkStorable(item);
|
||||
}
|
||||
}
|
||||
|
||||
protected static void validateMap(Map<?, ?> map) {
|
||||
Class<?> mapKeyType = null;
|
||||
for (Entry<?, ?> entry : map.entrySet()) {
|
||||
Class<?> keyType = checkStorable(entry.getKey());
|
||||
if (mapKeyType == null) {
|
||||
mapKeyType = keyType;
|
||||
} else if (keyType != null && keyType != mapKeyType) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot put a key of type " + Utilities.simpleName(keyType)
|
||||
+ " in a map using keys of type " + Utilities.simpleName(mapKeyType));
|
||||
}
|
||||
checkStorable(entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected static <V> V copyOrUse(Class<?> storedAsType, V value) {
|
||||
if (SortedMap.class.isAssignableFrom(storedAsType)) {
|
||||
value = (V) new TreeMap<>((SortedMap<?, ?>) value);
|
||||
} else if (Map.class.isAssignableFrom(storedAsType)) {
|
||||
value = (V) new LinkedHashMap<>((Map<?, ?>) value);
|
||||
} else if (List.class.isAssignableFrom(storedAsType)) {
|
||||
value = (V) new ArrayList<>((List<?>) value);
|
||||
} else if (SortedSet.class.isAssignableFrom(storedAsType)) {
|
||||
value = (V) new TreeSet<>((SortedSet<?>) value);
|
||||
} else if (Set.class.isAssignableFrom(storedAsType)) {
|
||||
value = (V) new LinkedHashSet<>((Set<?>) value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the specified object may be represented as metadata. If it can, the type used by
|
||||
* the metadata system to represent the object is returned. If the object cannot be represented by
|
||||
* the metadata system, an {@link IllegalArgumentException} is thrown. This method never returns
|
||||
* null.
|
||||
* <p>
|
||||
* This method uses the {@link Utilities#classifyStorableType(Class)} to determine whether the
|
||||
* object is storable using the primary metadata mechanism. Unlike that method, however, if the
|
||||
* object is not storable in the primary way, but the item's class implements
|
||||
* {@link Serializable}, this method returns Serializable.class, because the item will be
|
||||
* successfully stored/retrieved using the secondary mechanism for storing Serializable items, in
|
||||
* which objects are serialized as Strings.
|
||||
*
|
||||
* @param object the item to be stored as metadata
|
||||
* @return the type used to represent this item
|
||||
*/
|
||||
protected static Class<?> checkStorable(Object object) {
|
||||
if (object == null) {
|
||||
return null;
|
||||
}
|
||||
if (object instanceof List) {
|
||||
validateIterable((Iterable<?>) object);
|
||||
return List.class;
|
||||
}
|
||||
if (object instanceof SortedMap) {
|
||||
validateMap((Map<?, ?>) object);
|
||||
return SortedMap.class;
|
||||
}
|
||||
if (object instanceof Map) {
|
||||
validateMap((Map<?, ?>) object);
|
||||
return Map.class;
|
||||
}
|
||||
if (object instanceof SortedSet) {
|
||||
validateIterable((Iterable<?>) object);
|
||||
return SortedSet.class;
|
||||
}
|
||||
if (object instanceof Set) {
|
||||
validateIterable((Iterable<?>) object);
|
||||
return Set.class;
|
||||
}
|
||||
|
||||
Class<?> type = Utilities.classifyStorableType(object.getClass());
|
||||
|
||||
if (type == null && Serializable.class.isAssignableFrom(object.getClass())) {
|
||||
type = Serializable.class;
|
||||
}
|
||||
|
||||
if (type == null) {
|
||||
throw new IllegalArgumentException("Cannot directly represent objects of type "
|
||||
+ Utilities.simpleName(object.getClass()) + " as metadata");
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
}
|
||||
99
src/edu/jhuapl/ses/jsqrl/impl/TrackedMetadataManager.java
Normal file
99
src/edu/jhuapl/ses/jsqrl/impl/TrackedMetadataManager.java
Normal file
@@ -0,0 +1,99 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl;
|
||||
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import edu.jhuapl.ses.jsqrl.api.Key;
|
||||
import edu.jhuapl.ses.jsqrl.api.Metadata;
|
||||
import edu.jhuapl.ses.jsqrl.api.MetadataManager;
|
||||
import edu.jhuapl.ses.jsqrl.api.RepresentableAsMetadata;
|
||||
import edu.jhuapl.ses.jsqrl.api.Serializer;
|
||||
import edu.jhuapl.ses.jsqrl.impl.gson.Serializers;
|
||||
|
||||
/**
|
||||
* This is a helper implementation designed to wrap another implementation of the
|
||||
* {@link MetadataManager} interface.
|
||||
*/
|
||||
public final class TrackedMetadataManager implements MetadataManager, RepresentableAsMetadata {
|
||||
public static TrackedMetadataManager of(String metadataId) {
|
||||
return new TrackedMetadataManager(metadataId, Serializers.getDefault());
|
||||
}
|
||||
|
||||
private static final SortedSet<String> MANAGER_IDENTIFIERS = new TreeSet<>();
|
||||
private final Key<Metadata> metadataKey;
|
||||
private final Serializer serializer;
|
||||
private MetadataManager manager;
|
||||
|
||||
/**
|
||||
* Construct a new manager that will use the provided serializer. The identifying string provided
|
||||
* must be unique within the currently running application. Note that the new manager is not added
|
||||
* to the serializer by this constructor. That will be done when another manager is registered
|
||||
* with this manager.
|
||||
*
|
||||
* @param metadataId string used to idenfity this manager within the serializer
|
||||
* @param serializer the serializer
|
||||
* @throws IllegalStateException if the serializer already has a manager associated with the
|
||||
* provided string
|
||||
* @throws NullPointerException if any argument is null
|
||||
*/
|
||||
private TrackedMetadataManager(String metadataId, Serializer serializer) {
|
||||
Preconditions.checkNotNull(metadataId);
|
||||
Preconditions.checkNotNull(serializer);
|
||||
Preconditions.checkState(!MANAGER_IDENTIFIERS.contains(metadataId),
|
||||
"Duplicated manager identifier " + metadataId);
|
||||
MANAGER_IDENTIFIERS.add(metadataId);
|
||||
this.metadataKey = Key.of(metadataId);
|
||||
this.serializer = serializer;
|
||||
this.manager = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform all initializations required prior to serializing/deserializing metadata managed by
|
||||
* this manager. Note that all of this implementation's functions as a manager work just fine
|
||||
* without calling this method. Moreover, it is safe to call this method multiple times.
|
||||
*
|
||||
* A separate initialize method is provided so that source objects may be serialized in the
|
||||
* natural order established by the runtime function of the tool, rather than the order in which
|
||||
* source objects were instantiated, which may not be the same.
|
||||
*
|
||||
* @throws IllegalStateException if a manager was already registered, or if the serializer fails
|
||||
* to register this manager cleanly.
|
||||
*/
|
||||
public void register(MetadataManager manager) {
|
||||
Preconditions.checkNotNull(manager);
|
||||
Preconditions.checkState(this.manager == null);
|
||||
serializer.register(metadataKey, this);
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
public boolean isRegistered() {
|
||||
return manager != null;
|
||||
}
|
||||
|
||||
public Key<Metadata> getKey() {
|
||||
return metadataKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public final Metadata store() {
|
||||
Preconditions.checkState(manager != null);
|
||||
return manager.store();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public final void retrieve(Metadata sourceMetadata) {
|
||||
Preconditions.checkNotNull(sourceMetadata);
|
||||
Preconditions.checkState(manager != null);
|
||||
|
||||
manager.retrieve(sourceMetadata);
|
||||
}
|
||||
|
||||
}
|
||||
232
src/edu/jhuapl/ses/jsqrl/impl/Utilities.java
Normal file
232
src/edu/jhuapl/ses/jsqrl/impl/Utilities.java
Normal file
@@ -0,0 +1,232 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.SortedMap;
|
||||
import java.util.SortedSet;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import edu.jhuapl.ses.jsqrl.api.Key;
|
||||
import edu.jhuapl.ses.jsqrl.api.Metadata;
|
||||
import edu.jhuapl.ses.jsqrl.api.MetadataManager;
|
||||
import edu.jhuapl.ses.jsqrl.api.ProvidesMetadataFromGenericObject;
|
||||
import edu.jhuapl.ses.jsqrl.api.StorableAsMetadata;
|
||||
import edu.jhuapl.ses.jsqrl.api.Version;
|
||||
import edu.jhuapl.ses.jsqrl.impl.InstanceGetter;
|
||||
import edu.jhuapl.ses.jsqrl.impl.SettableMetadata;
|
||||
|
||||
public class Utilities {
|
||||
|
||||
// Release notes are now in the package-info file.
|
||||
|
||||
public static <K> ImmutableMap<K, Metadata> bulkStore(Map<K, MetadataManager> managers) {
|
||||
Preconditions.checkNotNull(managers);
|
||||
|
||||
ImmutableMap.Builder<K, Metadata> builder = ImmutableMap.builder();
|
||||
for (Entry<K, MetadataManager> entry : managers.entrySet()) {
|
||||
builder.put(entry.getKey(), entry.getValue().store());
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public static <K> void bulkRetrieve(Map<K, MetadataManager> managers, Map<K, Metadata> metadata) {
|
||||
Preconditions.checkNotNull(managers);
|
||||
Preconditions.checkNotNull(metadata);
|
||||
for (Entry<K, MetadataManager> entry : managers.entrySet()) {
|
||||
K key = entry.getKey();
|
||||
if (metadata.containsKey(key)) {
|
||||
entry.getValue().retrieve(metadata.get(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Key<?> provideTypeKeyIfPossible(Object object) {
|
||||
InstanceGetter instanceGetter = InstanceGetter.defaultInstanceGetter();
|
||||
|
||||
Key<?> key = null;
|
||||
if (instanceGetter.isStorableAsMetadata(object)) {
|
||||
key = instanceGetter.getKeyForType(object.getClass());
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
public static Object provideMetadataIfPossible(Object object) {
|
||||
InstanceGetter instanceGetter = InstanceGetter.defaultInstanceGetter();
|
||||
if (instanceGetter.isStorableAsMetadata(object)) {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<Object> objectType = (Class<Object>) object.getClass();
|
||||
|
||||
object = instanceGetter.providesMetadataFromGenericObject(objectType).provide(object);
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
public static String simpleName(Class<?> type) {
|
||||
if (type == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String simpleName = type.getSimpleName();
|
||||
if (simpleName.isEmpty()) {
|
||||
simpleName = type.getName().replaceAll(".*//.", "");
|
||||
}
|
||||
|
||||
return simpleName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine how to represent the specified type as metadata. For all the types the metadata
|
||||
* system was designed to handle natively (int, Map, etc.) and for types handled by the
|
||||
* {@link InstanceGetter} mechanism, the appropriate base class or interface used to set up
|
||||
* serialization/deserialization is returned. If the type is not one of these directly supported
|
||||
* types, null is returned.
|
||||
* <p>
|
||||
* The interface {@link java.io.Serializable} is a special case. If the specified type is not one
|
||||
* of the directly-supported types described above, but the type is assignable to Serializable,
|
||||
* this method returns null. This signifies that the type in question is not supported by the
|
||||
* primary metadata mechanism. However, while this method returns null, the method
|
||||
* {@link SettableMetadata#checkStorable(Object)} returns Serializable.class in this case. This
|
||||
* works because there is a secondary mechanism for Serializable items, in which they are
|
||||
* serialized into a String. This is for dealing with hierarchies for which no explicit metadata
|
||||
* rules are set up for whatever reason.
|
||||
*
|
||||
* @param type the actual type of object to be represented as metadata
|
||||
* @return the type the metadata system will use to store/retrieve such objects
|
||||
*/
|
||||
public static Class<?> classifyStorableType(Class<?> type) {
|
||||
if (type == null) {
|
||||
return null;
|
||||
}
|
||||
if (InstanceGetter.defaultInstanceGetter().isTypeStorableAsMetadata(type)) {
|
||||
return ProvidesMetadataFromGenericObject.class;
|
||||
}
|
||||
if (Key.class.isAssignableFrom(type)) {
|
||||
return Key.class;
|
||||
}
|
||||
if (Metadata.class.isAssignableFrom(type)) {
|
||||
return Metadata.class;
|
||||
}
|
||||
if (StorableAsMetadata.class.isAssignableFrom(type)) {
|
||||
return StorableAsMetadata.class;
|
||||
}
|
||||
if (Version.class.isAssignableFrom(type)) {
|
||||
return Version.class;
|
||||
}
|
||||
if (List.class.isAssignableFrom(type)) {
|
||||
return List.class;
|
||||
}
|
||||
if (SortedMap.class.isAssignableFrom(type)) {
|
||||
return SortedMap.class;
|
||||
}
|
||||
if (Map.class.isAssignableFrom(type)) {
|
||||
return Map.class;
|
||||
}
|
||||
if (SortedSet.class.isAssignableFrom(type)) {
|
||||
return SortedSet.class;
|
||||
}
|
||||
if (Set.class.isAssignableFrom(type)) {
|
||||
return Set.class;
|
||||
}
|
||||
if (String.class.isAssignableFrom(type)) {
|
||||
return String.class;
|
||||
}
|
||||
if (Character.class.isAssignableFrom(type)) {
|
||||
return Character.class;
|
||||
}
|
||||
if (Boolean.class.isAssignableFrom(type)) {
|
||||
return Boolean.class;
|
||||
}
|
||||
if (Double.class.isAssignableFrom(type)) {
|
||||
return Double.class;
|
||||
}
|
||||
if (Float.class.isAssignableFrom(type)) {
|
||||
return Float.class;
|
||||
}
|
||||
if (Integer.class.isAssignableFrom(type)) {
|
||||
return Integer.class;
|
||||
}
|
||||
if (Long.class.isAssignableFrom(type)) {
|
||||
return Long.class;
|
||||
}
|
||||
if (Short.class.isAssignableFrom(type)) {
|
||||
return Short.class;
|
||||
}
|
||||
if (Byte.class.isAssignableFrom(type)) {
|
||||
return Byte.class;
|
||||
}
|
||||
if (Date.class.isAssignableFrom(type)) {
|
||||
return Date.class;
|
||||
}
|
||||
if (String[].class.isAssignableFrom(type)) {
|
||||
return String[].class;
|
||||
}
|
||||
if (Character[].class.isAssignableFrom(type)) {
|
||||
return Character[].class;
|
||||
}
|
||||
if (Boolean[].class.isAssignableFrom(type)) {
|
||||
return Boolean[].class;
|
||||
}
|
||||
if (Double[].class.isAssignableFrom(type)) {
|
||||
return Double[].class;
|
||||
}
|
||||
if (Float[].class.isAssignableFrom(type)) {
|
||||
return Float[].class;
|
||||
}
|
||||
if (Integer[].class.isAssignableFrom(type)) {
|
||||
return Integer[].class;
|
||||
}
|
||||
if (Long[].class.isAssignableFrom(type)) {
|
||||
return Long[].class;
|
||||
}
|
||||
if (Short[].class.isAssignableFrom(type)) {
|
||||
return Short[].class;
|
||||
}
|
||||
if (Byte[].class.isAssignableFrom(type)) {
|
||||
return Byte[].class;
|
||||
}
|
||||
if (Date[].class.isAssignableFrom(type)) {
|
||||
return Date[].class;
|
||||
}
|
||||
if (Metadata[].class.isAssignableFrom(type)) {
|
||||
return Metadata[].class;
|
||||
}
|
||||
if (char[].class.isAssignableFrom(type)) {
|
||||
return char[].class;
|
||||
}
|
||||
if (boolean[].class.isAssignableFrom(type)) {
|
||||
return boolean[].class;
|
||||
}
|
||||
if (double[].class.isAssignableFrom(type)) {
|
||||
return double[].class;
|
||||
}
|
||||
if (float[].class.isAssignableFrom(type)) {
|
||||
return float[].class;
|
||||
}
|
||||
if (int[].class.isAssignableFrom(type)) {
|
||||
return int[].class;
|
||||
}
|
||||
if (long[].class.isAssignableFrom(type)) {
|
||||
return long[].class;
|
||||
}
|
||||
if (short[].class.isAssignableFrom(type)) {
|
||||
return short[].class;
|
||||
}
|
||||
if (byte[].class.isAssignableFrom(type)) {
|
||||
return byte[].class;
|
||||
}
|
||||
if (Class.class.isAssignableFrom(type)) {
|
||||
return Class.class;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
77
src/edu/jhuapl/ses/jsqrl/impl/gson/ClassIO.java
Normal file
77
src/edu/jhuapl/ses/jsqrl/impl/gson/ClassIO.java
Normal file
@@ -0,0 +1,77 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
|
||||
import edu.jhuapl.ses.jsqrl.api.Key;
|
||||
import edu.jhuapl.ses.jsqrl.impl.InstanceGetter;
|
||||
|
||||
public class ClassIO implements JsonSerializer<Class<?>>, JsonDeserializer<Class<?>> {
|
||||
|
||||
private static final InstanceGetter instanceGetter = InstanceGetter.defaultInstanceGetter();
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(Class<?> src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
String typeId = null;
|
||||
|
||||
try {
|
||||
Key<?> key = instanceGetter.getKeyForType(src);
|
||||
typeId = key.getId();
|
||||
} catch (@SuppressWarnings("unused") Exception e) {
|
||||
|
||||
}
|
||||
|
||||
if (typeId == null) {
|
||||
DataTypeInfo info = DataTypeInfo.of(src);
|
||||
if (info != DataTypeInfo.NULL) {
|
||||
typeId = info.getTypeId();
|
||||
}
|
||||
}
|
||||
|
||||
if (typeId == null) {
|
||||
typeId = src.getName();
|
||||
}
|
||||
|
||||
return new JsonPrimitive(typeId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
String typeId = json.getAsJsonPrimitive().getAsString();
|
||||
Class<?> result = null;
|
||||
|
||||
try {
|
||||
result = instanceGetter.getTypeForKey(Key.of(typeId));
|
||||
} catch (@SuppressWarnings("unused") Exception e) {
|
||||
|
||||
}
|
||||
|
||||
if (result == null) {
|
||||
try {
|
||||
DataTypeInfo info = DataTypeInfo.of(typeId);
|
||||
result = info.getTypeClass();
|
||||
} catch (@SuppressWarnings("unused") Exception e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (result == null) {
|
||||
try {
|
||||
result = Class.forName(typeId);
|
||||
} catch (@SuppressWarnings("unused") Exception e) {
|
||||
result = Object.class;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
178
src/edu/jhuapl/ses/jsqrl/impl/gson/DataTypeInfo.java
Normal file
178
src/edu/jhuapl/ses/jsqrl/impl/gson/DataTypeInfo.java
Normal file
@@ -0,0 +1,178 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl.gson;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.SortedMap;
|
||||
import java.util.SortedSet;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import edu.jhuapl.ses.jsqrl.api.Key;
|
||||
import edu.jhuapl.ses.jsqrl.api.Metadata;
|
||||
import edu.jhuapl.ses.jsqrl.api.StorableAsMetadata;
|
||||
import edu.jhuapl.ses.jsqrl.api.Version;
|
||||
import edu.jhuapl.ses.jsqrl.impl.InstanceGetter;
|
||||
import edu.jhuapl.ses.jsqrl.impl.Utilities;
|
||||
|
||||
/**
|
||||
* Enumerations representing different forms of type information associated with particular classes.
|
||||
* These enumerations are used via reflection to serialize objects, so it is important not to remove
|
||||
* any of these enumerations, or the associated types of objects will not be serializable. This is
|
||||
* true even if the particular enumerated items are not explicitly referenced.
|
||||
*
|
||||
* This enumeration must be kept consistent with the object types supported by the metadata package.
|
||||
*/
|
||||
enum DataTypeInfo {
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Metadata-specific types.
|
||||
METADATA_KEY("Key", Key.class, new TypeToken<Key<?>>() {}.getType()), //
|
||||
METADATA("Metadata", Metadata.class, new TypeToken<Metadata>() {}.getType()), //
|
||||
VERSION("Version", Version.class, new TypeToken<Version>() {}.getType()), //
|
||||
ELEMENT("Element", GsonElement.class, new TypeToken<GsonElement>() {}.getType()), //
|
||||
PROXIED_OBJECT("ProxiedObject", StorableAsMetadata.class,
|
||||
new TypeToken<StorableAsMetadata<?>>() {}.getType()),
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Collection types.
|
||||
LIST("List", List.class, new TypeToken<List<?>>() {}.getType()), //
|
||||
SORTED_MAP("SortedMap", SortedMap.class, new TypeToken<SortedMap<?, ?>>() {}.getType()), //
|
||||
MAP("Map", Map.class, new TypeToken<Map<?, ?>>() {}.getType()), //
|
||||
SORTED_SET("SortedSet", SortedSet.class, new TypeToken<SortedSet<?>>() {}.getType()), //
|
||||
SET("Set", Set.class, new TypeToken<Set<?>>() {}.getType()), //
|
||||
ITERABLE("Iterable", Iterable.class, new TypeToken<Iterable<?>>() {}.getType()), //
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Common object types.
|
||||
STRING("String", String.class, new TypeToken<String>() {}.getType()), //
|
||||
CHARACTER_OBJECT("Character", Character.class, new TypeToken<Character>() {}.getType()), //
|
||||
BOOLEAN_OBJECT("Boolean", Boolean.class, new TypeToken<Boolean>() {}.getType()), //
|
||||
// Floating-point types.
|
||||
DOUBLE_OBJECT("Double", Double.class, new TypeToken<Double>() {}.getType()), //
|
||||
FLOAT_OBJECT("Float", Float.class, new TypeToken<Float>() {}.getType()), //
|
||||
// Integer types.
|
||||
INTEGER_OBJECT("Integer", Integer.class, new TypeToken<Integer>() {}.getType()), //
|
||||
LONG_OBJECT("Long", Long.class, new TypeToken<Long>() {}.getType()), //
|
||||
SHORT_OBJECT("Short", Short.class, new TypeToken<Short>() {}.getType()), //
|
||||
BYTE_OBJECT("Byte", Byte.class, new TypeToken<Byte>() {}.getType()), //
|
||||
DATE_OBJECT("Date", Date.class, new TypeToken<Date>() {}.getType()), //
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Arrays of common object types.
|
||||
STRING_ARRAY("String Array", String[].class, new TypeToken<String[]>() {}.getType()), //
|
||||
CHARACTER_OBJECT_ARRAY("Character Array", Character[].class,
|
||||
new TypeToken<Character[]>() {}.getType()), //
|
||||
BOOLEAN_OBJECT_ARRAY("Boolean Array", Boolean[].class, new TypeToken<Boolean[]>() {}.getType()), //
|
||||
// Floating-point types.
|
||||
DOUBLE_OBJECT_ARRAY("Double Array", Double[].class, new TypeToken<Double[]>() {}.getType()), //
|
||||
FLOAT_OBJECT_ARRAY("Float Array", Float[].class, new TypeToken<Float[]>() {}.getType()), //
|
||||
// Integer types.
|
||||
INTEGER_OBJECT_ARRAY("Integer Array", Integer[].class, new TypeToken<Integer[]>() {}.getType()), //
|
||||
LONG_OBJECT_ARRAY("Long Array", Long[].class, new TypeToken<Long[]>() {}.getType()), //
|
||||
SHORT_OBJECT_ARRAY("Short Array", Short[].class, new TypeToken<Short[]>() {}.getType()), //
|
||||
BYTE_OBJECT_ARRAY("Byte Array", Byte[].class, new TypeToken<Byte[]>() {}.getType()), //
|
||||
DATE_ARRAY("Date Array", Date[].class, new TypeToken<Date[]>() {}.getType()), //
|
||||
METADATA_ARRAY("metadata Array", Metadata[].class, new TypeToken<Metadata[]>() {}.getType()), //
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Arrays of primitive types.
|
||||
CHARACTER_ARRAY("char Array", char[].class, new TypeToken<char[]>() {}.getType()), //
|
||||
BOOLEAN_ARRAY("boolean Array", boolean[].class, new TypeToken<boolean[]>() {}.getType()), //
|
||||
// Floating-point types.
|
||||
DOUBLE_ARRAY("double Array", double[].class, new TypeToken<double[]>() {}.getType()), //
|
||||
FLOAT_ARRAY("float Array", float[].class, new TypeToken<float[]>() {}.getType()), //
|
||||
// Integer types.
|
||||
INTEGER_ARRAY("int Array", int[].class, new TypeToken<int[]>() {}.getType()), //
|
||||
LONG_ARRAY("long Array", long[].class, new TypeToken<long[]>() {}.getType()), //
|
||||
SHORT_ARRAY("short Array", short[].class, new TypeToken<short[]>() {}.getType()), //
|
||||
BYTE_ARRAY("byte Array", byte[].class, new TypeToken<byte[]>() {}.getType()), //
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
// In a class by itself: Class:
|
||||
CLASS("Class", Class.class, new TypeToken<Class<?>>() {}.getType()), //
|
||||
SERIALIZABLE("Serializable", Serializable.class, new TypeToken<Serializable>() {}.getType()), //
|
||||
|
||||
// Catch-all case used both to handle nulls and to detect objects that cannot be serialized.
|
||||
NULL("Null", Object.class, new TypeToken<Object>() {}.getType()), //
|
||||
;
|
||||
|
||||
public static DataTypeInfo of(String typeId) {
|
||||
for (DataTypeInfo info : values()) {
|
||||
if (info.typeId.equals(typeId)) {
|
||||
return info;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Cannot decode unknown type " + typeId);
|
||||
}
|
||||
|
||||
public static DataTypeInfo of(Class<?> valueClass) {
|
||||
for (DataTypeInfo info : values()) {
|
||||
if (info.valueClass.isAssignableFrom(valueClass)) {
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
||||
// The final type info matches Object, which should be assignable from anything.
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
public static DataTypeInfo of(Type type) {
|
||||
for (DataTypeInfo info : values()) {
|
||||
if (info.type.equals(type)) {
|
||||
return info;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
public static DataTypeInfo forObject(Object object) {
|
||||
DataTypeInfo result = NULL;
|
||||
if (object != null) {
|
||||
if (InstanceGetter.defaultInstanceGetter().isStorableAsMetadata(object)) {
|
||||
result = METADATA;
|
||||
}
|
||||
if (result == NULL) {
|
||||
result = of(object.getClass());
|
||||
}
|
||||
if (result == NULL) {
|
||||
throw new IllegalArgumentException("Cannot serialize object of type "
|
||||
+ Utilities.simpleName(object.getClass()) + " to JSON format");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private final String typeId;
|
||||
private final Class<?> valueClass;
|
||||
private final Type type;
|
||||
|
||||
private DataTypeInfo(String typeId, Class<?> valueClass, Type type) {
|
||||
this.typeId = typeId;
|
||||
this.valueClass = valueClass;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getTypeId() {
|
||||
return typeId;
|
||||
}
|
||||
|
||||
public Class<?> getTypeClass() {
|
||||
return valueClass;
|
||||
}
|
||||
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TypeInfo: " + typeId + ", Type = " + type + ", class = "
|
||||
+ Utilities.simpleName(valueClass);
|
||||
}
|
||||
|
||||
}
|
||||
201
src/edu/jhuapl/ses/jsqrl/impl/gson/GsonElement.java
Normal file
201
src/edu/jhuapl/ses/jsqrl/impl/gson/GsonElement.java
Normal file
@@ -0,0 +1,201 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
|
||||
import edu.jhuapl.ses.jsqrl.api.Key;
|
||||
import edu.jhuapl.ses.jsqrl.api.Metadata;
|
||||
import edu.jhuapl.ses.jsqrl.api.Version;
|
||||
import edu.jhuapl.ses.jsqrl.impl.InstanceGetter;
|
||||
import edu.jhuapl.ses.jsqrl.impl.Utilities;
|
||||
|
||||
final class GsonElement {
|
||||
|
||||
static final class ElementIO
|
||||
implements JsonSerializer<GsonElement>, JsonDeserializer<GsonElement> {
|
||||
@Override
|
||||
public GsonElement deserialize(JsonElement jsonElement, Type typeOfT,
|
||||
JsonDeserializationContext context) throws JsonParseException {
|
||||
Preconditions.checkArgument(DataTypeInfo.ELEMENT.getType().equals(typeOfT));
|
||||
return GsonElement.of(jsonElement, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(GsonElement src, Type typeOfSrc,
|
||||
JsonSerializationContext context) {
|
||||
Preconditions.checkArgument(DataTypeInfo.ELEMENT.getType().equals(typeOfSrc));
|
||||
return src.toElement(context);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final InstanceGetter INSTANCE_GETTER = InstanceGetter.defaultInstanceGetter();
|
||||
|
||||
static final String VALUE_TYPE_KEY = "valueType";
|
||||
|
||||
public static JsonElement encodeItem(Object item, boolean excludeMetadataVersion,
|
||||
JsonSerializationContext context) {
|
||||
|
||||
item = Utilities.provideMetadataIfPossible(item);
|
||||
|
||||
DataTypeInfo typeInfo = DataTypeInfo.forObject(item);
|
||||
|
||||
if (excludeMetadataVersion && typeInfo == DataTypeInfo.METADATA) {
|
||||
return MetadataIOv2.encodeWithoutVersion((Metadata) item, context);
|
||||
}
|
||||
|
||||
return context.serialize(item, typeInfo.getType());
|
||||
}
|
||||
|
||||
public static JsonElement encodeItemWithType(Object item, boolean excludeMetadataVersion,
|
||||
JsonSerializationContext context) {
|
||||
|
||||
Key<? extends Object> typeKey = Utilities.provideTypeKeyIfPossible(item);
|
||||
|
||||
item = Utilities.provideMetadataIfPossible(item);
|
||||
|
||||
String typeId = typeKey != null ? typeKey.getId() : DataTypeInfo.forObject(item).getTypeId();
|
||||
|
||||
JsonObject result = new JsonObject();
|
||||
|
||||
result.add(typeId, encodeItem(item, excludeMetadataVersion, context));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void encodeTypeInfo(String typeId, JsonObject encodedItem) {
|
||||
encodedItem.addProperty(VALUE_TYPE_KEY, typeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode item according to the supplied type, using the supplied version (if not null) for all
|
||||
* Metadata.
|
||||
*
|
||||
* @param encodedItem
|
||||
* @param typeInfo
|
||||
* @param context
|
||||
* @return
|
||||
*/
|
||||
public static Object decodeItem(JsonElement encodedItem, Key<?> typeKey, Version commonVersion,
|
||||
JsonDeserializationContext context) {
|
||||
|
||||
if (INSTANCE_GETTER.isProvidableFromMetadata(typeKey)) {
|
||||
Metadata metadata =
|
||||
(Metadata) decodeItem(encodedItem, DataTypeInfo.METADATA, commonVersion, context);
|
||||
return INSTANCE_GETTER.providesGenericObjectFromMetadata(typeKey).provide(metadata);
|
||||
}
|
||||
|
||||
DataTypeInfo typeInfo = DataTypeInfo.of(typeKey.getId());
|
||||
return decodeItem(encodedItem, typeInfo, commonVersion, context);
|
||||
}
|
||||
|
||||
private static Object decodeItem(JsonElement encodedItem, DataTypeInfo typeInfo,
|
||||
Version commonVersion, JsonDeserializationContext context) {
|
||||
|
||||
if (commonVersion != null && typeInfo == DataTypeInfo.METADATA) {
|
||||
return MetadataIOv2.decode(encodedItem.getAsJsonObject(), commonVersion, context);
|
||||
}
|
||||
|
||||
return context.deserialize(encodedItem, typeInfo.getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode item using self-contained type informtion but with the supplied Version for decoding
|
||||
* compressed Metadata.
|
||||
*
|
||||
* @param encodedItem
|
||||
* @param commonVersion
|
||||
* @param context
|
||||
* @return
|
||||
*/
|
||||
public static Object decodeItem(JsonElement encodedItem, Version commonVersion,
|
||||
JsonDeserializationContext context) {
|
||||
Preconditions.checkArgument(encodedItem.isJsonObject());
|
||||
|
||||
JsonObject encodedTypeAndValue = encodedItem.getAsJsonObject();
|
||||
Preconditions.checkState(encodedTypeAndValue.size() == 1);
|
||||
|
||||
// Easiest way to get to the single entry is just to use a one-time loop.
|
||||
// That way we don't have to mess with the entry set, iterators etc.
|
||||
for (Entry<String, JsonElement> entry : encodedTypeAndValue.entrySet()) {
|
||||
Key<?> proxyTypeKey = Key.of(entry.getKey());
|
||||
JsonElement encodedValue = entry.getValue();
|
||||
|
||||
if (INSTANCE_GETTER.isProvidableFromMetadata(proxyTypeKey)) {
|
||||
Metadata metadata =
|
||||
(Metadata) decodeItem(encodedValue, DataTypeInfo.METADATA, commonVersion, context);
|
||||
return INSTANCE_GETTER.providesGenericObjectFromMetadata(proxyTypeKey).provide(metadata);
|
||||
}
|
||||
|
||||
DataTypeInfo typeInfo = DataTypeInfo.of(proxyTypeKey.getId());
|
||||
|
||||
return decodeItem(encodedValue, typeInfo, commonVersion, context);
|
||||
}
|
||||
|
||||
// Can't get here because the loop above is guaranteed to execute at least once.
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
public static Key<?> decodeTypeInfo(JsonObject encodedItem) {
|
||||
Key<?> typeKey = null;
|
||||
|
||||
if (encodedItem.has(VALUE_TYPE_KEY)) {
|
||||
JsonElement encodedType = encodedItem.get(VALUE_TYPE_KEY);
|
||||
typeKey = Key.of(encodedType.getAsString());
|
||||
}
|
||||
|
||||
return typeKey;
|
||||
}
|
||||
|
||||
public static GsonElement of(Object object) {
|
||||
return new GsonElement(object, DataTypeInfo.forObject(object));
|
||||
}
|
||||
|
||||
private static GsonElement of(JsonElement element, JsonDeserializationContext context) {
|
||||
Preconditions.checkNotNull(element);
|
||||
Preconditions.checkNotNull(context);
|
||||
Preconditions.checkArgument(element.isJsonObject());
|
||||
|
||||
JsonObject valueObject = element.getAsJsonObject();
|
||||
|
||||
Set<Entry<String, JsonElement>> entryList = valueObject.entrySet();
|
||||
Preconditions.checkState(entryList.size() == 1);
|
||||
|
||||
Entry<String, JsonElement> entry = entryList.iterator().next();
|
||||
DataTypeInfo objectInfo = DataTypeInfo.of(entry.getKey());
|
||||
|
||||
Object object = context.deserialize(entry.getValue(), objectInfo.getType());
|
||||
|
||||
return new GsonElement(object, objectInfo);
|
||||
}
|
||||
|
||||
private final Object object;
|
||||
private final DataTypeInfo objectInfo;
|
||||
|
||||
private GsonElement(Object object, DataTypeInfo objectInfo) {
|
||||
Preconditions.checkNotNull(objectInfo);
|
||||
this.object = object;
|
||||
this.objectInfo = objectInfo;
|
||||
}
|
||||
|
||||
public JsonElement toElement(JsonSerializationContext context) {
|
||||
JsonObject result = new JsonObject();
|
||||
result.add(objectInfo.getTypeId(), context.serialize(object, objectInfo.getType()));
|
||||
return result;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return object;
|
||||
}
|
||||
|
||||
}
|
||||
788
src/edu/jhuapl/ses/jsqrl/impl/gson/GsonSerializer.java
Normal file
788
src/edu/jhuapl/ses/jsqrl/impl/gson/GsonSerializer.java
Normal file
@@ -0,0 +1,788 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl.gson;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.SortedMap;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSortedSet;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import edu.jhuapl.ses.jsqrl.api.Key;
|
||||
import edu.jhuapl.ses.jsqrl.api.Metadata;
|
||||
import edu.jhuapl.ses.jsqrl.api.MetadataManager;
|
||||
import edu.jhuapl.ses.jsqrl.api.RepresentableAsMetadata;
|
||||
import edu.jhuapl.ses.jsqrl.api.Serializer;
|
||||
import edu.jhuapl.ses.jsqrl.api.StorableAsMetadata;
|
||||
import edu.jhuapl.ses.jsqrl.api.Version;
|
||||
import edu.jhuapl.ses.jsqrl.impl.InstanceGetter;
|
||||
import edu.jhuapl.ses.jsqrl.impl.SettableMetadata;
|
||||
import edu.jhuapl.ses.jsqrl.impl.EmptyMetadata;
|
||||
import edu.jhuapl.ses.jsqrl.impl.MetadataManagerCollection;
|
||||
import edu.jhuapl.ses.jsqrl.impl.gson.GsonElement.ElementIO;
|
||||
|
||||
public class GsonSerializer implements Serializer {
|
||||
|
||||
// Release notes are now in the package-info file.
|
||||
|
||||
// Encapsulation versions.
|
||||
// This version supports serializing proxy class metadata using the same format used
|
||||
// by standard Metadata (as in the Metadata interface). Instead of the key "Metadata",
|
||||
// the name of the type serves as the key in the output file format. Previous versions used a
|
||||
// separate proxy encapsulation. For backward compatibility, the proxy is still supported.
|
||||
private static final Version SERIALIZER_VERSION_4 = Version.of(4, 0);
|
||||
|
||||
// This version reads and writes syntactically correct JSON format files. Previous versions
|
||||
// were flawed in that they stored two consecutive JSON objects at the top level of the file.
|
||||
private static final Version SERIALIZER_VERSION_3 = Version.of(3, 0);
|
||||
|
||||
// This version added support for:
|
||||
// 1) saving/loading heterogeneous collections and
|
||||
// 2) compressed format when a collection of Metadata objects happen to have the same
|
||||
// version. In this case the version is stored once for the whole array or collection.
|
||||
private static final Version SERIALIZER_VERSION_2 = Version.of(2, 0);
|
||||
|
||||
// Initial version.
|
||||
private static final Version SERIALIZER_VERSION_1 = Version.of(1, 0);
|
||||
|
||||
private final MetadataManagerCollection managerCollection;
|
||||
|
||||
public static GsonSerializer of() {
|
||||
return new GsonSerializer();
|
||||
}
|
||||
|
||||
protected GsonSerializer() {
|
||||
this.managerCollection = MetadataManagerCollection.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Version getVersion() {
|
||||
return SERIALIZER_VERSION_4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(Key<? extends Metadata> key, MetadataManager manager) {
|
||||
managerCollection.add(key, manager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deregister(Key<? extends Metadata> key) {
|
||||
managerCollection.remove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(File file) throws IOException {
|
||||
Preconditions.checkNotNull(file);
|
||||
|
||||
Version fileVersion = loadVersion(file);
|
||||
|
||||
if (SERIALIZER_VERSION_3.compareTo(fileVersion) > 0) {
|
||||
loadBeforeV3(file);
|
||||
return;
|
||||
}
|
||||
Gson gson = configureGson(fileVersion);
|
||||
|
||||
try (JsonReader reader = gson.newJsonReader(new FileReader(file))) {
|
||||
Metadata source = gson.fromJson(reader, DataTypeInfo.METADATA.getType());
|
||||
retrieveInSingleThreadContext(source);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(File file) throws IOException {
|
||||
Preconditions.checkNotNull(file);
|
||||
|
||||
File dir = file.getParentFile();
|
||||
if (!dir.exists()) {
|
||||
dir.mkdirs();
|
||||
}
|
||||
save(file, getVersion());
|
||||
}
|
||||
|
||||
private Version loadVersion(File file) throws IOException {
|
||||
Preconditions.checkNotNull(file);
|
||||
|
||||
Gson gson = createGsonBuilder().create();
|
||||
try (JsonReader jsonReader = gson.newJsonReader(new FileReader(file))) {
|
||||
jsonReader.beginObject();
|
||||
|
||||
String name = jsonReader.nextName();
|
||||
if (!name.equals(DataTypeInfo.VERSION.getTypeId())) {
|
||||
throw new IOException("Invalid Metadata file format");
|
||||
}
|
||||
|
||||
String versionString = jsonReader.nextString();
|
||||
|
||||
return Version.of(versionString);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void loadBeforeV3(File file) throws IOException {
|
||||
Preconditions.checkNotNull(file);
|
||||
|
||||
SettableMetadata source = SettableMetadata.of(Version.of(0, 0));
|
||||
Gson versionOnlyGson = configureGsonToReadVersionOnly();
|
||||
try (JsonReader reader = versionOnlyGson.newJsonReader(new FileReader(file))) {
|
||||
Version fileVersion = null;
|
||||
try {
|
||||
fileVersion = versionOnlyGson.fromJson(reader, DataTypeInfo.VERSION.getType());
|
||||
} catch (Exception e) {
|
||||
throw new IOException("Metadata reader version " + getVersion()
|
||||
+ " cannot read metadata format of file " + file, e);
|
||||
}
|
||||
|
||||
Gson gson = configureGson(fileVersion);
|
||||
|
||||
Map<String, Metadata> metadataMap = gson.fromJson(reader, DataTypeInfo.MAP.getType());
|
||||
for (Entry<String, Metadata> entry : metadataMap.entrySet()) {
|
||||
source.put(Key.of(entry.getKey()), entry.getValue());
|
||||
}
|
||||
}
|
||||
retrieveInSingleThreadContext(source);
|
||||
}
|
||||
|
||||
private void save(File file, Version version) throws IOException {
|
||||
if (version.equals(SERIALIZER_VERSION_1)) {
|
||||
saveV1(file);
|
||||
return;
|
||||
} else if (version.equals(SERIALIZER_VERSION_2)) {
|
||||
saveV2(file);
|
||||
return;
|
||||
}
|
||||
|
||||
Gson gson = configureGson(version);
|
||||
try (FileWriter fileWriter = new FileWriter(file)) {
|
||||
try (JsonWriter jsonWriter = gson.newJsonWriter(fileWriter)) {
|
||||
|
||||
SettableMetadata metaMetadata = SettableMetadata.of(version);
|
||||
Map<String, Metadata> metadataMap = new LinkedHashMap<>();
|
||||
for (Key<? extends Metadata> key : managerCollection.getKeys()) {
|
||||
MetadataManager manager = managerCollection.getManager(key);
|
||||
Metadata metadata = manager.store();
|
||||
if (!EmptyMetadata.instance().equals(metadata)) {
|
||||
metaMetadata.put(Key.of(key.getId()), metadata);
|
||||
metadataMap.put(key.getId(), metadata);
|
||||
}
|
||||
}
|
||||
|
||||
gson.toJson(metaMetadata, DataTypeInfo.METADATA.getType(), jsonWriter);
|
||||
|
||||
fileWriter.write('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void saveV2(File file) throws IOException {
|
||||
Preconditions.checkNotNull(file);
|
||||
Gson gson = configureGson(SERIALIZER_VERSION_2);
|
||||
try (FileWriter fileWriter = new FileWriter(file)) {
|
||||
try (JsonWriter jsonWriter = gson.newJsonWriter(fileWriter)) {
|
||||
Map<String, Metadata> metadataMap = new HashMap<>();
|
||||
for (Key<? extends Metadata> key : managerCollection.getKeys()) {
|
||||
MetadataManager manager = managerCollection.getManager(key);
|
||||
Metadata metadata = manager.store();
|
||||
if (!EmptyMetadata.instance().equals(metadata)) {
|
||||
metadataMap.put(key.getId(), metadata);
|
||||
}
|
||||
}
|
||||
gson.toJson(SERIALIZER_VERSION_2, DataTypeInfo.VERSION.getType(), jsonWriter);
|
||||
jsonWriter.flush();
|
||||
fileWriter.write('\n');
|
||||
gson.toJson(metadataMap, DataTypeInfo.MAP.getType(), jsonWriter);
|
||||
jsonWriter.flush();
|
||||
fileWriter.write('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void saveV1(File file) throws IOException {
|
||||
Preconditions.checkNotNull(file);
|
||||
|
||||
Gson gson = configureGson(SERIALIZER_VERSION_1);
|
||||
try (FileWriter fileWriter = new FileWriter(file)) {
|
||||
try (JsonWriter jsonWriter = gson.newJsonWriter(fileWriter)) {
|
||||
Map<String, Metadata> metadataMap = new HashMap<>();
|
||||
for (Key<? extends Metadata> key : managerCollection.getKeys()) {
|
||||
MetadataManager manager = managerCollection.getManager(key);
|
||||
Metadata metadata = manager.store();
|
||||
if (!EmptyMetadata.instance().equals(metadata)) {
|
||||
metadataMap.put(key.getId(), metadata);
|
||||
}
|
||||
}
|
||||
gson.toJson(SERIALIZER_VERSION_1, DataTypeInfo.VERSION.getType(), jsonWriter);
|
||||
jsonWriter.flush();
|
||||
fileWriter.write('\n');
|
||||
gson.toJson(metadataMap, DataTypeInfo.MAP.getType(), jsonWriter);
|
||||
jsonWriter.flush();
|
||||
fileWriter.write('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void retrieveInSingleThreadContext(Metadata source) {
|
||||
for (Key<? extends Metadata> key : managerCollection.getKeys()) {
|
||||
if (source.hasKey(key)) {
|
||||
Metadata element = source.get(key);
|
||||
if (element != null) {
|
||||
managerCollection.getManager(key).retrieve(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Gson configureGsonToReadVersionOnly() {
|
||||
GsonBuilder builder = new GsonBuilder();
|
||||
builder.registerTypeAdapter(DataTypeInfo.VERSION.getType(), new GsonVersionIO());
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
private static Gson configureGson(Version serializerVersion) {
|
||||
if (SERIALIZER_VERSION_1.equals(serializerVersion)) {
|
||||
return configureGsonV1();
|
||||
}
|
||||
|
||||
return configureGsonBuilder().create();
|
||||
}
|
||||
|
||||
private static GsonBuilder createGsonBuilder() {
|
||||
GsonBuilder builder = new GsonBuilder();
|
||||
|
||||
builder.serializeNulls();
|
||||
builder.setPrettyPrinting();
|
||||
builder.serializeSpecialFloatingPointValues();
|
||||
builder.disableHtmlEscaping();
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
private static GsonBuilder configureGsonBuilder() {
|
||||
GsonBuilder builder = createGsonBuilder();
|
||||
|
||||
builder.registerTypeAdapter(DataTypeInfo.SORTED_SET.getType(), new SortedSetIOv2());
|
||||
builder.registerTypeAdapter(DataTypeInfo.SET.getType(), new SetIOv2());
|
||||
builder.registerTypeAdapter(DataTypeInfo.LIST.getType(), new ListIOv2());
|
||||
builder.registerTypeAdapter(DataTypeInfo.ITERABLE.getType(), new ListIOv2());
|
||||
builder.registerTypeAdapter(DataTypeInfo.SORTED_MAP.getType(), new SortedMapIOv2());
|
||||
builder.registerTypeAdapter(DataTypeInfo.MAP.getType(), new MapIOv2());
|
||||
builder.registerTypeAdapter(DataTypeInfo.METADATA.getType(), new MetadataIOv2());
|
||||
builder.registerTypeAdapter(DataTypeInfo.VERSION.getType(), new GsonVersionIO());
|
||||
builder.registerTypeAdapter(DataTypeInfo.ELEMENT.getType(), new ElementIO());
|
||||
builder.registerTypeAdapter(DataTypeInfo.PROXIED_OBJECT.getType(), new ProxyIOv2<>());
|
||||
builder.registerTypeAdapter(DataTypeInfo.CLASS.getType(), new ClassIO());
|
||||
builder.registerTypeAdapter(DataTypeInfo.SERIALIZABLE.getType(), new SerializableIO());
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
private static Gson configureGsonV1() {
|
||||
GsonBuilder builder = createGsonBuilder();
|
||||
|
||||
builder.registerTypeAdapter(DataTypeInfo.SORTED_SET.getType(), new SortedSetIOv1());
|
||||
builder.registerTypeAdapter(DataTypeInfo.SET.getType(), new SetIOv1());
|
||||
builder.registerTypeAdapter(DataTypeInfo.LIST.getType(), new ListIOv1());
|
||||
builder.registerTypeAdapter(DataTypeInfo.ITERABLE.getType(), new ListIOv1());
|
||||
builder.registerTypeAdapter(DataTypeInfo.SORTED_MAP.getType(), new SortedMapIOv1());
|
||||
builder.registerTypeAdapter(DataTypeInfo.MAP.getType(), new MapIOv1());
|
||||
builder.registerTypeAdapter(DataTypeInfo.METADATA.getType(), new MetadataIOv1());
|
||||
builder.registerTypeAdapter(DataTypeInfo.VERSION.getType(), new GsonVersionIO());
|
||||
builder.registerTypeAdapter(DataTypeInfo.ELEMENT.getType(), new ElementIO());
|
||||
builder.registerTypeAdapter(DataTypeInfo.PROXIED_OBJECT.getType(), new ProxyIOv1<>());
|
||||
builder.registerTypeAdapter(DataTypeInfo.CLASS.getType(), new ClassIO());
|
||||
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
/**
|
||||
* This enumeration demonstrates how to serialize/deserialize an enumeration by implementing the
|
||||
* StorableAsMetadata interface.
|
||||
*
|
||||
*/
|
||||
private static final Key<String> NAME = Key.of("Name");
|
||||
private static final Key<TestEnum> TEST_ENUM_PROXY_KEY = Key.of("TestEnum");
|
||||
private static final Version VERSION = Version.of(1, 0);
|
||||
|
||||
private enum TestEnum implements StorableAsMetadata<TestEnum> {
|
||||
OPTION0("Option 0"), OPTION1("Option 1");
|
||||
|
||||
// Need to live with this warning until the register method has been phased out.
|
||||
public static void register(InstanceGetter instanceGetter) {
|
||||
instanceGetter.register(TEST_ENUM_PROXY_KEY, (metadata) -> {
|
||||
return valueOf(metadata.get(NAME));
|
||||
});
|
||||
}
|
||||
|
||||
private final String text;
|
||||
|
||||
TestEnum(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Key<TestEnum> getKey() {
|
||||
return TEST_ENUM_PROXY_KEY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Metadata store() {
|
||||
return SettableMetadata.of(VERSION).put(NAME, name());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This enumeration demonstrates how to serialize/deserialize an enumeration without implementing
|
||||
* StorableAsMetadata.
|
||||
*/
|
||||
private enum TestEnum2 {
|
||||
OPTION0, OPTION1;
|
||||
}
|
||||
|
||||
private static final Key<TestEnum2> TEST_ENUM2_PROXY_KEY = Key.of("TestEnum2");
|
||||
|
||||
private static void registerTestEnum2(InstanceGetter instanceGetter) {
|
||||
instanceGetter.register(TEST_ENUM2_PROXY_KEY, metadata -> {
|
||||
return TestEnum2.valueOf(metadata.get(NAME));
|
||||
}, TestEnum2.class, object -> {
|
||||
return SettableMetadata.of(VERSION).put(NAME, object.name());
|
||||
});
|
||||
}
|
||||
|
||||
private static class TestManager implements MetadataManager {
|
||||
private final SettableMetadata metadata;
|
||||
|
||||
TestManager(SettableMetadata metadata) {
|
||||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Metadata store() {
|
||||
SettableMetadata destination = SettableMetadata.of(metadata.getVersion());
|
||||
for (Key<?> key : metadata.getKeys()) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Key<Object> newKey = (Key<Object>) key;
|
||||
destination.put(newKey, metadata.get(key));
|
||||
}
|
||||
|
||||
return destination;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void retrieve(Metadata source) {
|
||||
metadata.clear();
|
||||
for (Key<?> key : source.getKeys()) {
|
||||
Object value = source.get(key);
|
||||
@SuppressWarnings("unchecked")
|
||||
Key<Object> newKey = (Key<Object>) key;
|
||||
metadata.put(newKey, value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// These are all just fodder for test cases, These version numbers have nothing to do with the
|
||||
// version of
|
||||
// the serializer.
|
||||
private static final Version SAMPLE_METADATA_VERSION = Version.of(1, 0);
|
||||
private static final Version SAMPLE_SUB_METADATA_VERSION = Version.of(3, 1);
|
||||
private static final String SUB_METADATA_ID = "Bennu / V3";
|
||||
private static final Key<SettableMetadata> SAMPLE_METADATA_KEY = Key.of("testState");
|
||||
private static final Key<SettableMetadata> SAMPLE_SUB_METADATA_KEY = Key.of(SUB_METADATA_ID);
|
||||
private static final Key<List<List<String>>> LIST_LIST_STRING_KEY = Key.of("listListString");
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
TestEnum.register(InstanceGetter.defaultInstanceGetter());
|
||||
registerTestEnum2(InstanceGetter.defaultInstanceGetter());
|
||||
|
||||
// Test failure when trying to serialize something that can't be serialized.
|
||||
{
|
||||
class UnserializableObject {
|
||||
|
||||
};
|
||||
|
||||
UnserializableObject unserializableObject = new UnserializableObject();
|
||||
|
||||
try {
|
||||
SettableMetadata.of(SAMPLE_METADATA_VERSION).put(Key.of("unserializable"),
|
||||
unserializableObject);
|
||||
System.err.println("Saving an unserializable object did not throw an exception");
|
||||
} catch (@SuppressWarnings("unused") IllegalArgumentException e) {
|
||||
// This is as it should be.
|
||||
}
|
||||
}
|
||||
|
||||
// Test V1.
|
||||
String testPath = Paths.get(System.getProperty("user.home"), "Downloads").toString();
|
||||
{
|
||||
SettableMetadata state = createV1SampleMetadata();
|
||||
File file = Paths.get(testPath, "MyStateV1.sbmt").toFile();
|
||||
testSaveAndReloadState(state, file, SERIALIZER_VERSION_1);
|
||||
}
|
||||
|
||||
// Test V2.
|
||||
{
|
||||
SettableMetadata state = createV2SampleMetadata();
|
||||
File file = Paths.get(testPath, "MyStateV2.sbmt").toFile();
|
||||
testSaveAndReloadState(state, file, SERIALIZER_VERSION_2);
|
||||
}
|
||||
|
||||
// Test V3.
|
||||
{
|
||||
SettableMetadata state = createV3SampleMetadata();
|
||||
File file = Paths.get(testPath, "MyStateV3.sbmt").toFile();
|
||||
testSaveAndReloadState(state, file, SERIALIZER_VERSION_3);
|
||||
}
|
||||
|
||||
// Test current version.
|
||||
{
|
||||
SettableMetadata state = createV4SampleMetadata();
|
||||
File file = Paths.get(testPath, "MyState.sbmt").toFile();
|
||||
state = testSaveAndReloadState(state, file, SERIALIZER_VERSION_4);
|
||||
|
||||
SettableMetadata subState = state.get(SAMPLE_SUB_METADATA_KEY);
|
||||
|
||||
// Test some further unpacking.
|
||||
state.get(Key.of("double array"));
|
||||
state.get(Key.of("int array"));
|
||||
state.get(Key.of("Double array"));
|
||||
state.get(Key.of("Integer array"));
|
||||
state.get(Key.of("String array"));
|
||||
|
||||
subState.get(Key.of("longNull"));
|
||||
if (TestEnum.OPTION1 != subState.get(Key.of("testEnum"))) {
|
||||
System.err.println("testEnum value was not option 1");
|
||||
}
|
||||
|
||||
state.get(Key.of("stringSet"));
|
||||
|
||||
if (TestEnum2.OPTION1 != subState.get(Key.of("testEnum2"))) {
|
||||
System.err
|
||||
.println("testEnum2 value was " + subState.get(Key.of("testEnum2")) + ", not option 1");
|
||||
}
|
||||
|
||||
// This fails at runtime. If this were a real key templated on Long it would fail at compile
|
||||
// time.
|
||||
// Float fVal = subState.get(Key.of("long"));
|
||||
|
||||
// This doesn't fail at runtime or compile time but I wish it would:
|
||||
// List<List<Integer>> unpackedListList = state.get(Key.of("listListString"));
|
||||
|
||||
// But the following does fail to compile, which is probably good enough.
|
||||
// unpackedListList = state.get(listListStringKey);
|
||||
// And this fails at runtime, as it should.
|
||||
// System.out.println(unpackedListList.get(1).get(1) * 7);
|
||||
|
||||
// It would be OK if this were to work but it doesn't.
|
||||
// float fVal = subState.get(Key.of("resolution"));
|
||||
|
||||
// This one is supposed to throw an exception.
|
||||
// Short longAsShort = subState.get(Key.of("facets"));
|
||||
// System.err.println("long retrieved as a short is " + longAsShort);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static SettableMetadata createV1SampleMetadata() {
|
||||
|
||||
SettableMetadata subState = SettableMetadata.of(SAMPLE_SUB_METADATA_VERSION);
|
||||
TestEnum testEnumBefore = TestEnum.OPTION1;
|
||||
|
||||
subState.put(Key.of("tab"), "1");
|
||||
subState.put(Key.of("facets"), 2000000001L);
|
||||
subState.put(Key.of("showBaseMap"), true);
|
||||
subState.put(Key.of("resolution"), -5.e64);
|
||||
subState.put(Key.of("int"), 20);
|
||||
subState.put(Key.of("long"), (long) 20);
|
||||
subState.put(Key.of("short"), (short) 20);
|
||||
subState.put(Key.of("byte"), (byte) 20);
|
||||
subState.put(Key.of("double"), (double) 20);
|
||||
subState.put(Key.of("float"), (float) 20);
|
||||
subState.put(Key.of("char"), (char) 20);
|
||||
subState.put(Key.of("boolean"), false);
|
||||
subState.put(Key.of("string"), "a string");
|
||||
subState.put(Key.of("htmlString"), "<pre>A literal escaped in html</pre>");
|
||||
subState.put(Key.of("stringNull"), null);
|
||||
subState.put(Key.of("longNull"), null);
|
||||
subState.put(Key.of("testEnum"), testEnumBefore);
|
||||
subState.put(Key.of("List<TestEnum>"), ImmutableList.of(TestEnum.OPTION1, TestEnum.OPTION0));
|
||||
|
||||
List<String> stringList = new ArrayList<>();
|
||||
stringList.add("String0");
|
||||
stringList.add(null);
|
||||
stringList.add("String2");
|
||||
Key<List<String>> stringListKey = Key.of("stringList");
|
||||
subState.put(stringListKey, stringList);
|
||||
|
||||
List<Integer> intList = new ArrayList<>();
|
||||
intList.add(0);
|
||||
intList.add(null);
|
||||
intList.add(2);
|
||||
Key<List<Integer>> intListKey = Key.of("intList");
|
||||
subState.put(intListKey, intList);
|
||||
|
||||
List<List<String>> listListString = new ArrayList<>();
|
||||
listListString.add(null);
|
||||
listListString.add(ImmutableList.of("X", "y", "z"));
|
||||
listListString.add(stringList);
|
||||
|
||||
final SettableMetadata state = SettableMetadata.of(SAMPLE_METADATA_VERSION);
|
||||
|
||||
state.put(Key.of("Current View"), SUB_METADATA_ID);
|
||||
state.put(Key.of("Tab Number"), new Integer(3));
|
||||
state.put(Key.of("Current View2"), SUB_METADATA_ID);
|
||||
state.put(LIST_LIST_STRING_KEY, listListString);
|
||||
state.put(Key.of("stringSet"), ImmutableSortedSet.of("liver", "spleen", "aardvark"));
|
||||
state.put(Key.of("Metadata"), "a string that happens to have the key \"Metadata\"");
|
||||
// The following type has built-in support through DataTypeInfo.
|
||||
state.put(Key.of("Double.class"), Double.class);
|
||||
// The following type is registered with InstanceGetter. This should work using the registerd
|
||||
// name.
|
||||
state.put(Key.of("TestEnum2.class"), TestEnum2.class);
|
||||
// The following type is not registered with InstanceGetter. This should also work using the
|
||||
// full class name.
|
||||
state.put(Key.of("Metadata.class"), RepresentableAsMetadata.class);
|
||||
|
||||
Map<Byte, Short> byteShortMap = new HashMap<>();
|
||||
byteShortMap.put((byte) 1, null);
|
||||
byteShortMap.put(null, (short) 12);
|
||||
byteShortMap.put((byte) 11, (short) 23);
|
||||
byteShortMap.put((byte) 10, (short) 17);
|
||||
Key<Map<Byte, Short>> byteShortMapKey = Key.of("byteShortMap");
|
||||
state.put(byteShortMapKey, byteShortMap);
|
||||
|
||||
SortedMap<Byte, Short> byteSortedMap = new TreeMap<>();
|
||||
byteSortedMap.put((byte) 1, null);
|
||||
byteSortedMap.put((byte) 11, (short) 23);
|
||||
byteSortedMap.put((byte) 10, (short) 17);
|
||||
Key<SortedMap<Byte, Short>> byteSortedMapKey = Key.of("byteSortedMap");
|
||||
state.put(byteSortedMapKey, byteSortedMap);
|
||||
|
||||
SortedMap<String, SortedMap<Integer, String>> homogeneousMapMap = new TreeMap<>();
|
||||
homogeneousMapMap.put("nullMap", null);
|
||||
SortedMap<Integer, String> intMap = new TreeMap<>();
|
||||
intMap.put(0, "zero");
|
||||
intMap.put(1, "one");
|
||||
homogeneousMapMap.put("map0", intMap);
|
||||
homogeneousMapMap.put("map1", intMap);
|
||||
state.put(Key.of("homogeneous map of map"), homogeneousMapMap);
|
||||
homogeneousMapMap = state.get(Key.of("homogeneous map of map"));
|
||||
|
||||
SortedSet<String> treeSet = new TreeSet<>();
|
||||
treeSet.add("string0");
|
||||
state.put(Key.of("treeSet"), treeSet);
|
||||
treeSet = state.get(Key.of("treeSet"));
|
||||
|
||||
state.put(Key.of("single element map"), ImmutableMap.of("key0", "value0"));
|
||||
state.put(Key.of("single element list"), ImmutableList.of(7));
|
||||
|
||||
state.put(Key.of("double array"), new double[] {3., 4., 5.});
|
||||
state.put(Key.of("int array"), new int[] {6, 7, 8});
|
||||
state.put(Key.of("Double array"), new Double[] {9., 10., 11.});
|
||||
state.put(Key.of("Integer array"), new Integer[] {12, 13, 14});
|
||||
state.put(Key.of("String array"), new String[] {"a", "b", "c"});
|
||||
|
||||
state.put(SAMPLE_SUB_METADATA_KEY, subState);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
private static SettableMetadata createV2SampleMetadata() {
|
||||
// Start with the V1 metadata set.
|
||||
SettableMetadata state = createV1SampleMetadata();
|
||||
SettableMetadata subState = state.get(SAMPLE_SUB_METADATA_KEY);
|
||||
|
||||
// Add tests for things supported in V2 and above.
|
||||
SortedMap<String, SortedMap<Integer, Object>> mapHeterogeneousMap = new TreeMap<>();
|
||||
mapHeterogeneousMap.put("nullMap", null);
|
||||
SortedMap<Integer, Object> nestedMap = new TreeMap<>();
|
||||
nestedMap.put(0, "zero");
|
||||
nestedMap.put(1, 1.);
|
||||
mapHeterogeneousMap.put("map0", nestedMap);
|
||||
mapHeterogeneousMap.put("map1", nestedMap);
|
||||
state.put(Key.of("map of heterogenous maps"), mapHeterogeneousMap);
|
||||
|
||||
List<Integer> intList = subState.get(Key.of("intList"));
|
||||
|
||||
SortedMap<String, Object> mapOfCollections = new TreeMap<>();
|
||||
mapOfCollections.put("nullMap", null);
|
||||
mapOfCollections.put("map", nestedMap);
|
||||
mapOfCollections.put("intList", intList);
|
||||
state.put(Key.of("map containing nested objects"), mapOfCollections);
|
||||
|
||||
List<Object> objectList = new ArrayList<Object>();
|
||||
objectList.add(null);
|
||||
objectList.add("a");
|
||||
objectList.add(1);
|
||||
objectList.add(2.);
|
||||
objectList.add(false);
|
||||
objectList.add(SettableMetadata.of(Version.of(1, 3)));
|
||||
objectList.add(SettableMetadata.of(Version.of(1, 3)).put(Key.of("key0"), "value0"));
|
||||
subState.put(Key.of("objectList"), objectList);
|
||||
|
||||
Set<Object> objectSet = new HashSet<>();
|
||||
objectSet.add("a");
|
||||
objectSet.add(null);
|
||||
objectSet.add(1);
|
||||
objectSet.add(2.);
|
||||
objectSet.add(true);
|
||||
objectSet.add(SettableMetadata.of(Version.of(1, 3)).put(Key.of("key0"), "value0"));
|
||||
subState.put(Key.of("objectSet"), objectSet);
|
||||
|
||||
Map<Object, Object> objectMap = new HashMap<>();
|
||||
objectMap.put("key0", "repeatedValue");
|
||||
objectMap.put("key1", "repeatedValue");
|
||||
objectMap.put(null, "valueForNullKey");
|
||||
objectMap.put("key2", "distinctValue");
|
||||
subState.put(Key.of("homogeneousObjectMap"), objectMap);
|
||||
try {
|
||||
// Now test exception for heterogenous keys.
|
||||
objectMap.put(7, "stringValue");
|
||||
subState.put(Key.of("invalidObjectMap"), objectMap);
|
||||
} catch (@SuppressWarnings("unused") IllegalArgumentException e) {
|
||||
// This is as it should be.
|
||||
}
|
||||
|
||||
objectMap = new HashMap<>();
|
||||
objectMap.put("key0", "repeatedValue");
|
||||
objectMap.put("key1", "repeatedValue");
|
||||
objectMap.put(null, 0);
|
||||
objectMap.put("key2", 4.2);
|
||||
objectMap.put("meta0", SettableMetadata.of(Version.of(2, 2)).put(Key.of("key0"), "value0"));
|
||||
objectMap.put("meta1", SettableMetadata.of(Version.of(2, 2)).put(Key.of("key1"), "value1"));
|
||||
objectMap.put("meta2", SettableMetadata.of(Version.of(2, 3)).put(Key.of("key1"), "value1"));
|
||||
subState.put(Key.of("heterogeneousObjectMap"), objectMap);
|
||||
|
||||
objectMap = new HashMap<>();
|
||||
objectMap.put("key0", "repeatedValue");
|
||||
objectMap.put("key1", "repeatedValue");
|
||||
objectMap.put(null, 0);
|
||||
objectMap.put("key2", 4.2);
|
||||
objectMap.put("meta0", SettableMetadata.of(Version.of(2, 2)).put(Key.of("key0"), "value0"));
|
||||
objectMap.put("meta1", SettableMetadata.of(Version.of(2, 2)).put(Key.of("key0"), "value0")
|
||||
.put(Key.of("key1"), "value1"));
|
||||
subState.put(Key.of("heterogeneousObjectHomogeneousMetadataMap"), objectMap);
|
||||
|
||||
objectMap = new HashMap<>();
|
||||
objectMap.put("meta0", SettableMetadata.of(Version.of(2, 2)).put(Key.of("key0"), "value0"));
|
||||
objectMap.put("meta1", SettableMetadata.of(Version.of(2, 2)).put(Key.of("key1"), "value1"));
|
||||
subState.put(Key.of("homogeneousMetadataMap"), objectMap);
|
||||
|
||||
objectMap = new HashMap<>();
|
||||
objectMap.put("meta0", SettableMetadata.of(Version.of(2, 2)).put(Key.of("key0"), "value0"));
|
||||
objectMap.put("meta1", SettableMetadata.of(Version.of(2, 3)).put(Key.of("key1"), "value1"));
|
||||
subState.put(Key.of("heterogeneousMetadataMap"), objectMap);
|
||||
|
||||
List<Metadata> metadataList = new ArrayList<>();
|
||||
metadataList.add(SettableMetadata.of(Version.of(0, 1)).put(Key.of("key0"), "version 0.1"));
|
||||
metadataList.add(SettableMetadata.of(Version.of(0, 1)).put(Key.of("key0"), "version 0.1")
|
||||
.put(Key.of("key1"), "version 0.1"));
|
||||
subState.put(Key.of("metadataList"), metadataList);
|
||||
metadataList.add(SettableMetadata.of(Version.of(0, 2)).put(Key.of("key2"), "version 0.2"));
|
||||
subState.put(Key.of("heterogeneousMetadataList"), metadataList);
|
||||
|
||||
Set<Metadata> metadataSet = new HashSet<>();
|
||||
metadataSet.add(SettableMetadata.of(Version.of(0, 1)).put(Key.of("key0"), "version 0.1"));
|
||||
metadataSet.add(SettableMetadata.of(Version.of(0, 1)).put(Key.of("key0"), "version 0.1")
|
||||
.put(Key.of("key1"), "version 0.1"));
|
||||
subState.put(Key.of("metadataSet"), metadataSet);
|
||||
metadataSet.add(SettableMetadata.of(Version.of(0, 2)).put(Key.of("key2"), "version 0.2"));
|
||||
subState.put(Key.of("heterogeneousMetadataSet"), metadataSet);
|
||||
|
||||
SettableMetadata homogeneousMetaMetadata = SettableMetadata.of(Version.of(2, 0));
|
||||
homogeneousMetaMetadata.put(Key.of("md0"),
|
||||
SettableMetadata.of(Version.of(2, 0)).put(Key.of("key0"), "value0"));
|
||||
homogeneousMetaMetadata.put(Key.of("md1"),
|
||||
SettableMetadata.of(Version.of(2, 0)).put(Key.of("key0"), 100).put(Key.of("key1"), 101.));
|
||||
// subState.put(Key.of("homogeneousMetaMetadata"), homogeneousMetaMetadata);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
private static SettableMetadata createV3SampleMetadata() {
|
||||
// V3 was a change to the low level format; no difference in the types of objects that could be
|
||||
// supported.
|
||||
return createV2SampleMetadata();
|
||||
}
|
||||
|
||||
private static SettableMetadata createV4SampleMetadata() {
|
||||
SettableMetadata state = createV3SampleMetadata();
|
||||
|
||||
SettableMetadata subState = state.get(SAMPLE_SUB_METADATA_KEY);
|
||||
|
||||
// Starting in V4, possible to serialize proxy objects directly as metadata using newer
|
||||
// capabilities of the InstanceGetter class.
|
||||
TestEnum2 testEnum2Before = TestEnum2.OPTION1;
|
||||
subState.put(Key.of("testEnum2"), testEnum2Before);
|
||||
subState.put(Key.of("testEnum2List"), ImmutableList.of(TestEnum2.OPTION1, TestEnum2.OPTION0));
|
||||
subState.put(Key.of("testEnum2Map"),
|
||||
ImmutableMap.of("enumA", TestEnum2.OPTION1, "enumB", TestEnum2.OPTION0));
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
private static SettableMetadata testSaveAndReloadState(SettableMetadata originalState, File file,
|
||||
Version saveVersion) throws IOException {
|
||||
SettableMetadata originalSubState = originalState.get(SAMPLE_SUB_METADATA_KEY);
|
||||
|
||||
{
|
||||
TestManager stateManager = new TestManager(originalState);
|
||||
TestManager subStateManager = new TestManager(originalSubState);
|
||||
|
||||
GsonSerializer serializer = GsonSerializer.of();
|
||||
serializer.register(SAMPLE_METADATA_KEY, stateManager);
|
||||
serializer.register(SAMPLE_SUB_METADATA_KEY, subStateManager);
|
||||
|
||||
serializer.save(file, saveVersion);
|
||||
}
|
||||
|
||||
{
|
||||
// Blank states with the same keys as the originals.
|
||||
SettableMetadata reloadedState = SettableMetadata.of(SAMPLE_METADATA_VERSION);
|
||||
SettableMetadata reloadedSubState = SettableMetadata.of(SAMPLE_SUB_METADATA_VERSION);
|
||||
|
||||
TestManager stateManager = new TestManager(reloadedState);
|
||||
TestManager subStateManager = new TestManager(reloadedSubState);
|
||||
|
||||
GsonSerializer serializer = GsonSerializer.of();
|
||||
// Go in reverse order here just to test that the order doesn't need to be the same.
|
||||
serializer.register(SAMPLE_SUB_METADATA_KEY, subStateManager);
|
||||
serializer.register(SAMPLE_METADATA_KEY, stateManager);
|
||||
|
||||
serializer.load(file);
|
||||
|
||||
System.out.println("Reloaded " + saveVersion + " state was"
|
||||
+ (originalState.equals(reloadedState) ? " " : " ******* NOT ******* ")
|
||||
+ "found equal to original");
|
||||
|
||||
System.out.println("Reloaded " + saveVersion + " sampleState was"
|
||||
+ (originalSubState.equals(reloadedSubState) ? " " : " ******* NOT ******* ")
|
||||
+ "found equal to original");
|
||||
|
||||
return reloadedState;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
65
src/edu/jhuapl/ses/jsqrl/impl/gson/GsonVersionIO.java
Normal file
65
src/edu/jhuapl/ses/jsqrl/impl/gson/GsonVersionIO.java
Normal file
@@ -0,0 +1,65 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
|
||||
import edu.jhuapl.ses.jsqrl.api.Version;
|
||||
|
||||
final class GsonVersionIO implements JsonSerializer<Version>, JsonDeserializer<Version> {
|
||||
private static final String KEY_ID = DataTypeInfo.VERSION.getTypeId();
|
||||
|
||||
public static JsonPrimitive encode(Version version) {
|
||||
Preconditions.checkNotNull(version);
|
||||
return new JsonPrimitive(version.toString());
|
||||
}
|
||||
|
||||
public static Version decode(JsonPrimitive jsonVersion) {
|
||||
Preconditions.checkNotNull(jsonVersion);
|
||||
|
||||
return Version.of(jsonVersion.getAsString());
|
||||
}
|
||||
|
||||
public static Version decode(JsonObject jsonObject) {
|
||||
Preconditions.checkNotNull(jsonObject);
|
||||
|
||||
JsonElement jsonVersion = jsonObject.get(KEY_ID);
|
||||
Preconditions.checkArgument(jsonVersion.isJsonPrimitive());
|
||||
|
||||
return decode(jsonVersion.getAsJsonPrimitive());
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(Version src, @SuppressWarnings("unused") Type typeOfSrc,
|
||||
@SuppressWarnings("unused") JsonSerializationContext context) {
|
||||
JsonObject result = new JsonObject();
|
||||
result.add(KEY_ID, encode(src));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Version deserialize(JsonElement jsonElement, @SuppressWarnings("unused") Type typeOfT,
|
||||
@SuppressWarnings("unused") JsonDeserializationContext context) {
|
||||
Preconditions.checkNotNull(jsonElement);
|
||||
Preconditions.checkArgument(jsonElement.isJsonObject());
|
||||
|
||||
JsonObject object = jsonElement.getAsJsonObject();
|
||||
|
||||
// Unpack metadata.
|
||||
JsonElement keyIdElement = object.get(KEY_ID);
|
||||
if (keyIdElement == null || !keyIdElement.isJsonPrimitive()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Field \"" + KEY_ID + "\" is missing or has wrong type in Json object");
|
||||
}
|
||||
|
||||
return decode(keyIdElement.getAsJsonPrimitive());
|
||||
}
|
||||
|
||||
}
|
||||
144
src/edu/jhuapl/ses/jsqrl/impl/gson/IterableIOv1.java
Normal file
144
src/edu/jhuapl/ses/jsqrl/impl/gson/IterableIOv1.java
Normal file
@@ -0,0 +1,144 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl.gson;
|
||||
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
abstract class IterableIOv1 implements JsonSerializer<Iterable<?>> {
|
||||
/**
|
||||
* Internal utility class; just here so the unpack method can return all the distinct pieces of
|
||||
* information contained in the input JsonElement.
|
||||
*/
|
||||
protected static class DeserializedJsonArray {
|
||||
protected final DataTypeInfo dataTypeInfo;
|
||||
protected final JsonArray jsonArray;
|
||||
|
||||
protected DeserializedJsonArray(DataTypeInfo dataTypeInfo, JsonArray jsonArray) {
|
||||
this.dataTypeInfo = dataTypeInfo;
|
||||
this.jsonArray = jsonArray;
|
||||
}
|
||||
}
|
||||
|
||||
protected IterableIOv1() {
|
||||
|
||||
}
|
||||
|
||||
private static final String ITERABLE_VALUE_TYPE = "valueType";
|
||||
private static final String ITERABLE_VALUE = "value";
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(Iterable<?> src, @SuppressWarnings("unused") Type typeOfSrc,
|
||||
JsonSerializationContext context) {
|
||||
JsonObject result = new JsonObject();
|
||||
|
||||
// First pass: if any entries are found, determine types of key and value based on the type of
|
||||
// the first non-null element.
|
||||
DataTypeInfo valueInfo = DataTypeInfo.NULL;
|
||||
for (Object value : src) {
|
||||
if (valueInfo == DataTypeInfo.NULL) {
|
||||
valueInfo = DataTypeInfo.forObject(value);
|
||||
}
|
||||
if (valueInfo != DataTypeInfo.NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Second pass: write the collection's entries to a JsonArray.
|
||||
JsonArray destArray = new JsonArray();
|
||||
Type valueType = valueInfo.getType();
|
||||
|
||||
for (Object value : src) {
|
||||
destArray.add(context.serialize(value, valueType));
|
||||
}
|
||||
|
||||
// Put iterable metadata and data into the resultant object.
|
||||
result.add(ITERABLE_VALUE_TYPE, context.serialize(valueInfo.getTypeId()));
|
||||
result.add(ITERABLE_VALUE, destArray);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected DeserializedJsonArray unpack(JsonElement jsonElement) {
|
||||
if (!jsonElement.isJsonObject()) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
JsonObject object = jsonElement.getAsJsonObject();
|
||||
|
||||
// Unpack metadata.
|
||||
JsonElement dataTypeElement = object.get(ITERABLE_VALUE_TYPE);
|
||||
if (dataTypeElement == null || !dataTypeElement.isJsonPrimitive()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Field \"" + ITERABLE_VALUE_TYPE + "\" is missing or has wrong type in Json object");
|
||||
}
|
||||
|
||||
DataTypeInfo dataTypeInfo = DataTypeInfo.of(dataTypeElement.getAsString());
|
||||
|
||||
// Unpack data.
|
||||
JsonElement dataElement = object.get(ITERABLE_VALUE);
|
||||
if (dataElement == null || !dataElement.isJsonArray()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Field \"" + ITERABLE_VALUE + "\" is missing or has wrong type in Json object");
|
||||
}
|
||||
|
||||
return new DeserializedJsonArray(dataTypeInfo, dataElement.getAsJsonArray());
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Set<String> set1 = new HashSet<>();
|
||||
set1.add("One");
|
||||
set1.add(null);
|
||||
|
||||
Set<String> set2 = new HashSet<>();
|
||||
set2.add("Zero");
|
||||
set2.add("Two");
|
||||
|
||||
List<Set<String>> createdList = new ArrayList<>();
|
||||
createdList.add(set1);
|
||||
createdList.add(set2);
|
||||
|
||||
Gson GSON = new GsonBuilder().serializeNulls()
|
||||
.registerTypeAdapter(DataTypeInfo.of(SortedSet.class).getType(), new SortedSetIOv1())
|
||||
.registerTypeAdapter(DataTypeInfo.of(Set.class).getType(), new SetIOv1())
|
||||
.registerTypeAdapter(DataTypeInfo.of(List.class).getType(), new ListIOv1())
|
||||
.setPrettyPrinting().create();
|
||||
|
||||
String testPath = Paths.get(System.getProperty("user.home"), "Downloads").toString();
|
||||
String file = Paths.get(testPath, "test-iterables.json").toString();
|
||||
try (FileWriter fileWriter = new FileWriter(file)) {
|
||||
try (JsonWriter jsonWriter = GSON.newJsonWriter(fileWriter)) {
|
||||
GSON.toJson(createdList, DataTypeInfo.forObject(createdList).getType(), jsonWriter);
|
||||
fileWriter.write('\n');
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
try (JsonReader jsonReader = GSON.newJsonReader(new FileReader(file))) {
|
||||
Iterable<?> readList = GSON.fromJson(jsonReader, DataTypeInfo.of(List.class).getType());
|
||||
if (!readList.equals(createdList)) {
|
||||
System.err.println("OUTPUT IS NOT EQUAL TO INPUT!!");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
217
src/edu/jhuapl/ses/jsqrl/impl/gson/IterableIOv2.java
Normal file
217
src/edu/jhuapl/ses/jsqrl/impl/gson/IterableIOv2.java
Normal file
@@ -0,0 +1,217 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl.gson;
|
||||
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
import edu.jhuapl.ses.jsqrl.api.Key;
|
||||
import edu.jhuapl.ses.jsqrl.api.Metadata;
|
||||
import edu.jhuapl.ses.jsqrl.api.Version;
|
||||
import edu.jhuapl.ses.jsqrl.impl.Utilities;
|
||||
|
||||
abstract class IterableIOv2 implements JsonSerializer<Iterable<?>> {
|
||||
|
||||
/**
|
||||
* Iterate over objects that may include implementations of Metadata and extract the common
|
||||
* Metadata Version, if there is one.
|
||||
*
|
||||
* @param iterable the objects to examine
|
||||
* @return the version that all the metadata share, or null if either there are no Metadata
|
||||
* objects, if the Metadata objects do not share a common version, or if there is only one
|
||||
* Metadata object
|
||||
*/
|
||||
public static Version getCommonVersion(Iterable<?> iterable) {
|
||||
Version result = null;
|
||||
|
||||
int metadataCount = 0;
|
||||
for (Object item : iterable) {
|
||||
if (item instanceof Metadata) {
|
||||
++metadataCount;
|
||||
Version itemVersion = ((Metadata) item).getVersion();
|
||||
|
||||
if (result == null) {
|
||||
// First Metadata found -- provisionally make its Version the result.
|
||||
result = itemVersion;
|
||||
|
||||
} else if (!result.equals(itemVersion)) {
|
||||
// More than one Metadata was found, and it has a different Version from the provisional
|
||||
// result. Discard the provisional result and don't look any further.
|
||||
result = null;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If only one metadata object is present, do not return a "common" version.
|
||||
if (metadataCount == 1) {
|
||||
result = null;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected IterableIOv2() {
|
||||
|
||||
}
|
||||
|
||||
private static final String VALUE_KEY = "value";
|
||||
private static final Key<?> PRIVATE_NULL_KEY = Key.of("PRIVATE NULL KEY");
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(Iterable<?> src, @SuppressWarnings("unused") Type typeOfSrc,
|
||||
JsonSerializationContext context) {
|
||||
|
||||
// First pass: if any entries are found, determine types of key and value based on the type of
|
||||
// the first non-null element.
|
||||
// Note that although iterableTypeInfo and iterableTypeKey are very similar, there are nuances
|
||||
// that lead to the need to treat them slightly differently with respect to how null values are
|
||||
// handled/categorized.
|
||||
DataTypeInfo iterableTypeInfo = DataTypeInfo.NULL; // Meaning an entry is a null pointer.
|
||||
Key<?> iterableTypeKey = null; // Meaning the instance getter could not decode this.
|
||||
boolean sameType = true;
|
||||
for (Object item : src) {
|
||||
DataTypeInfo valueInfo = DataTypeInfo.forObject(item);
|
||||
if (iterableTypeInfo == DataTypeInfo.NULL) {
|
||||
iterableTypeInfo = valueInfo;
|
||||
} else if (valueInfo != DataTypeInfo.NULL && valueInfo != iterableTypeInfo) {
|
||||
sameType = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// See if there is a provider for the type indicated by this key.
|
||||
Key<?> valueTypeKey = Utilities.provideTypeKeyIfPossible(item);
|
||||
if (valueTypeKey == null) {
|
||||
// Use a null object rather than null pointer to distinguish between the cases "no provider"
|
||||
// and "no provider YET".
|
||||
valueTypeKey = PRIVATE_NULL_KEY;
|
||||
}
|
||||
|
||||
if (iterableTypeKey == null) {
|
||||
iterableTypeKey = valueTypeKey;
|
||||
} else if (iterableTypeKey == PRIVATE_NULL_KEY || valueTypeKey == PRIVATE_NULL_KEY) {
|
||||
// Use object equality for comparisons involving the private null key. This is to prevent a
|
||||
// name collision should the user happen to define type key with the same name as the
|
||||
// private null key.
|
||||
if (iterableTypeKey != valueTypeKey) {
|
||||
sameType = false;
|
||||
break;
|
||||
}
|
||||
} else if (!iterableTypeKey.equals(valueTypeKey)) {
|
||||
sameType = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// The private null key is just for use within this method, so replace it with null before
|
||||
// continuing.
|
||||
if (iterableTypeKey == PRIVATE_NULL_KEY) {
|
||||
iterableTypeKey = null;
|
||||
}
|
||||
|
||||
// Extract metadata version, if any.
|
||||
Version commonVersion = getCommonVersion(src);
|
||||
boolean excludeMetadataVersionInValues = commonVersion != null;
|
||||
|
||||
// Second pass: write items, either with or without their types depending on whether they are
|
||||
// the same.
|
||||
JsonArray jsonArray = new JsonArray();
|
||||
for (Object item : src) {
|
||||
JsonElement encodedItem =
|
||||
sameType ? GsonElement.encodeItem(item, excludeMetadataVersionInValues, context)
|
||||
: GsonElement.encodeItemWithType(item, excludeMetadataVersionInValues, context);
|
||||
jsonArray.add(encodedItem);
|
||||
}
|
||||
|
||||
// Put iterable metadata and data into the resultant object.
|
||||
JsonObject result = new JsonObject();
|
||||
if (sameType) {
|
||||
String iterableTypeId =
|
||||
iterableTypeKey != null ? iterableTypeKey.getId() : iterableTypeInfo.getTypeId();
|
||||
GsonElement.encodeTypeInfo(iterableTypeId, result);
|
||||
}
|
||||
if (excludeMetadataVersionInValues) {
|
||||
MetadataIOv2.encodeVersion(commonVersion, result);
|
||||
}
|
||||
result.add(VALUE_KEY, jsonArray);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected List<?> deserialize(JsonObject encodedIterable, JsonDeserializationContext context) {
|
||||
Key<?> typeKey = GsonElement.decodeTypeInfo(encodedIterable);
|
||||
|
||||
Version commonVersion = MetadataIOv2.decodeVersion(encodedIterable);
|
||||
|
||||
JsonArray encodedArray = encodedIterable.get(VALUE_KEY).getAsJsonArray();
|
||||
|
||||
List<Object> result = new ArrayList<>();
|
||||
for (JsonElement encodedItem : encodedArray) {
|
||||
if (typeKey != null) {
|
||||
result.add(GsonElement.decodeItem(encodedItem, typeKey, commonVersion, context));
|
||||
} else {
|
||||
result.add(GsonElement.decodeItem(encodedItem, commonVersion, context));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Set<String> set1 = new HashSet<>();
|
||||
set1.add("One");
|
||||
set1.add(null);
|
||||
|
||||
Set<String> set2 = new HashSet<>();
|
||||
set2.add("Zero");
|
||||
set2.add("Two");
|
||||
|
||||
List<Set<String>> createdList = new ArrayList<>();
|
||||
createdList.add(set1);
|
||||
createdList.add(set2);
|
||||
|
||||
Gson GSON = new GsonBuilder().serializeNulls()
|
||||
.registerTypeAdapter(DataTypeInfo.of(SortedSet.class).getType(), new SortedSetIOv2())
|
||||
.registerTypeAdapter(DataTypeInfo.of(Set.class).getType(), new SetIOv2())
|
||||
.registerTypeAdapter(DataTypeInfo.of(List.class).getType(), new ListIOv2())
|
||||
.setPrettyPrinting().create();
|
||||
|
||||
String testPath = Paths.get(System.getProperty("user.home"), "Downloads").toString();
|
||||
String file = Paths.get(testPath, "test-iterables.json").toString();
|
||||
try (FileWriter fileWriter = new FileWriter(file)) {
|
||||
try (JsonWriter jsonWriter = GSON.newJsonWriter(fileWriter)) {
|
||||
GSON.toJson(createdList, DataTypeInfo.forObject(createdList).getType(), jsonWriter);
|
||||
fileWriter.write('\n');
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
try (JsonReader jsonReader = GSON.newJsonReader(new FileReader(file))) {
|
||||
Iterable<?> readList = GSON.fromJson(jsonReader, DataTypeInfo.of(List.class).getType());
|
||||
if (!readList.equals(createdList)) {
|
||||
System.err.println("OUTPUT IS NOT EQUAL TO INPUT!!");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
9
src/edu/jhuapl/ses/jsqrl/impl/gson/ListIO.java
Normal file
9
src/edu/jhuapl/ses/jsqrl/impl/gson/ListIO.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl.gson;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gson.JsonDeserializer;
|
||||
|
||||
interface ListIO extends JsonDeserializer<List<?>> {
|
||||
|
||||
}
|
||||
35
src/edu/jhuapl/ses/jsqrl/impl/gson/ListIOv1.java
Normal file
35
src/edu/jhuapl/ses/jsqrl/impl/gson/ListIOv1.java
Normal file
@@ -0,0 +1,35 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParseException;
|
||||
|
||||
final class ListIOv1 extends IterableIOv1 implements ListIO {
|
||||
|
||||
ListIOv1() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<?> deserialize(JsonElement jsonElement, @SuppressWarnings("unused") Type typeOfT,
|
||||
JsonDeserializationContext context) throws JsonParseException {
|
||||
DeserializedJsonArray array = unpack(jsonElement);
|
||||
DataTypeInfo dataInfo = array.dataTypeInfo;
|
||||
JsonArray jsonArray = array.jsonArray;
|
||||
|
||||
// Create output data object.
|
||||
List<?> result = new ArrayList<>();
|
||||
|
||||
Type valueType = dataInfo.getType();
|
||||
for (JsonElement entryElement : jsonArray) {
|
||||
result.add(context.deserialize(entryElement, valueType));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
24
src/edu/jhuapl/ses/jsqrl/impl/gson/ListIOv2.java
Normal file
24
src/edu/jhuapl/ses/jsqrl/impl/gson/ListIOv2.java
Normal file
@@ -0,0 +1,24 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
final class ListIOv2 extends IterableIOv2 implements ListIO {
|
||||
|
||||
ListIOv2() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<?> deserialize(JsonElement jsonElement, @SuppressWarnings("unused") Type typeOfT,
|
||||
JsonDeserializationContext context) {
|
||||
Preconditions.checkArgument(jsonElement.isJsonObject());
|
||||
|
||||
return deserialize(jsonElement.getAsJsonObject(), context);
|
||||
}
|
||||
|
||||
}
|
||||
162
src/edu/jhuapl/ses/jsqrl/impl/gson/MapBaseIOv1.java
Normal file
162
src/edu/jhuapl/ses/jsqrl/impl/gson/MapBaseIOv1.java
Normal file
@@ -0,0 +1,162 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl.gson;
|
||||
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonNull;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
abstract class MapBaseIOv1 implements JsonSerializer<Map<?, ?>> {
|
||||
/**
|
||||
* Internal utility class; just here so the unpack method can return all the distinct pieces of
|
||||
* information contained in the input JsonElement.
|
||||
*/
|
||||
protected static class DeserializedJsonObject {
|
||||
protected final DataTypeInfo keyTypeInfo;
|
||||
protected final DataTypeInfo valueTypeInfo;
|
||||
protected final JsonObject jsonMap;
|
||||
|
||||
protected DeserializedJsonObject(DataTypeInfo keyTypeInfo, DataTypeInfo valueTypeInfo,
|
||||
JsonObject jsonMap) {
|
||||
this.keyTypeInfo = keyTypeInfo;
|
||||
this.valueTypeInfo = valueTypeInfo;
|
||||
this.jsonMap = jsonMap;
|
||||
}
|
||||
}
|
||||
|
||||
private static final String MAP_KEY_TYPE = "keyType";
|
||||
private static final String MAP_VALUE_TYPE = "valueType";
|
||||
private static final String MAP_VALUE = "value";
|
||||
|
||||
protected MapBaseIOv1() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(Map<?, ?> src, @SuppressWarnings("unused") Type typeOfSrc,
|
||||
JsonSerializationContext context) {
|
||||
JsonObject result = new JsonObject();
|
||||
|
||||
// First pass: if any entries are found, determine types of key and value.
|
||||
DataTypeInfo keyInfo = DataTypeInfo.NULL;
|
||||
DataTypeInfo valueInfo = DataTypeInfo.NULL;
|
||||
for (Entry<?, ?> entry : src.entrySet()) {
|
||||
if (keyInfo == DataTypeInfo.NULL) {
|
||||
keyInfo = DataTypeInfo.forObject(entry.getKey());
|
||||
}
|
||||
if (valueInfo == DataTypeInfo.NULL) {
|
||||
valueInfo = DataTypeInfo.forObject(entry.getValue());
|
||||
}
|
||||
if (keyInfo != DataTypeInfo.NULL && valueInfo != DataTypeInfo.NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Second pass: write the map entries to a JsonObject.
|
||||
JsonObject dest = new JsonObject();
|
||||
Type valueType = valueInfo.getType();
|
||||
|
||||
for (Entry<?, ?> entry : src.entrySet()) {
|
||||
Object key = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
dest.add(key != null ? key.toString() : JsonNull.INSTANCE.toString(),
|
||||
context.serialize(value, valueType));
|
||||
}
|
||||
|
||||
// Put type information about key and value, along with the map entries
|
||||
// into the resultant object.
|
||||
result.add(MAP_KEY_TYPE, context.serialize(keyInfo.getTypeId()));
|
||||
result.add(MAP_VALUE_TYPE, context.serialize(valueInfo.getTypeId()));
|
||||
result.add(MAP_VALUE, dest);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public DeserializedJsonObject unpack(JsonElement jsonElement) {
|
||||
if (!jsonElement.isJsonObject()) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
JsonObject object = jsonElement.getAsJsonObject();
|
||||
|
||||
// Unpack metadata.
|
||||
JsonElement keyTypeElement = object.get(MAP_KEY_TYPE);
|
||||
if (keyTypeElement == null || !keyTypeElement.isJsonPrimitive()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Field \"" + MAP_KEY_TYPE + "\" is missing or has wrong type in Json object");
|
||||
}
|
||||
|
||||
JsonElement valueTypeElement = object.get(MAP_VALUE_TYPE);
|
||||
if (valueTypeElement == null || !valueTypeElement.isJsonPrimitive()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Field \"" + MAP_VALUE_TYPE + "\" is missing or has wrong type in Json object");
|
||||
}
|
||||
|
||||
DataTypeInfo keyInfo = DataTypeInfo.of(keyTypeElement.getAsString());
|
||||
DataTypeInfo valueInfo = DataTypeInfo.of(valueTypeElement.getAsString());
|
||||
|
||||
// Unpack data.
|
||||
JsonElement dataElement = object.get(MAP_VALUE);
|
||||
if (dataElement == null || !dataElement.isJsonObject()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Field \"" + MAP_VALUE + "\" is missing or has wrong type in Json object");
|
||||
}
|
||||
|
||||
return new DeserializedJsonObject(keyInfo, valueInfo, dataElement.getAsJsonObject());
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Map<Integer, String> map1 = new HashMap<>();
|
||||
map1.put(1, "One");
|
||||
map1.put(null, "Null");
|
||||
|
||||
Map<Integer, String> map2 = new HashMap<>();
|
||||
map2.put(0, "Zero");
|
||||
map2.put(2, null);
|
||||
|
||||
SortedMap<String, Map<Integer, String>> createdMap = new TreeMap<>();
|
||||
createdMap.put("Map one", map1);
|
||||
createdMap.put("Map two", map2);
|
||||
|
||||
Gson GSON = new GsonBuilder().serializeNulls()
|
||||
.registerTypeAdapter(DataTypeInfo.of(SortedMap.class).getType(), new SortedMapIOv1())
|
||||
.registerTypeAdapter(DataTypeInfo.of(Map.class).getType(), new MapIOv1())
|
||||
.setPrettyPrinting().create();
|
||||
|
||||
String testPath = Paths.get(System.getProperty("user.home"), "Downloads").toString();
|
||||
String file = Paths.get(testPath, "test-map.json").toString();
|
||||
try (FileWriter fileWriter = new FileWriter(file)) {
|
||||
try (JsonWriter jsonWriter = GSON.newJsonWriter(fileWriter)) {
|
||||
GSON.toJson(createdMap, DataTypeInfo.forObject(createdMap).getType(), jsonWriter);
|
||||
fileWriter.write('\n');
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
try (JsonReader jsonReader = GSON.newJsonReader(new FileReader(file))) {
|
||||
Map<?, ?> readMap = GSON.fromJson(jsonReader, DataTypeInfo.of(Map.class).getType());
|
||||
if (!readMap.equals(createdMap)) {
|
||||
System.err.println("OUTPUT IS NOT EQUAL TO INPUT!!");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
207
src/edu/jhuapl/ses/jsqrl/impl/gson/MapBaseIOv2.java
Normal file
207
src/edu/jhuapl/ses/jsqrl/impl/gson/MapBaseIOv2.java
Normal file
@@ -0,0 +1,207 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl.gson;
|
||||
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonNull;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
import edu.jhuapl.ses.jsqrl.api.Key;
|
||||
import edu.jhuapl.ses.jsqrl.api.Version;
|
||||
import edu.jhuapl.ses.jsqrl.impl.Utilities;
|
||||
|
||||
abstract class MapBaseIOv2 implements JsonSerializer<Map<?, ?>> {
|
||||
|
||||
protected static Object decodeKeyString(String keyString, DataTypeInfo typeInfo,
|
||||
JsonDeserializationContext context) {
|
||||
JsonElement keyElement =
|
||||
keyString.equals("null") ? JsonNull.INSTANCE : new JsonPrimitive(keyString);
|
||||
return context.deserialize(keyElement, typeInfo.getType());
|
||||
}
|
||||
|
||||
static final String KEY_TYPE_KEY = "keyType";
|
||||
static final String VALUE_KEY = "value";
|
||||
private static final Key<?> PRIVATE_NULL_KEY = Key.of("PRIVATE NULL KEY");
|
||||
|
||||
protected MapBaseIOv2() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(Map<?, ?> src, @SuppressWarnings("unused") Type typeOfSrc,
|
||||
JsonSerializationContext context) {
|
||||
Preconditions.checkNotNull(src);
|
||||
Preconditions.checkNotNull(context);
|
||||
|
||||
Set<?> keys = src.keySet();
|
||||
|
||||
// First pass: if any entries are found, determine types of key and value.
|
||||
List<Object> values = new ArrayList<>();
|
||||
DataTypeInfo mapKeyInfo = DataTypeInfo.NULL;
|
||||
// Note that although mapValueInfo and mapValueTypeKey are very similar, there are nuances
|
||||
// that lead to the need to treat them slightly differently with respect to how null values are
|
||||
// handled/categorized.
|
||||
DataTypeInfo mapValueInfo = DataTypeInfo.NULL; // Meaning a value is a null pointer.
|
||||
Key<?> mapValueTypeKey = null; // Meaning the instance getter could not decode this.
|
||||
boolean sameValueType = keys.size() > 1;
|
||||
|
||||
for (Object key : keys) {
|
||||
DataTypeInfo keyInfo = DataTypeInfo.forObject(key);
|
||||
Object value = src.get(key);
|
||||
values.add(value);
|
||||
|
||||
if (mapKeyInfo == DataTypeInfo.NULL) {
|
||||
mapKeyInfo = keyInfo;
|
||||
} else if (keyInfo != DataTypeInfo.NULL && keyInfo != mapKeyInfo) {
|
||||
// This could be supported if anyone ever needs it.
|
||||
throw new IllegalStateException("Cannot store a key of type " + keyInfo.getTypeId()
|
||||
+ " in a map inferred to have keys of type " + mapKeyInfo.getTypeId());
|
||||
}
|
||||
|
||||
DataTypeInfo valueInfo = DataTypeInfo.forObject(value);
|
||||
if (mapValueInfo == DataTypeInfo.NULL) {
|
||||
mapValueInfo = valueInfo;
|
||||
} else if (valueInfo != DataTypeInfo.NULL && valueInfo != mapValueInfo) {
|
||||
sameValueType = false;
|
||||
}
|
||||
|
||||
// See if there is a provider for the type indicated by this key.
|
||||
Key<?> valueTypeKey = Utilities.provideTypeKeyIfPossible(value);
|
||||
if (valueTypeKey == null) {
|
||||
// Use a null object rather than null pointer to distinguish between the cases "no provider"
|
||||
// and "no provider YET".
|
||||
valueTypeKey = PRIVATE_NULL_KEY;
|
||||
}
|
||||
|
||||
if (mapValueTypeKey == null) {
|
||||
mapValueTypeKey = valueTypeKey;
|
||||
} else if (mapValueTypeKey == PRIVATE_NULL_KEY || valueTypeKey == PRIVATE_NULL_KEY) {
|
||||
// Use object equality for comparisons involving the private null key. This is to prevent a
|
||||
// name collision should the user happen to define type key with the same name as the
|
||||
// private null key.
|
||||
if (mapValueTypeKey != valueTypeKey) {
|
||||
sameValueType = false;
|
||||
break;
|
||||
}
|
||||
} else if (!mapValueTypeKey.equals(valueTypeKey)) {
|
||||
sameValueType = false;
|
||||
}
|
||||
}
|
||||
|
||||
// The private null key is just for use within this method, so replace it with null before
|
||||
// continuing.
|
||||
if (mapValueTypeKey == PRIVATE_NULL_KEY) {
|
||||
mapValueTypeKey = null;
|
||||
}
|
||||
|
||||
// Extract metadata version, if any.
|
||||
Version commonVersion = IterableIOv2.getCommonVersion(values);
|
||||
boolean excludeMetadataVersionInValues = commonVersion != null;
|
||||
|
||||
// Second pass: write the map entries to a JsonObject.
|
||||
JsonObject encodedMap = new JsonObject();
|
||||
for (Object metadataKey : keys) {
|
||||
Object key = metadataKey != null ? metadataKey : JsonNull.INSTANCE;
|
||||
Object value = src.get(metadataKey);
|
||||
|
||||
JsonElement encodedValue =
|
||||
sameValueType ? GsonElement.encodeItem(value, excludeMetadataVersionInValues, context)
|
||||
: GsonElement.encodeItemWithType(value, excludeMetadataVersionInValues, context);
|
||||
|
||||
encodedMap.add(key.toString(), encodedValue);
|
||||
}
|
||||
|
||||
// Put type information about key and value, along with the map entries
|
||||
// into the resultant object.
|
||||
JsonObject result = new JsonObject();
|
||||
result.addProperty(KEY_TYPE_KEY, mapKeyInfo.getTypeId());
|
||||
if (sameValueType) {
|
||||
String mapValueTypeId =
|
||||
mapValueTypeKey != null ? mapValueTypeKey.getId() : mapValueInfo.getTypeId();
|
||||
GsonElement.encodeTypeInfo(mapValueTypeId, result);
|
||||
}
|
||||
if (excludeMetadataVersionInValues) {
|
||||
MetadataIOv2.encodeVersion(commonVersion, result);
|
||||
}
|
||||
result.add(VALUE_KEY, encodedMap);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void deserialize(JsonObject encodedItem, JsonDeserializationContext context,
|
||||
Map<Object, Object> map) {
|
||||
DataTypeInfo mapKeyInfo = DataTypeInfo.of(encodedItem.get(KEY_TYPE_KEY).getAsString());
|
||||
Key<?> mapValueType = GsonElement.decodeTypeInfo(encodedItem);
|
||||
Version commonVersion = MetadataIOv2.decodeVersion(encodedItem);
|
||||
JsonObject encodedMap = encodedItem.get(VALUE_KEY).getAsJsonObject();
|
||||
|
||||
for (Entry<String, JsonElement> entry : encodedMap.entrySet()) {
|
||||
Object key = decodeKeyString(entry.getKey(), mapKeyInfo, context);
|
||||
Object value = mapValueType != null
|
||||
? GsonElement.decodeItem(entry.getValue(), mapValueType, commonVersion, context)
|
||||
: GsonElement.decodeItem(entry.getValue(), commonVersion, context);
|
||||
map.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Map<Integer, String> map1 = new HashMap<>();
|
||||
map1.put(1, "One");
|
||||
map1.put(null, "Null");
|
||||
|
||||
Map<Integer, String> map2 = new HashMap<>();
|
||||
map2.put(0, "Zero");
|
||||
map2.put(2, null);
|
||||
|
||||
SortedMap<String, Map<Integer, String>> createdMap = new TreeMap<>();
|
||||
createdMap.put("Map one", map1);
|
||||
createdMap.put("Map two", map2);
|
||||
|
||||
Gson GSON = new GsonBuilder().serializeNulls()
|
||||
.registerTypeAdapter(DataTypeInfo.of(SortedMap.class).getType(), new SortedMapIOv2())
|
||||
.registerTypeAdapter(DataTypeInfo.of(Map.class).getType(), new MapIOv2())
|
||||
.setPrettyPrinting().create();
|
||||
|
||||
String testPath = Paths.get(System.getProperty("user.home"), "Downloads").toString();
|
||||
String file = Paths.get(testPath, "test-map.json").toString();
|
||||
try (FileWriter fileWriter = new FileWriter(file)) {
|
||||
try (JsonWriter jsonWriter = GSON.newJsonWriter(fileWriter)) {
|
||||
GSON.toJson(createdMap, DataTypeInfo.forObject(createdMap).getType(), jsonWriter);
|
||||
fileWriter.write('\n');
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
try (JsonReader jsonReader = GSON.newJsonReader(new FileReader(file))) {
|
||||
Map<?, ?> readMap = GSON.fromJson(jsonReader, DataTypeInfo.of(Map.class).getType());
|
||||
if (!readMap.equals(createdMap)) {
|
||||
System.err.println("OUTPUT IS NOT EQUAL TO INPUT!!");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
16
src/edu/jhuapl/ses/jsqrl/impl/gson/MapIO.java
Normal file
16
src/edu/jhuapl/ses/jsqrl/impl/gson/MapIO.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
|
||||
interface MapIO extends JsonDeserializer<Map<?, ?>> {
|
||||
|
||||
@Override
|
||||
Map<?, ?> deserialize(JsonElement jsonElement, Type typeOfT, JsonDeserializationContext context);
|
||||
|
||||
}
|
||||
37
src/edu/jhuapl/ses/jsqrl/impl/gson/MapIOv1.java
Normal file
37
src/edu/jhuapl/ses/jsqrl/impl/gson/MapIOv1.java
Normal file
@@ -0,0 +1,37 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonNull;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
|
||||
final class MapIOv1 extends MapBaseIOv1 implements MapIO {
|
||||
@Override
|
||||
public Map<?, ?> deserialize(JsonElement jsonElement, @SuppressWarnings("unused") Type typeOfT,
|
||||
JsonDeserializationContext context) throws JsonParseException {
|
||||
Map<?, ?> result = new HashMap<>();
|
||||
|
||||
DeserializedJsonObject object = unpack(jsonElement);
|
||||
Type keyType = object.keyTypeInfo.getType();
|
||||
Type valueType = object.valueTypeInfo.getType();
|
||||
|
||||
for (Entry<String, JsonElement> entry : object.jsonMap.getAsJsonObject().entrySet()) {
|
||||
String keyString = entry.getKey();
|
||||
JsonElement keyElement =
|
||||
keyString.equals("null") ? JsonNull.INSTANCE : new JsonPrimitive(keyString);
|
||||
JsonElement valueElement = entry.getValue();
|
||||
|
||||
result.put(context.deserialize(keyElement, keyType),
|
||||
context.deserialize(valueElement, valueType));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
25
src/edu/jhuapl/ses/jsqrl/impl/gson/MapIOv2.java
Normal file
25
src/edu/jhuapl/ses/jsqrl/impl/gson/MapIOv2.java
Normal file
@@ -0,0 +1,25 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
final class MapIOv2 extends MapBaseIOv2 implements MapIO {
|
||||
|
||||
@Override
|
||||
public Map<?, ?> deserialize(JsonElement jsonElement, @SuppressWarnings("unused") Type typeOfT,
|
||||
JsonDeserializationContext context) {
|
||||
|
||||
Preconditions.checkArgument(jsonElement.isJsonObject());
|
||||
|
||||
Map<Object, Object> result = new LinkedHashMap<>();
|
||||
deserialize(jsonElement.getAsJsonObject(), context, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
10
src/edu/jhuapl/ses/jsqrl/impl/gson/MetadataIO.java
Normal file
10
src/edu/jhuapl/ses/jsqrl/impl/gson/MetadataIO.java
Normal file
@@ -0,0 +1,10 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl.gson;
|
||||
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonSerializer;
|
||||
|
||||
import edu.jhuapl.ses.jsqrl.api.Metadata;
|
||||
|
||||
interface MetadataIO extends JsonSerializer<Metadata>, JsonDeserializer<Metadata> {
|
||||
|
||||
}
|
||||
75
src/edu/jhuapl/ses/jsqrl/impl/gson/MetadataIOv1.java
Normal file
75
src/edu/jhuapl/ses/jsqrl/impl/gson/MetadataIOv1.java
Normal file
@@ -0,0 +1,75 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
|
||||
import edu.jhuapl.ses.jsqrl.api.Key;
|
||||
import edu.jhuapl.ses.jsqrl.api.Metadata;
|
||||
import edu.jhuapl.ses.jsqrl.api.Version;
|
||||
import edu.jhuapl.ses.jsqrl.impl.SettableMetadata;
|
||||
|
||||
final class MetadataIOv1 implements MetadataIO {
|
||||
@Override
|
||||
public JsonElement serialize(Metadata src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
Preconditions.checkNotNull(src);
|
||||
Preconditions.checkArgument(DataTypeInfo.METADATA.getType().equals(typeOfSrc));
|
||||
Preconditions.checkNotNull(context);
|
||||
|
||||
JsonArray array = new JsonArray();
|
||||
array.add(context.serialize(src.getVersion(), DataTypeInfo.VERSION.getType()));
|
||||
|
||||
JsonObject jsonMetadata = new JsonObject();
|
||||
for (Key<?> key : src.getKeys()) {
|
||||
Object value = src.get(key);
|
||||
jsonMetadata.add(key.getId(),
|
||||
context.serialize(GsonElement.of(value), DataTypeInfo.ELEMENT.getType()));
|
||||
}
|
||||
|
||||
array.add(jsonMetadata);
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Metadata deserialize(JsonElement jsonSrc, Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
Preconditions.checkNotNull(jsonSrc);
|
||||
Preconditions.checkArgument(jsonSrc.isJsonArray());
|
||||
Preconditions.checkArgument(DataTypeInfo.METADATA.getType().equals(typeOfT));
|
||||
Preconditions.checkNotNull(context);
|
||||
|
||||
JsonArray jsonArray = jsonSrc.getAsJsonArray();
|
||||
JsonElement jsonElement = null;
|
||||
Iterator<JsonElement> iterator = jsonArray.iterator();
|
||||
|
||||
if (!iterator.hasNext()) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
jsonElement = iterator.next();
|
||||
|
||||
Version version = context.deserialize(jsonElement, DataTypeInfo.VERSION.getType());
|
||||
|
||||
final SettableMetadata metadata = SettableMetadata.of(version);
|
||||
if (!iterator.hasNext()) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
jsonElement = iterator.next();
|
||||
JsonObject jsonMetadata = jsonElement.getAsJsonObject();
|
||||
for (Entry<String, JsonElement> entry : jsonMetadata.entrySet()) {
|
||||
Key<Object> key = Key.of(entry.getKey());
|
||||
GsonElement element = context.deserialize(entry.getValue(), DataTypeInfo.ELEMENT.getType());
|
||||
metadata.put(key, element.getValue());
|
||||
}
|
||||
return metadata;
|
||||
}
|
||||
|
||||
}
|
||||
159
src/edu/jhuapl/ses/jsqrl/impl/gson/MetadataIOv2.java
Normal file
159
src/edu/jhuapl/ses/jsqrl/impl/gson/MetadataIOv2.java
Normal file
@@ -0,0 +1,159 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
|
||||
import edu.jhuapl.ses.jsqrl.api.Key;
|
||||
import edu.jhuapl.ses.jsqrl.api.Metadata;
|
||||
import edu.jhuapl.ses.jsqrl.api.Version;
|
||||
import edu.jhuapl.ses.jsqrl.impl.SettableMetadata;
|
||||
|
||||
final class MetadataIOv2 implements MetadataIO {
|
||||
|
||||
private static final String VERSION_KEY = "metadata.Version";
|
||||
|
||||
public static JsonObject encodeWithoutVersion(Metadata src, JsonSerializationContext context) {
|
||||
JsonObject result = encodeWithVersion(src, context);
|
||||
|
||||
result.remove(DataTypeInfo.VERSION.getTypeId());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static JsonObject encodeWithVersion(Metadata src, JsonSerializationContext context) {
|
||||
Map<String, Object> map = new LinkedHashMap<>();
|
||||
for (Key<?> key : src.getKeys()) {
|
||||
map.put(key.getId(), src.get(key));
|
||||
}
|
||||
|
||||
// Use MapIO to do the detailed encoding.
|
||||
MapIOv2 mapIo = new MapIOv2();
|
||||
JsonObject encodedMap =
|
||||
mapIo.serialize(map, DataTypeInfo.MAP.getType(), context).getAsJsonObject();
|
||||
|
||||
// Pull out info needed to characterize the Metadata. (Skip the Key type -- known to be string).
|
||||
JsonObject result = new JsonObject();
|
||||
result.add(DataTypeInfo.VERSION.getTypeId(), GsonVersionIO.encode(src.getVersion()));
|
||||
if (encodedMap.has(GsonElement.VALUE_TYPE_KEY)) {
|
||||
result.add(GsonElement.VALUE_TYPE_KEY, encodedMap.get(GsonElement.VALUE_TYPE_KEY));
|
||||
}
|
||||
if (encodedMap.has(VERSION_KEY)) {
|
||||
result.add(VERSION_KEY, encodedMap.get(VERSION_KEY));
|
||||
}
|
||||
|
||||
// Rebundle the serialized map so it's stored in the same order as the metadata.
|
||||
JsonObject keyValueObject = encodedMap.get(MapBaseIOv2.VALUE_KEY).getAsJsonObject();
|
||||
JsonObject keyValueObjectInOrder = new JsonObject();
|
||||
for (Key<?> key : src.getKeys()) {
|
||||
String keyId = key.getId();
|
||||
keyValueObjectInOrder.add(keyId, keyValueObject.get(keyId));
|
||||
}
|
||||
|
||||
result.add(MapBaseIOv2.VALUE_KEY, keyValueObjectInOrder);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void encodeVersion(Version version, JsonObject object) {
|
||||
object.add(VERSION_KEY, GsonVersionIO.encode(version));
|
||||
}
|
||||
|
||||
public static Metadata decode(JsonObject jsonMetadata, Version version,
|
||||
JsonDeserializationContext context) {
|
||||
Preconditions.checkNotNull(jsonMetadata);
|
||||
Preconditions.checkNotNull(version);
|
||||
Preconditions.checkNotNull(context);
|
||||
|
||||
// Reverse the encoding process. The ordered map is stored as the "value".
|
||||
JsonObject keyValueObjectInOrder = jsonMetadata.get(MapBaseIOv2.VALUE_KEY).getAsJsonObject();
|
||||
|
||||
// Convert the supplied jsonMetadata object into the same format as an encoded map.
|
||||
JsonObject encodedMap = new JsonObject();
|
||||
// Note the key type was not serialized but we need to add it here.
|
||||
encodedMap.addProperty(MapBaseIOv2.KEY_TYPE_KEY, DataTypeInfo.STRING.getTypeId());
|
||||
if (jsonMetadata.has(GsonElement.VALUE_TYPE_KEY)) {
|
||||
encodedMap.add(GsonElement.VALUE_TYPE_KEY, jsonMetadata.get(GsonElement.VALUE_TYPE_KEY));
|
||||
}
|
||||
if (jsonMetadata.has(VERSION_KEY)) {
|
||||
encodedMap.add(VERSION_KEY, jsonMetadata.get(VERSION_KEY));
|
||||
}
|
||||
encodedMap.add(MapBaseIOv2.VALUE_KEY, keyValueObjectInOrder);
|
||||
|
||||
// Now decode the synthesized encoded map.
|
||||
MapIOv2 mapIo = new MapIOv2();
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> map =
|
||||
(Map<String, Object>) mapIo.deserialize(encodedMap, DataTypeInfo.MAP.getType(), context);
|
||||
|
||||
// Finally use the key order from the serialized form to reconstruct the metadata object content
|
||||
// in order.
|
||||
SettableMetadata metadata = SettableMetadata.of(version);
|
||||
for (Entry<String, JsonElement> entry : keyValueObjectInOrder.entrySet()) {
|
||||
String keyId = entry.getKey();
|
||||
// Pull the reconstructed elements of the metadata from the map.
|
||||
metadata.put(Key.of(keyId), map.get(keyId));
|
||||
}
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
public static Metadata decodeWithVersion(JsonObject jsonMetadata,
|
||||
JsonDeserializationContext context) {
|
||||
Preconditions.checkNotNull(jsonMetadata);
|
||||
|
||||
Version version = decodeVersion(jsonMetadata);
|
||||
|
||||
return decode(jsonMetadata, version, context);
|
||||
}
|
||||
|
||||
public static Version decodeVersion(JsonObject object) {
|
||||
Version result = null;
|
||||
|
||||
if (object.has(VERSION_KEY)) {
|
||||
result = GsonVersionIO.decode(object.get(VERSION_KEY).getAsJsonPrimitive());
|
||||
} else if (object.has(DataTypeInfo.VERSION.getTypeId())) {
|
||||
result =
|
||||
GsonVersionIO.decode(object.get(DataTypeInfo.VERSION.getTypeId()).getAsJsonPrimitive());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* edu.jhuapl.ses.jsqrl.impl.gson.MetadataIO#serialize(edu.jhuapl.ses.jsqrl.api.Metadata,
|
||||
* java.lang.reflect.Type, com.google.gson.JsonSerializationContext)
|
||||
*/
|
||||
@Override
|
||||
public JsonElement serialize(Metadata src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
Preconditions.checkArgument(DataTypeInfo.METADATA.getType().equals(typeOfSrc));
|
||||
return encodeWithVersion(src, context);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see edu.jhuapl.ses.jsqrl.impl.gson.MetadataIO#deserialize(com.google.gson.JsonElement,
|
||||
* java.lang.reflect.Type, com.google.gson.JsonDeserializationContext)
|
||||
*/
|
||||
@Override
|
||||
public Metadata deserialize(JsonElement jsonSrc, Type typeOfT,
|
||||
JsonDeserializationContext context) {
|
||||
Preconditions.checkNotNull(jsonSrc);
|
||||
Preconditions.checkArgument(jsonSrc.isJsonObject());
|
||||
Preconditions.checkArgument(DataTypeInfo.METADATA.getType().equals(typeOfT));
|
||||
|
||||
return decodeWithVersion(jsonSrc.getAsJsonObject(), context);
|
||||
}
|
||||
|
||||
}
|
||||
8
src/edu/jhuapl/ses/jsqrl/impl/gson/ProxyIO.java
Normal file
8
src/edu/jhuapl/ses/jsqrl/impl/gson/ProxyIO.java
Normal file
@@ -0,0 +1,8 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl.gson;
|
||||
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonSerializer;
|
||||
|
||||
interface ProxyIO<T> extends JsonSerializer<Object>, JsonDeserializer<T> {
|
||||
|
||||
}
|
||||
57
src/edu/jhuapl/ses/jsqrl/impl/gson/ProxyIOv1.java
Normal file
57
src/edu/jhuapl/ses/jsqrl/impl/gson/ProxyIOv1.java
Normal file
@@ -0,0 +1,57 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
|
||||
import edu.jhuapl.ses.jsqrl.api.Key;
|
||||
import edu.jhuapl.ses.jsqrl.api.Metadata;
|
||||
import edu.jhuapl.ses.jsqrl.api.StorableAsMetadata;
|
||||
import edu.jhuapl.ses.jsqrl.impl.InstanceGetter;
|
||||
|
||||
final class ProxyIOv1<T> implements ProxyIO<T> {
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(Object src, @SuppressWarnings("unused") Type typeOfSrc,
|
||||
JsonSerializationContext context) {
|
||||
JsonObject object = new JsonObject();
|
||||
|
||||
Key<?> key;
|
||||
Metadata metadata;
|
||||
if (src instanceof StorableAsMetadata) {
|
||||
StorableAsMetadata<?> storable = (StorableAsMetadata<?>) src;
|
||||
|
||||
key = storable.getKey();
|
||||
metadata = storable.store();
|
||||
} else {
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<Object> objectType = (Class<Object>) src.getClass();
|
||||
InstanceGetter instanceGetter = InstanceGetter.defaultInstanceGetter();
|
||||
|
||||
key = instanceGetter.getKeyForType(objectType);
|
||||
metadata = instanceGetter.providesMetadataFromGenericObject(objectType).provide(src);
|
||||
}
|
||||
|
||||
object.addProperty("proxiedType", key.getId());
|
||||
object.add("proxyMetadata", context.serialize(metadata, DataTypeInfo.METADATA.getType()));
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T deserialize(JsonElement json, @SuppressWarnings("unused") Type typeOfT,
|
||||
JsonDeserializationContext context) throws JsonParseException {
|
||||
JsonObject object = json.getAsJsonObject();
|
||||
Key<T> proxyKey = Key.of(object.get("proxiedType").getAsString());
|
||||
Metadata objectMetadata =
|
||||
context.deserialize(object.get("proxyMetadata"), DataTypeInfo.METADATA.getType());
|
||||
|
||||
return InstanceGetter.defaultInstanceGetter().providesGenericObjectFromMetadata(proxyKey)
|
||||
.provide(objectMetadata);
|
||||
}
|
||||
|
||||
}
|
||||
57
src/edu/jhuapl/ses/jsqrl/impl/gson/ProxyIOv2.java
Normal file
57
src/edu/jhuapl/ses/jsqrl/impl/gson/ProxyIOv2.java
Normal file
@@ -0,0 +1,57 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
|
||||
import edu.jhuapl.ses.jsqrl.api.Key;
|
||||
import edu.jhuapl.ses.jsqrl.api.Metadata;
|
||||
import edu.jhuapl.ses.jsqrl.api.StorableAsMetadata;
|
||||
import edu.jhuapl.ses.jsqrl.impl.InstanceGetter;
|
||||
|
||||
final class ProxyIOv2<T> implements ProxyIO<T> {
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(Object src, @SuppressWarnings("unused") Type typeOfSrc,
|
||||
JsonSerializationContext context) {
|
||||
JsonObject object = new JsonObject();
|
||||
|
||||
Key<?> key;
|
||||
Metadata metadata;
|
||||
if (src instanceof StorableAsMetadata) {
|
||||
StorableAsMetadata<?> storable = (StorableAsMetadata<?>) src;
|
||||
|
||||
key = storable.getKey();
|
||||
metadata = storable.store();
|
||||
} else {
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<Object> objectType = (Class<Object>) src.getClass();
|
||||
InstanceGetter instanceGetter = InstanceGetter.defaultInstanceGetter();
|
||||
|
||||
key = instanceGetter.getKeyForType(objectType);
|
||||
metadata = instanceGetter.providesMetadataFromGenericObject(objectType).provide(src);
|
||||
}
|
||||
|
||||
object.addProperty("proxiedType", key.getId());
|
||||
object.add("proxyMetadata", context.serialize(metadata, DataTypeInfo.METADATA.getType()));
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T deserialize(JsonElement json, @SuppressWarnings("unused") Type typeOfT,
|
||||
JsonDeserializationContext context) throws JsonParseException {
|
||||
JsonObject object = json.getAsJsonObject();
|
||||
Key<T> proxyKey = Key.of(object.get("proxiedType").getAsString());
|
||||
Metadata objectMetadata =
|
||||
context.deserialize(object.get("proxyMetadata"), DataTypeInfo.METADATA.getType());
|
||||
|
||||
return InstanceGetter.defaultInstanceGetter().providesGenericObjectFromMetadata(proxyKey)
|
||||
.provide(objectMetadata);
|
||||
}
|
||||
|
||||
}
|
||||
66
src/edu/jhuapl/ses/jsqrl/impl/gson/SerializableIO.java
Normal file
66
src/edu/jhuapl/ses/jsqrl/impl/gson/SerializableIO.java
Normal file
@@ -0,0 +1,66 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl.gson;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Base64;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonNull;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
|
||||
public class SerializableIO
|
||||
implements JsonSerializer<Serializable>, JsonDeserializer<Serializable> {
|
||||
|
||||
public SerializableIO() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(Serializable src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
String encodedString;
|
||||
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
|
||||
try (ObjectOutputStream oos =
|
||||
new ObjectOutputStream(/* new GZIPOutputStream( */new GZIPOutputStream(baos))) {
|
||||
oos.writeObject(src);
|
||||
}
|
||||
encodedString = Base64.getEncoder().encodeToString(baos.toByteArray());
|
||||
} catch (Exception e) {
|
||||
encodedString = null;
|
||||
}
|
||||
|
||||
return encodedString != null ? new JsonPrimitive(encodedString) : JsonNull.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Serializable deserialize(JsonElement jsonElement, Type typeOfT,
|
||||
JsonDeserializationContext context) throws JsonParseException {
|
||||
Preconditions.checkArgument(jsonElement.isJsonPrimitive());
|
||||
|
||||
String encodedString = jsonElement.getAsString();
|
||||
|
||||
byte[] data = Base64.getDecoder().decode(encodedString);
|
||||
|
||||
Serializable serializable;
|
||||
try (ObjectInputStream ois =
|
||||
new ObjectInputStream(new GZIPInputStream(new ByteArrayInputStream(data)))) {
|
||||
serializable = (Serializable) ois.readObject();
|
||||
} catch (Exception e) {
|
||||
serializable = null;
|
||||
}
|
||||
|
||||
|
||||
return serializable;
|
||||
}
|
||||
|
||||
}
|
||||
102
src/edu/jhuapl/ses/jsqrl/impl/gson/Serializers.java
Normal file
102
src/edu/jhuapl/ses/jsqrl/impl/gson/Serializers.java
Normal file
@@ -0,0 +1,102 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl.gson;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import edu.jhuapl.ses.jsqrl.api.Key;
|
||||
import edu.jhuapl.ses.jsqrl.api.Metadata;
|
||||
import edu.jhuapl.ses.jsqrl.api.MetadataManager;
|
||||
import edu.jhuapl.ses.jsqrl.api.Serializer;
|
||||
import edu.jhuapl.ses.jsqrl.api.Version;
|
||||
import edu.jhuapl.ses.jsqrl.impl.FixedMetadata;
|
||||
import edu.jhuapl.ses.jsqrl.impl.SettableMetadata;
|
||||
import edu.jhuapl.ses.jsqrl.impl.gson.GsonSerializer;
|
||||
|
||||
public class Serializers {
|
||||
private static final Serializer INSTANCE = GsonSerializer.of();
|
||||
|
||||
public static Serializer getDefault() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public static Serializer of() {
|
||||
return GsonSerializer.of();
|
||||
}
|
||||
|
||||
public static void serialize(String metadataId, MetadataManager manager, File file)
|
||||
throws IOException {
|
||||
Preconditions.checkNotNull(metadataId);
|
||||
Preconditions.checkNotNull(manager);
|
||||
Preconditions.checkNotNull(file);
|
||||
|
||||
Serializer serializer = of();
|
||||
serializer.register(Key.of(metadataId), manager);
|
||||
serializer.save(file);
|
||||
}
|
||||
|
||||
public static void serialize(String metadataId, Metadata metadata, File file) throws IOException {
|
||||
Preconditions.checkNotNull(metadataId);
|
||||
Preconditions.checkNotNull(metadata);
|
||||
Preconditions.checkNotNull(file);
|
||||
|
||||
serialize(metadataId, new MetadataManager() {
|
||||
|
||||
@Override
|
||||
public Metadata store() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void retrieve(@SuppressWarnings("unused") Metadata source) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}, file);
|
||||
}
|
||||
|
||||
public static void deserialize(File file, String metadataId, MetadataManager manager)
|
||||
throws IOException {
|
||||
Preconditions.checkNotNull(file);
|
||||
Preconditions.checkNotNull(metadataId);
|
||||
Preconditions.checkNotNull(manager);
|
||||
|
||||
Serializer serializer = of();
|
||||
Key<Metadata> key = Key.of(metadataId);
|
||||
serializer.register(key, manager);
|
||||
serializer.load(file);
|
||||
serializer.deregister(key);
|
||||
}
|
||||
|
||||
public static FixedMetadata deserialize(File file, String metadataId) throws IOException {
|
||||
Preconditions.checkNotNull(file);
|
||||
Preconditions.checkNotNull(metadataId);
|
||||
|
||||
class DirectMetadataManager implements MetadataManager {
|
||||
final SettableMetadata metadata = SettableMetadata.of(Version.of(0, 1));
|
||||
|
||||
@Override
|
||||
public Metadata store() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void retrieve(Metadata source) {
|
||||
for (Key<?> key : source.getKeys()) {
|
||||
put(key, source.get(key), metadata);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DirectMetadataManager manager = new DirectMetadataManager();
|
||||
deserialize(file, metadataId, manager);
|
||||
return FixedMetadata.of(manager.metadata);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> void put(Key<?> key, T object, SettableMetadata metadata) {
|
||||
metadata.put((Key<T>) key, object);
|
||||
}
|
||||
}
|
||||
9
src/edu/jhuapl/ses/jsqrl/impl/gson/SetIO.java
Normal file
9
src/edu/jhuapl/ses/jsqrl/impl/gson/SetIO.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl.gson;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.gson.JsonDeserializer;
|
||||
|
||||
interface SetIO extends JsonDeserializer<Set<?>> {
|
||||
|
||||
}
|
||||
30
src/edu/jhuapl/ses/jsqrl/impl/gson/SetIOv1.java
Normal file
30
src/edu/jhuapl/ses/jsqrl/impl/gson/SetIOv1.java
Normal file
@@ -0,0 +1,30 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParseException;
|
||||
|
||||
final class SetIOv1 extends IterableIOv1 implements SetIO {
|
||||
@Override
|
||||
public Set<?> deserialize(JsonElement jsonElement, @SuppressWarnings("unused") Type typeOfT,
|
||||
JsonDeserializationContext context) throws JsonParseException {
|
||||
DeserializedJsonArray array = unpack(jsonElement);
|
||||
DataTypeInfo dataInfo = array.dataTypeInfo;
|
||||
JsonArray jsonArray = array.jsonArray;
|
||||
|
||||
// Create output data object.
|
||||
Set<?> result = new HashSet<>();
|
||||
|
||||
Type valueType = dataInfo.getType();
|
||||
for (JsonElement entryElement : jsonArray) {
|
||||
result.add(context.deserialize(entryElement, valueType));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
21
src/edu/jhuapl/ses/jsqrl/impl/gson/SetIOv2.java
Normal file
21
src/edu/jhuapl/ses/jsqrl/impl/gson/SetIOv2.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
final class SetIOv2 extends IterableIOv2 implements SetIO {
|
||||
|
||||
@Override
|
||||
public Set<?> deserialize(JsonElement jsonElement, @SuppressWarnings("unused") Type typeOfT,
|
||||
JsonDeserializationContext context) {
|
||||
Preconditions.checkArgument(jsonElement.isJsonObject());
|
||||
|
||||
return new LinkedHashSet<>(deserialize(jsonElement.getAsJsonObject(), context));
|
||||
}
|
||||
|
||||
}
|
||||
10
src/edu/jhuapl/ses/jsqrl/impl/gson/SortedMapIO.java
Normal file
10
src/edu/jhuapl/ses/jsqrl/impl/gson/SortedMapIO.java
Normal file
@@ -0,0 +1,10 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl.gson;
|
||||
|
||||
import java.util.SortedMap;
|
||||
|
||||
import com.google.gson.JsonDeserializer;
|
||||
|
||||
|
||||
interface SortedMapIO extends JsonDeserializer<SortedMap<?, ?>> {
|
||||
|
||||
}
|
||||
38
src/edu/jhuapl/ses/jsqrl/impl/gson/SortedMapIOv1.java
Normal file
38
src/edu/jhuapl/ses/jsqrl/impl/gson/SortedMapIOv1.java
Normal file
@@ -0,0 +1,38 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonNull;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
|
||||
final class SortedMapIOv1 extends MapBaseIOv1 implements SortedMapIO {
|
||||
@Override
|
||||
public SortedMap<?, ?> deserialize(JsonElement jsonElement,
|
||||
@SuppressWarnings("unused") Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
SortedMap<?, ?> result = new TreeMap<>();
|
||||
|
||||
DeserializedJsonObject object = unpack(jsonElement);
|
||||
Type keyType = object.keyTypeInfo.getType();
|
||||
Type valueType = object.valueTypeInfo.getType();
|
||||
|
||||
for (Entry<String, JsonElement> entry : object.jsonMap.getAsJsonObject().entrySet()) {
|
||||
String keyString = entry.getKey();
|
||||
JsonElement keyElement =
|
||||
keyString.equals("null") ? JsonNull.INSTANCE : new JsonPrimitive(keyString);
|
||||
JsonElement valueElement = entry.getValue();
|
||||
|
||||
result.put(context.deserialize(keyElement, keyType),
|
||||
context.deserialize(valueElement, valueType));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
25
src/edu/jhuapl/ses/jsqrl/impl/gson/SortedMapIOv2.java
Normal file
25
src/edu/jhuapl/ses/jsqrl/impl/gson/SortedMapIOv2.java
Normal file
@@ -0,0 +1,25 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
final class SortedMapIOv2 extends MapBaseIOv2 implements SortedMapIO {
|
||||
|
||||
@Override
|
||||
public SortedMap<?, ?> deserialize(JsonElement jsonElement,
|
||||
@SuppressWarnings("unused") Type typeOfT, JsonDeserializationContext context) {
|
||||
|
||||
Preconditions.checkArgument(jsonElement.isJsonObject());
|
||||
|
||||
SortedMap<Object, Object> result = new TreeMap<>();
|
||||
deserialize(jsonElement.getAsJsonObject(), context, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
10
src/edu/jhuapl/ses/jsqrl/impl/gson/SortedSetIO.java
Normal file
10
src/edu/jhuapl/ses/jsqrl/impl/gson/SortedSetIO.java
Normal file
@@ -0,0 +1,10 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl.gson;
|
||||
|
||||
import java.util.SortedSet;
|
||||
|
||||
import com.google.gson.JsonDeserializer;
|
||||
|
||||
|
||||
interface SortedSetIO extends JsonDeserializer<SortedSet<?>> {
|
||||
|
||||
}
|
||||
30
src/edu/jhuapl/ses/jsqrl/impl/gson/SortedSetIOv1.java
Normal file
30
src/edu/jhuapl/ses/jsqrl/impl/gson/SortedSetIOv1.java
Normal file
@@ -0,0 +1,30 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParseException;
|
||||
|
||||
final class SortedSetIOv1 extends IterableIOv1 implements SortedSetIO {
|
||||
@Override
|
||||
public SortedSet<?> deserialize(JsonElement jsonElement, @SuppressWarnings("unused") Type typeOfT,
|
||||
JsonDeserializationContext context) throws JsonParseException {
|
||||
DeserializedJsonArray array = unpack(jsonElement);
|
||||
DataTypeInfo dataInfo = array.dataTypeInfo;
|
||||
JsonArray jsonArray = array.jsonArray;
|
||||
|
||||
// Create output data object.
|
||||
SortedSet<?> result = new TreeSet<>();
|
||||
|
||||
Type valueType = dataInfo.getType();
|
||||
for (JsonElement entryElement : jsonArray) {
|
||||
result.add(context.deserialize(entryElement, valueType));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
21
src/edu/jhuapl/ses/jsqrl/impl/gson/SortedSetIOv2.java
Normal file
21
src/edu/jhuapl/ses/jsqrl/impl/gson/SortedSetIOv2.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
final class SortedSetIOv2 extends IterableIOv2 implements SortedSetIO {
|
||||
|
||||
@Override
|
||||
public SortedSet<?> deserialize(JsonElement jsonElement, @SuppressWarnings("unused") Type typeOfT,
|
||||
JsonDeserializationContext context) {
|
||||
Preconditions.checkArgument(jsonElement.isJsonObject());
|
||||
|
||||
return new TreeSet<>(deserialize(jsonElement.getAsJsonObject(), context));
|
||||
}
|
||||
|
||||
}
|
||||
6
src/edu/jhuapl/ses/jsqrl/impl/gson/Spud.java
Normal file
6
src/edu/jhuapl/ses/jsqrl/impl/gson/Spud.java
Normal file
@@ -0,0 +1,6 @@
|
||||
package edu.jhuapl.ses.jsqrl.impl.gson;
|
||||
|
||||
public class Spud
|
||||
{
|
||||
|
||||
}
|
||||
43
src/edu/jhuapl/ses/jsqrl/package-info.java
Normal file
43
src/edu/jhuapl/ses/jsqrl/package-info.java
Normal file
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Core implementation of the metadata API. This includes factories for implementations of the
|
||||
* primary interfaces (Metadata etc.) as well as utility classes and abstract base implementations.
|
||||
* <p>
|
||||
* Release Notes
|
||||
* <p>
|
||||
* Package Version 4.4.1, 2020-03-11
|
||||
* <p>
|
||||
* 1. Fixed a bug which caused SortedMap and SortedSet implementations to be serialized as normal
|
||||
* Maps and Sets, respectively. This led to spurious exceptions when they were deserialized.
|
||||
* <p>
|
||||
* Package Version 4.4, 2020-03-05
|
||||
* <p>
|
||||
* 1. Support storing/retrieving Class objects.
|
||||
* <p>
|
||||
* 2. Use LinkedHashSet and LinkedHashMap to do a better job of preserving order.
|
||||
* <p>
|
||||
* Package Version 4.3, 2019-11-15
|
||||
* <p>
|
||||
* Bug fix: if InstanceGetter had a custom serializer/deserializer for a type that implemented Map,
|
||||
* Set or List, two bugs would cause an object of that type to be serialized as a Map, Set or List,
|
||||
* bypassing the custom serializer.
|
||||
* <p>
|
||||
* Package Version 4.2, 2019-10-02
|
||||
* <p>
|
||||
* Bug fix: when serializing Iterables and Maps, under some circumstances, objects that should have
|
||||
* been recognized as having different types were being treated as if they were stored the same way.
|
||||
* This resulted in errors when trying to deserialize metadata files that had been written by the
|
||||
* buggy code.
|
||||
* <p>
|
||||
* Package Version 4.1, 2019-04-10
|
||||
* <p>
|
||||
* InstanceGetter: Add support for matching abstract types and interfaces when encoding/decoding
|
||||
* objects as proxy metadata.
|
||||
* <p>
|
||||
* Package Version 4.0, 2019-03-25
|
||||
* <p>
|
||||
* 1. Accept, serialize and deserialize Class<?> objects.
|
||||
* <p>
|
||||
* 2. Create directories as needed to serialize the file in question.
|
||||
* <p>
|
||||
*/
|
||||
package edu.jhuapl.ses.jsqrl;
|
||||
Reference in New Issue
Block a user