diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/.classpath b/runtime/tests/org.eclipse.e4.core.javax.tests/.classpath
new file mode 100644
index 00000000000..675a5e2962b
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/.classpath
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/.gitignore b/runtime/tests/org.eclipse.e4.core.javax.tests/.gitignore
new file mode 100644
index 00000000000..c59ea270aa5
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/.gitignore
@@ -0,0 +1 @@
+OSGI-INF/*.xml
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/.project b/runtime/tests/org.eclipse.e4.core.javax.tests/.project
new file mode 100644
index 00000000000..bc2c0c6a994
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/.project
@@ -0,0 +1,33 @@
+
+
+ org.eclipse.e4.core.javax.tests
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.pde.ManifestBuilder
+
+
+
+
+ org.eclipse.pde.SchemaBuilder
+
+
+
+
+ org.eclipse.pde.ds.core.builder
+
+
+
+
+
+ org.eclipse.pde.PluginNature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/.settings/org.eclipse.core.resources.prefs b/runtime/tests/org.eclipse.e4.core.javax.tests/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 00000000000..99f26c0203a
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/=UTF-8
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/.settings/org.eclipse.core.runtime.prefs b/runtime/tests/org.eclipse.e4.core.javax.tests/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 00000000000..5a0ad22d2a7
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/.settings/org.eclipse.jdt.core.prefs b/runtime/tests/org.eclipse.e4.core.javax.tests/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000000..1e7783f372f
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,445 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.builder.annotationPath.allLocations=disabled
+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=17
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=17
+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=error
+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=ignore
+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=warning
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+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=error
+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=disabled
+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=warning
+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=17
+org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_additive_operator=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=16
+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_logical_operator=16
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_module_statements=16
+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=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_string_concatenation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+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=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_package=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_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_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=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped=true
+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=false
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=false
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
+org.eclipse.jdt.core.formatter.comment.line_length=80
+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_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=do not 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=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=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_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_superinterfaces=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_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_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_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_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_superinterfaces=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_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_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=true
+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_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=120
+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_at_beginning_of_method_body=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_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=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+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_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_string_concatenation=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/.settings/org.eclipse.jdt.ui.prefs b/runtime/tests/org.eclipse.e4.core.javax.tests/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 00000000000..5c2f9bc5044
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,66 @@
+cleanup.use_type_arguments=false
+cleanup_settings_version=2
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=org.eclipse.jdt.ui.default.eclipse_profile
+formatter_settings_version=14
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.staticondemandthreshold=99
+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.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=true
+sp_cleanup.format_source_code_changes_only=true
+sp_cleanup.insert_inferred_type_arguments=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.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=true
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+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.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=false
+sp_cleanup.remove_trailing_whitespaces=true
+sp_cleanup.remove_trailing_whitespaces_all=true
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=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_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.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=true
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=true
+sp_cleanup.use_parentheses_in_expressions=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_type_arguments=false
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/.settings/org.eclipse.pde.ds.annotations.prefs b/runtime/tests/org.eclipse.e4.core.javax.tests/.settings/org.eclipse.pde.ds.annotations.prefs
new file mode 100644
index 00000000000..38f9eecff8e
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/.settings/org.eclipse.pde.ds.annotations.prefs
@@ -0,0 +1,7 @@
+dsVersion=V1_3
+eclipse.preferences.version=1
+enabled=true
+generateBundleActivationPolicyLazy=true
+path=OSGI-INF
+validationErrorLevel=error
+validationErrorLevel.missingImplicitUnbindMethod=error
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/META-INF/MANIFEST.MF b/runtime/tests/org.eclipse.e4.core.javax.tests/META-INF/MANIFEST.MF
new file mode 100644
index 00000000000..938730a37ac
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/META-INF/MANIFEST.MF
@@ -0,0 +1,40 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: E4 Core Tests
+Bundle-SymbolicName: org.eclipse.e4.core.javax.tests
+Bundle-Version: 1.3.200.qualifier
+Bundle-Vendor: Eclipse.org
+Bundle-Activator: org.eclipse.e4.core.internal.tests.CoreTestsActivator
+Require-Bundle: org.eclipse.osgi;bundle-version="3.6.0",
+ org.eclipse.equinox.preferences;bundle-version="3.3.0",
+ org.eclipse.e4.core.di,
+ org.eclipse.e4.core.di.extensions,
+ org.eclipse.e4.core.di.extensions.supplier,
+ org.eclipse.e4.core.contexts,
+ org.eclipse.equinox.registry;bundle-version="3.5.0",
+ org.eclipse.core.tests.harness;bundle-version="3.6.0",
+ org.eclipse.e4.core.services;bundle-version="1.1.0",
+ org.junit;bundle-version="4.12.0"
+Bundle-ActivationPolicy: lazy
+Bundle-RequiredExecutionEnvironment: JavaSE-17
+Import-Package: javax.annotation;version="[1.3.0,2.0.0)",
+ javax.inject;version="[1.0.0,2.0.0)",
+ org.osgi.service.component;version="1.3.0",
+ org.osgi.service.event;version="1.3.0"
+Export-Package: org.eclipse.e4.core.internal.tests;x-internal:=true,
+ org.eclipse.e4.core.internal.tests.contexts;x-internal:=true,
+ org.eclipse.e4.core.internal.tests.contexts.inject;x-internal:=true,
+ org.eclipse.e4.core.internal.tests.contexts.performance;x-internal:=true,
+ org.eclipse.e4.core.internal.tests.di;x-internal:=true,
+ org.eclipse.e4.core.internal.tests.di.extensions;x-internal:=true,
+ org.eclipse.e4.core.internal.tests.manual;x-internal:=true,
+ org.eclipse.e4.core.internal.tests.nls;x-internal:=true,
+ org.eclipse.e4.core.javax.tests
+Service-Component: OSGI-INF/*.xml
+Eclipse-BundleShape: dir
+Require-Capability: osgi.extender;
+ filter:="(&(osgi.extender=osgi.component)(version>=1.3)(!(version>=2.0)))",
+ osgi.service;
+ filter:="(objectClass=org.osgi.service.event.EventAdmin)";
+ effective:="active"
+Automatic-Module-Name: org.eclipse.e4.core.javax.tests
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/OSGI-INF/l10n/bundle.properties b/runtime/tests/org.eclipse.e4.core.javax.tests/OSGI-INF/l10n/bundle.properties
new file mode 100644
index 00000000000..ad0b4b93cb0
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/OSGI-INF/l10n/bundle.properties
@@ -0,0 +1,11 @@
+message=BundleMessage
+message_one=BundleMessageUnderscore
+messageOne=BundleMessageCamelCase
+message.two=BundleMessageUnderscoreDot
+message.three=BundleMessageCamelCaseDot
+message.four=The idea is from {0}
+messageFive_Sub=BundleMessageCamelCaseAndUnderscoreOriginal
+message_six__sub=BundleMessageCamelCaseAndUnderscoreDeCamelCasified
+message.seven..sub=BundleMessageCamelCaseAndUnderscoreDeCamelCasifiedAndDeUnderscorified
+messageEight.Sub=BundleMessageCamelCaseAndUnderscoreDeUnderscorified
+message_nine._sub=BundleMessageCamelCaseAndUnderscoreDeUnderscorifiedAndDeCamelCasified
\ No newline at end of file
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/OSGI-INF/l10n/bundle_de.properties b/runtime/tests/org.eclipse.e4.core.javax.tests/OSGI-INF/l10n/bundle_de.properties
new file mode 100644
index 00000000000..c45cde6d1d7
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/OSGI-INF/l10n/bundle_de.properties
@@ -0,0 +1,10 @@
+message=BundleNachricht
+message_one=BundleNachrichtUnderscore
+messageOne=BundleNachrichtCamelCase
+message.two=BundleNachrichtUnderscoreDot
+message.four=Die Idee ist von {0}
+messageFive_Sub=BundleNachrichtCamelCaseAndUnderscoreOriginal
+message_six__sub=BundleNachrichtCamelCaseAndUnderscoreDeCamelCasified
+message.seven..sub=BundleNachrichtCamelCaseAndUnderscoreDeCamelCasifiedAndDeUnderscorified
+messageEight.Sub=BundleNachrichtCamelCaseAndUnderscoreDeUnderscorified
+message_nine._sub=BundleNachrichtCamelCaseAndUnderscoreDeUnderscorifiedAndDeCamelCasified
\ No newline at end of file
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/OSGI-INF/l10n/bundle_de_ch_test.properties b/runtime/tests/org.eclipse.e4.core.javax.tests/OSGI-INF/l10n/bundle_de_ch_test.properties
new file mode 100644
index 00000000000..a0582385afb
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/OSGI-INF/l10n/bundle_de_ch_test.properties
@@ -0,0 +1,10 @@
+message=BundleNachrichtVariant
+message_one=BundleNachrichtUnderscoreVariant
+messageOne=BundleNachrichtCamelCaseVariant
+message.two=BundleNachrichtUnderscoreDotVariant
+message.four=Die Idee ist von {0} Variant
+messageFive_Sub=BundleNachrichtCamelCaseAndUnderscoreOriginalVariant
+message_six__sub=BundleNachrichtCamelCaseAndUnderscoreDeCamelCasifiedVariant
+message.seven..sub=BundleNachrichtCamelCaseAndUnderscoreDeCamelCasifiedAndDeUnderscorifiedVariant
+messageEight.Sub=BundleNachrichtCamelCaseAndUnderscoreDeUnderscorifiedVariant
+message_nine._sub=BundleNachrichtCamelCaseAndUnderscoreDeUnderscorifiedAndDeCamelCasifiedVariant
\ No newline at end of file
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/README.md b/runtime/tests/org.eclipse.e4.core.javax.tests/README.md
new file mode 100644
index 00000000000..c15285d1bfc
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/README.md
@@ -0,0 +1,2 @@
+This is a copy of `org.eclipse.e4.core.tests`, that uses javax annotations while the original uses jakarta annotations now.
+When support for javax annotations is removed from the E4-Injector, this project can be deleted entirely as well.
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/about.html b/runtime/tests/org.eclipse.e4.core.javax.tests/about.html
new file mode 100644
index 00000000000..164f781a8fd
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/about.html
@@ -0,0 +1,36 @@
+
+
+
+
+About
+
+
+
About This Content
+
+
November 30, 2017
+
License
+
+
+ The Eclipse Foundation makes available all content in this plug-in
+ ("Content"). Unless otherwise indicated below, the Content
+ is provided to you under the terms and conditions of the Eclipse
+ Public License Version 2.0 ("EPL"). A copy of the EPL is
+ available at http://www.eclipse.org/legal/epl-2.0.
+ For purposes of the EPL, "Program" will mean the Content.
+
+
+
+ If you did not receive this Content directly from the Eclipse
+ Foundation, the Content is being redistributed by another party
+ ("Redistributor") and different terms and conditions may
+ apply to your use of any object code in the Content. Check the
+ Redistributor's license that was provided with the Content. If no such
+ license exists, contact the Redistributor. Unless otherwise indicated
+ below, the terms and conditions of the EPL still apply to any source
+ code in the Content and such source code may be obtained at http://www.eclipse.org.
+
+
+
+
\ No newline at end of file
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/build.properties b/runtime/tests/org.eclipse.e4.core.javax.tests/build.properties
new file mode 100644
index 00000000000..76d226c77dc
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/build.properties
@@ -0,0 +1,24 @@
+###############################################################################
+# Copyright (c) 2010, 2015 IBM Corporation and others.
+#
+# This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License 2.0
+# which accompanies this distribution, and is available at
+# https://www.eclipse.org/legal/epl-2.0/
+#
+# SPDX-License-Identifier: EPL-2.0
+#
+# Contributors:
+# IBM Corporation - initial API and implementation
+# Lars Vogel - Bug 474642
+###############################################################################
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ test.xml,\
+ OSGI-INF/,\
+ resources/,\
+ about.html
+src.includes = resources/,\
+ about.html
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/pom.xml b/runtime/tests/org.eclipse.e4.core.javax.tests/pom.xml
new file mode 100644
index 00000000000..44f12659599
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/pom.xml
@@ -0,0 +1,62 @@
+
+
+
+ 4.0.0
+
+ org.eclipse.platform
+ eclipse.platform.runtime
+ 4.30.0-SNAPSHOT
+ ../..
+
+ org.eclipse.e4.core.javax.tests
+ 1.3.200-SNAPSHOT
+ eclipse-test-plugin
+
+ org.eclipse.e4.core.javax.tests.CoreTestSuite
+
+
+ src
+
+
+ org.apache.maven.plugins
+ maven-resources-plugin
+
+
+
+ copy-ds-component-xml
+
+ copy-resources
+
+ process-test-resources
+
+
+
+
+ ${project.build.outputDirectory}/OSGI-INF
+ *.xml
+
+
+ ${project.basedir}/OSGI-INF
+
+
+
+
+
+
+
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/resources/another.properties b/runtime/tests/org.eclipse.e4.core.javax.tests/resources/another.properties
new file mode 100644
index 00000000000..86e9d9c7baf
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/resources/another.properties
@@ -0,0 +1,11 @@
+message=ResourcesMessage
+message_one=ResourcesMessageUnderscore
+messageOne=ResourcesMessageCamelCase
+message.two=ResourcesMessageUnderscoreDot
+message.three=ResourcesMessageCamelCaseDot
+message.four=The idea is from {0}
+messageFive_Sub=ResourcesMessageCamelCaseAndUnderscoreOriginal
+message_six__sub=ResourcesMessageCamelCaseAndUnderscoreDeCamelCasified
+message.seven..sub=ResourcesMessageCamelCaseAndUnderscoreDeCamelCasifiedAndDeUnderscorified
+messageEight.Sub=ResourcesMessageCamelCaseAndUnderscoreDeUnderscorified
+message_nine._sub=ResourcesMessageCamelCaseAndUnderscoreDeUnderscorifiedAndDeCamelCasified
\ No newline at end of file
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/resources/another_de.properties b/runtime/tests/org.eclipse.e4.core.javax.tests/resources/another_de.properties
new file mode 100644
index 00000000000..7c4441b54a6
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/resources/another_de.properties
@@ -0,0 +1,10 @@
+message=ResourcesNachricht
+message_one=ResourcesNachrichtUnderscore
+messageOne=ResourcesNachrichtCamelCase
+message.two=ResourcesNachrichtUnderscoreDot
+message.four=Die Idee ist von {0}
+messageFive_Sub=ResourcesNachrichtCamelCaseAndUnderscoreOriginal
+message_six__sub=ResourcesNachrichtCamelCaseAndUnderscoreDeCamelCasified
+message.seven..sub=ResourcesNachrichtCamelCaseAndUnderscoreDeCamelCasifiedAndDeUnderscorified
+messageEight.Sub=ResourcesNachrichtCamelCaseAndUnderscoreDeUnderscorified
+message_nine._sub=ResourcesNachrichtCamelCaseAndUnderscoreDeUnderscorifiedAndDeCamelCasified
\ No newline at end of file
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/CoreTestsActivator.java b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/CoreTestsActivator.java
new file mode 100644
index 00000000000..6d0c273f3e1
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/CoreTestsActivator.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2015 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.e4.core.internal.tests;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.eclipse.core.runtime.preferences.IPreferencesService;
+import org.eclipse.e4.core.contexts.IContextFunction;
+import org.eclipse.e4.core.internal.tests.contexts.ContextFunctionHigh;
+import org.eclipse.e4.core.internal.tests.contexts.ContextFunctionLow;
+import org.eclipse.osgi.service.debug.DebugOptions;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.service.event.EventAdmin;
+import org.osgi.util.tracker.ServiceTracker;
+
+public class CoreTestsActivator implements BundleActivator {
+
+ static private CoreTestsActivator defaultInstance;
+ private BundleContext bundleContext;
+ private ServiceTracker debugTracker = null;
+ private ServiceTracker preferencesTracker = null;
+ private ServiceTracker eventAdminTracker;
+
+ public CoreTestsActivator() {
+ defaultInstance = this;
+ }
+
+ public static CoreTestsActivator getDefault() {
+ return defaultInstance;
+ }
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ bundleContext = context;
+ registerContextFunctions();
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ if (preferencesTracker != null) {
+ preferencesTracker.close();
+ preferencesTracker = null;
+ }
+ if (debugTracker != null) {
+ debugTracker.close();
+ debugTracker = null;
+ }
+ if (eventAdminTracker != null) {
+ eventAdminTracker.close();
+ eventAdminTracker = null;
+ }
+ bundleContext = null;
+ }
+
+ private void registerContextFunctions() {
+ {
+ Dictionary properties = new Hashtable<>();
+ properties.put(IContextFunction.SERVICE_CONTEXT_KEY,"test.contextfunction.ranking");
+ properties.put(Constants.SERVICE_RANKING, 0);
+ bundleContext.registerService(IContextFunction.SERVICE_NAME, new ContextFunctionLow(), properties);
+ }
+
+ Dictionary properties = new Hashtable<>();
+ properties.put(IContextFunction.SERVICE_CONTEXT_KEY,"test.contextfunction.ranking");
+ properties.put(Constants.SERVICE_RANKING, 100);
+ bundleContext.registerService(IContextFunction.SERVICE_NAME, new ContextFunctionHigh(), properties);
+
+ }
+
+ public BundleContext getBundleContext() {
+ return bundleContext;
+ }
+
+ public EventAdmin getEventAdmin() {
+ if (eventAdminTracker == null) {
+ if (bundleContext == null) {
+ return null;
+ }
+ eventAdminTracker = new ServiceTracker<>(bundleContext, EventAdmin.class.getName(), null);
+ eventAdminTracker.open();
+ }
+ return eventAdminTracker.getService();
+ }
+
+}
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/ActivationTest.java b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/ActivationTest.java
new file mode 100644
index 00000000000..767113bd3dd
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/ActivationTest.java
@@ -0,0 +1,332 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2015 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Lars Vogel - Bug 474274
+ ******************************************************************************/
+
+package org.eclipse.e4.core.internal.tests.contexts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.eclipse.e4.core.contexts.ContextFunction;
+import org.eclipse.e4.core.contexts.EclipseContextFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.contexts.RunAndTrack;
+import org.junit.Test;
+
+public class ActivationTest {
+
+ static public class TestRAT extends ContextFunction {
+ @Override
+ public Object compute(IEclipseContext context, String contextKey) {
+ IEclipseContext activeContext = context.getActiveLeaf();
+ // returns name of the context
+ return activeContext.get("debugString");
+ }
+ }
+
+ @Test
+ public void testContextActivation() {
+ IEclipseContext rootContext = EclipseContextFactory.create("root");
+ rootContext.set("testRAT", new TestRAT());
+
+ IEclipseContext child1 = rootContext.createChild("child1");
+ IEclipseContext child11 = child1.createChild("child11");
+ IEclipseContext child12 = child1.createChild("child12");
+
+ IEclipseContext child2 = rootContext.createChild("child2");
+ IEclipseContext child21 = child2.createChild("child21");
+ IEclipseContext child22 = child2.createChild("child22");
+
+ assertEquals(rootContext, rootContext.getActiveLeaf());
+ assertNull(rootContext.getActiveChild());
+ assertEquals("root", rootContext.get("testRAT"));
+
+ child12.activateBranch();
+ assertEquals(child12, rootContext.getActiveLeaf());
+ assertEquals(child1, rootContext.getActiveChild());
+ assertEquals("child12", rootContext.get("testRAT"));
+
+ assertEquals(child2, child2.getActiveLeaf());
+ assertNull(child2.getActiveChild());
+ assertEquals("child2", child2.get("testRAT"));
+
+ child21.activateBranch();
+ assertEquals(child21, rootContext.getActiveLeaf());
+ assertEquals(child2, rootContext.getActiveChild());
+ assertEquals("child21", rootContext.get("testRAT"));
+ assertEquals(child12, child1.getActiveLeaf());
+ assertEquals(child12, child1.getActiveChild());
+ assertEquals("child12", child1.get("testRAT"));
+ assertEquals(child21, child2.getActiveLeaf());
+ assertEquals(child21, child2.getActiveChild());
+ assertEquals("child21", child2.get("testRAT"));
+
+ child21.deactivate();
+ assertEquals(child2, rootContext.getActiveLeaf());
+ assertEquals("child2", rootContext.get("testRAT"));
+ assertEquals(child12, child1.getActiveLeaf());
+ assertEquals("child12", child1.get("testRAT"));
+ assertEquals(child2, child2.getActiveLeaf());
+ assertNull(child2.getActiveChild());
+ assertEquals("child2", child2.get("testRAT"));
+
+ child22.activateBranch();
+ assertEquals(child22, rootContext.getActiveLeaf());
+ assertEquals("child22", rootContext.get("testRAT"));
+ assertEquals(child12, child1.getActiveLeaf());
+ assertEquals("child12", child1.get("testRAT"));
+ assertEquals(child22, child2.getActiveLeaf());
+ assertEquals("child22", child2.get("testRAT"));
+
+ child11.activateBranch();
+ assertEquals(child11, rootContext.getActiveLeaf());
+ assertEquals("child11", rootContext.get("testRAT"));
+ assertEquals(child11, child1.getActiveLeaf());
+ assertEquals("child11", child1.get("testRAT"));
+ assertEquals(child22, child2.getActiveLeaf());
+ assertEquals("child22", child2.get("testRAT"));
+
+ child11.deactivate();
+ assertEquals(child1, rootContext.getActiveLeaf());
+ assertEquals("child1", rootContext.get("testRAT"));
+ assertEquals(child1, child1.getActiveLeaf());
+ assertEquals("child1", child1.get("testRAT"));
+ assertEquals(child22, child2.getActiveLeaf());
+ assertEquals("child22", child2.get("testRAT"));
+
+ child1.dispose();
+ assertNull(rootContext.getActiveChild());
+ child2.activateBranch();
+ assertEquals(child22, rootContext.getActiveLeaf());
+ assertEquals("child22", rootContext.get("testRAT"));
+ assertEquals(child22, child2.getActiveLeaf());
+ assertEquals("child22", child2.get("testRAT"));
+ }
+
+ @Test
+ public void testGetActive() {
+ IEclipseContext root = EclipseContextFactory.create("root");
+
+ IEclipseContext child1 = root.createChild("child1");
+ IEclipseContext child11 = child1.createChild("child11");
+ IEclipseContext child12 = child1.createChild("child12");
+
+ IEclipseContext child2 = root.createChild("child2");
+ IEclipseContext child21 = child2.createChild("child21");
+ IEclipseContext child22 = child2.createChild("child22");
+
+ child11.set("var", "1");
+ child12.set("var", "2");
+ child1.set("var", "3");
+ child21.set("var", "4");
+ child22.set("var", "5");
+ child2.set("var", "6");
+ root.set("var", "7");
+
+ // nothing is active - we get value from the node
+ assertEquals("3", child1.getActive("var"));
+
+ child11.activateBranch();
+ assertEquals("1", child1.getActive("var"));
+ child12.activateBranch();
+ assertEquals("2", child1.getActive("var"));
+ child22.activateBranch();
+ assertEquals("5", child2.getActive("var"));
+ }
+
+ @Test
+ public void testGetActiveBug384425() {
+ IEclipseContext root = EclipseContextFactory.create("root");
+
+ IEclipseContext child1 = root.createChild("child1");
+ IEclipseContext child11 = child1.createChild("child11");
+
+ IEclipseContext child2 = root.createChild("child2");
+
+ // nothing is active - we get value from the node
+ assertNull(root.getActive("var"));
+ assertNull(child1.getActive("var"));
+ assertNull(child2.getActive("var"));
+
+ child11.activateBranch();
+ child11.set("var", "1");
+
+ assertEquals("1", root.getActive("var"));
+ assertEquals("1", child1.getActive("var"));
+ assertNull(child2.getActive("var"));
+ }
+
+ @Test
+ public void testGetActiveRAT() {
+ IEclipseContext root = EclipseContextFactory.create("root");
+
+ IEclipseContext child1 = root.createChild("child1");
+ IEclipseContext child11 = child1.createChild("child11");
+ IEclipseContext child12 = child1.createChild("child12");
+
+ IEclipseContext child2 = root.createChild("child2");
+ IEclipseContext child21 = child2.createChild("child21");
+ IEclipseContext child22 = child2.createChild("child22");
+
+ child11.set("var", "1");
+ child12.set("var", "2");
+ child1.set("var", "3");
+ child21.set("var", "4");
+ child22.set("var", "5");
+ child2.set("var", "6");
+ root.set("var", "7");
+
+ final String[] result = new String[1];
+
+ child1.runAndTrack(new RunAndTrack() {
+ @Override
+ public boolean changed(IEclipseContext context) {
+ result[0] = (String) context.getActive("var");
+ return true;
+ }});
+
+ // nothing is active - we get value from the node
+ assertEquals("3", result[0]);
+
+ child11.activateBranch();
+ assertEquals("1", result[0]);
+ child12.activateBranch();
+ assertEquals("2", result[0]);
+ child22.activateBranch();
+ assertEquals("2", result[0]);
+ }
+
+ @Test
+ public void testGetActiveRATNumberOfCalls() {
+ IEclipseContext root = EclipseContextFactory.create("root");
+
+ IEclipseContext child1 = root.createChild("child1");
+ IEclipseContext child11 = child1.createChild("child11");
+ IEclipseContext child12 = child1.createChild("child12");
+
+ IEclipseContext child2 = root.createChild("child2");
+ IEclipseContext child21 = child2.createChild("child21");
+ IEclipseContext child22 = child2.createChild("child22");
+
+ child11.set("var", "1");
+ child12.set("var", "1");
+ child1.set("var", "3");
+ child21.set("var", "4");
+ child22.set("var", "4");
+ child2.set("var", "6");
+ root.set("var", "7");
+
+ final String[] result = new String[1];
+ final int[] called = new int[1];
+ called[0] = 0;
+
+ child1.runAndTrack(new RunAndTrack() {
+ @Override
+ public boolean changed(IEclipseContext context) {
+ result[0] = (String) context.getActive("var");
+ called[0]++;
+ return true;
+ }});
+
+ // nothing is active - we get value from the node
+ assertEquals("3", result[0]);
+ assertEquals(1, called[0]);
+
+ child11.activateBranch();
+ assertEquals("1", result[0]);
+ assertEquals(2, called[0]);
+
+ child12.activateBranch();
+ assertEquals("1", result[0]);
+ assertEquals(3, called[0]);
+
+ child22.activateBranch();
+ assertEquals("1", result[0]);
+ assertEquals(3, called[0]);
+
+ child21.activateBranch();
+ assertEquals("1", result[0]);
+ assertEquals(3, called[0]);
+ }
+
+ /**
+ * A variation of {@link #testGetActiveRATNumberOfCalls()} that
+ * uses distinct values in the leaf contexts.
+ */
+ @Test
+ public void testGetActiveRATNumberOfCalls2() {
+ IEclipseContext root = EclipseContextFactory.create("root");
+
+ IEclipseContext child1 = root.createChild("child1");
+ IEclipseContext child11 = child1.createChild("child11");
+ IEclipseContext child12 = child1.createChild("child12");
+
+ IEclipseContext child2 = root.createChild("child2");
+ IEclipseContext child21 = child2.createChild("child21");
+ IEclipseContext child22 = child2.createChild("child22");
+
+ child11.set("var", "11");
+ child12.set("var", "12");
+ child1.set("var", "3");
+ child21.set("var", "21");
+ child22.set("var", "22");
+ child2.set("var", "6");
+ root.set("var", "7");
+
+ final String[] result = new String[1];
+ final int[] called = new int[1];
+ called[0] = 0;
+
+ child1.runAndTrack(new RunAndTrack() {
+ @Override
+ public boolean changed(IEclipseContext context) {
+ result[0] = (String) context.getActive("var");
+ called[0]++;
+ return true;
+ }});
+
+ // nothing is active - we get value from the node
+ assertEquals("3", result[0]);
+ assertEquals(1, called[0]);
+
+ child11.activateBranch();
+ assertEquals("11", result[0]);
+ assertEquals(2, called[0]);
+
+ child12.activateBranch();
+ assertEquals("12", result[0]);
+ assertEquals(3, called[0]);
+
+ child22.activateBranch();
+ assertEquals("12", result[0]);
+ assertEquals(3, called[0]);
+
+ child21.activateBranch();
+ assertEquals("12", result[0]);
+ assertEquals(3, called[0]);
+ }
+
+ public static class ActiveInject {
+ //@Inject @Named("var")
+ public String value;
+
+ @Inject
+ public void setValue(@Named("var") String value) {
+ this.value = value;
+ }
+ }
+}
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/AddContextFunction.java b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/AddContextFunction.java
new file mode 100644
index 00000000000..5e260552012
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/AddContextFunction.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2015 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.e4.core.internal.tests.contexts;
+
+import org.eclipse.e4.core.contexts.ContextFunction;
+import org.eclipse.e4.core.contexts.IContextFunction;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.osgi.service.component.annotations.Component;
+
+
+/**
+ * A function provided as a declarative service. See OSGI-INF/adder.xml.
+ */
+@Component(service = IContextFunction.class, property = "service.context.key:String=sum")
+public class AddContextFunction extends ContextFunction {
+
+ @Override
+ public Object compute(IEclipseContext context, String contextKey) {
+ Integer xInt = (Integer) context.get("x");
+ Integer yInt = (Integer) context.get("y");
+ int sum = xInt == null ? 0 : xInt.intValue();
+ sum += yInt == null ? 0 : yInt.intValue();
+ return Integer.valueOf(sum);
+ }
+}
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/ContextDynamicTest.java b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/ContextDynamicTest.java
new file mode 100644
index 00000000000..4378096f02d
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/ContextDynamicTest.java
@@ -0,0 +1,178 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2015 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Lars Vogel - Bug 474274
+ *******************************************************************************/
+package org.eclipse.e4.core.internal.tests.contexts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import org.eclipse.e4.core.contexts.ContextFunction;
+import org.eclipse.e4.core.contexts.ContextInjectionFactory;
+import org.eclipse.e4.core.contexts.EclipseContextFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.internal.tests.contexts.inject.ObjectBasic;
+import org.junit.Test;
+
+/**
+ * Tests for the basic context functionality
+ */
+public class ContextDynamicTest {
+
+
+ @Test
+ public void testReplaceFunctionWithStaticValue() {
+ IEclipseContext parent = EclipseContextFactory.create();
+ IEclipseContext context = parent.createChild();
+ assertNull(context.getLocal("bar"));
+ context.set("bar", "baz1");
+ context.set("bar", new ContextFunction() {
+ @Override
+ public Object compute(IEclipseContext context, String contextKey) {
+ return "baz1";
+ }
+ });
+ parent.set("bar", "baz2");
+ assertEquals("baz1", context.get("bar"));
+ context.set("bar", "baz3");
+ assertEquals("baz3", context.get("bar"));
+ }
+
+ /**
+ * Tests objects being added and removed from the context
+ */
+ @Test
+ public synchronized void testAddRemove() {
+ Integer testInt = Integer.valueOf(123);
+ String testString = "abc";
+ Double testDouble = Double.valueOf(1.23);
+ Float testFloat = Float.valueOf(12.3f);
+ Character testChar = Character.valueOf('v');
+
+ // create original context
+ IEclipseContext context = EclipseContextFactory.create();
+ context.set(Integer.class.getName(), testInt);
+ context.set(String.class.getName(), testString);
+ context.set(Double.class.getName(), testDouble);
+ context.set(Float.class.getName(), testFloat);
+ context.set(Character.class.getName(), testChar);
+
+ ObjectBasic userObject = new ObjectBasic();
+ ContextInjectionFactory.inject(userObject, context);
+
+ // check basic injection
+ assertEquals(testString, userObject.injectedString);
+ assertEquals(testInt, userObject.getInt());
+ assertEquals(context, userObject.context);
+ assertEquals(1, userObject.setMethodCalled);
+ assertEquals(1, userObject.setMethodCalled2);
+ assertEquals(testDouble, userObject.d);
+ assertEquals(testFloat, userObject.f);
+ assertEquals(testChar, userObject.c);
+
+ // change value
+ Double testDouble2 = Double.valueOf(3.45);
+ Integer testInt2 = Integer.valueOf(123);
+ context.set(Double.class.getName(), testDouble2);
+ context.set(Integer.class.getName(), testInt2);
+
+ // and check
+ assertEquals(testString, userObject.injectedString);
+ assertEquals(testInt2, userObject.getInt());
+ assertEquals(context, userObject.context);
+ assertEquals(2, userObject.setMethodCalled);
+ assertEquals(1, userObject.setMethodCalled2);
+ assertEquals(testDouble2, userObject.d);
+ assertEquals(testFloat, userObject.f);
+ assertEquals(testChar, userObject.c);
+
+ // remove element
+ context.remove(String.class.getName());
+ context.remove(Character.class.getName());
+
+ // and check
+ assertNull(userObject.injectedString);
+ assertEquals(testInt2, userObject.getInt());
+ assertEquals(context, userObject.context);
+ assertEquals(2, userObject.setMethodCalled);
+ assertEquals(2, userObject.setMethodCalled2);
+ assertEquals(testDouble2, userObject.d);
+ assertEquals(testFloat, userObject.f);
+ assertNull(userObject.c);
+ }
+
+ /**
+ * Tests objects being added and removed from the context
+ */
+ @Test
+ public synchronized void testParentAddRemove() {
+ Integer testInt = Integer.valueOf(123);
+ String testString = "abc";
+ Double testDouble = Double.valueOf(1.23);
+ Float testFloat = Float.valueOf(12.3f);
+ Character testChar = Character.valueOf('v');
+
+ // create original context
+ IEclipseContext parentContext = EclipseContextFactory.create();
+ parentContext.set(Integer.class.getName(), testInt);
+ parentContext.set(String.class.getName(), testString);
+ parentContext.set(Double.class.getName(), testDouble);
+ parentContext.set(Float.class.getName(), testFloat);
+ parentContext.set(Character.class.getName(), testChar);
+ IEclipseContext context = parentContext.createChild();
+
+ ObjectBasic userObject = new ObjectBasic();
+ ContextInjectionFactory.inject(userObject, context);
+
+ // check basic injection
+ assertEquals(testString, userObject.injectedString);
+ assertEquals(testInt, userObject.getInt());
+ assertEquals(context, userObject.context);
+ assertEquals(1, userObject.setMethodCalled);
+ assertEquals(1, userObject.setMethodCalled2);
+ assertEquals(testDouble, userObject.d);
+ assertEquals(testFloat, userObject.f);
+ assertEquals(testChar, userObject.c);
+
+ // change value
+ Double testDouble2 = Double.valueOf(3.45);
+ Integer testInt2 = Integer.valueOf(123);
+ context.set(Double.class.getName(), testDouble2);
+ context.set(Integer.class.getName(), testInt2);
+
+ // and check
+ assertEquals(testString, userObject.injectedString);
+ assertEquals(testInt2, userObject.getInt());
+ assertEquals(context, userObject.context);
+ assertEquals(2, userObject.setMethodCalled);
+ assertEquals(1, userObject.setMethodCalled2);
+ assertEquals(testDouble2, userObject.d);
+ assertEquals(testFloat, userObject.f);
+ assertEquals(testChar, userObject.c);
+
+ // remove element
+ parentContext.remove(String.class.getName());
+ parentContext.remove(Character.class.getName());
+
+ // and check
+ assertNull(userObject.injectedString);
+ assertEquals(testInt2, userObject.getInt());
+ assertEquals(context, userObject.context);
+ assertEquals(2, userObject.setMethodCalled);
+ assertEquals(2, userObject.setMethodCalled2);
+ assertEquals(testDouble2, userObject.d);
+ assertEquals(testFloat, userObject.f);
+ assertNull(userObject.c);
+ }
+
+}
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/ContextFunctionHigh.java b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/ContextFunctionHigh.java
new file mode 100644
index 00000000000..f229460b3e7
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/ContextFunctionHigh.java
@@ -0,0 +1,11 @@
+package org.eclipse.e4.core.internal.tests.contexts;
+
+import org.eclipse.e4.core.contexts.ContextFunction;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+
+public class ContextFunctionHigh extends ContextFunction {
+ @Override
+ public Object compute(IEclipseContext context) {
+ return "High";
+ }
+}
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/ContextFunctionLow.java b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/ContextFunctionLow.java
new file mode 100644
index 00000000000..9e04f359f29
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/ContextFunctionLow.java
@@ -0,0 +1,11 @@
+package org.eclipse.e4.core.internal.tests.contexts;
+
+import org.eclipse.e4.core.contexts.ContextFunction;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+
+public class ContextFunctionLow extends ContextFunction {
+ @Override
+ public Object compute(IEclipseContext context) {
+ return "Low";
+ }
+}
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/DependenciesLeakTest.java b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/DependenciesLeakTest.java
new file mode 100644
index 00000000000..93a81efed7c
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/DependenciesLeakTest.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2015 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Stefan Mücke - initial API and implementation
+ * Lars Vogel - Bug 474274
+ *******************************************************************************/
+package org.eclipse.e4.core.internal.tests.contexts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.eclipse.e4.core.contexts.ContextFunction;
+import org.eclipse.e4.core.contexts.EclipseContextFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.internal.contexts.EclipseContext;
+import org.junit.Before;
+import org.junit.Test;
+
+@SuppressWarnings("restriction")
+public class DependenciesLeakTest {
+
+ final static String LEGACY_H_ID = "legacy::handler::"; //$NON-NLS-1$
+
+ static class HandlerSelectionFunction extends ContextFunction {
+ private final String commandId;
+ public HandlerSelectionFunction(String commandId) {
+ this.commandId = commandId;
+ }
+ @Override
+ public Object compute(IEclipseContext context, String contextKey) {
+ return context.get(LEGACY_H_ID + commandId);
+ }
+ @Override
+ public String toString() {
+ return "HandlerSelectionFunction [commandId=" + commandId + "]";
+ }
+ }
+
+ private IEclipseContext windowContext;
+ private IEclipseContext perspectiveContext;
+ private IEclipseContext partContext;
+
+ @Before
+ public void setUp() throws Exception {
+ windowContext = EclipseContextFactory.create("Window");
+ perspectiveContext = windowContext.createChild("Perspective");
+ partContext = perspectiveContext.createChild("Part");
+ }
+
+ @Test
+ public void testBug() {
+ // register a handler
+ Object handler = "";
+ windowContext.set("legacy::handler::foo.bar", handler); // fake activate legacy handler
+ windowContext.set("foo.bar", new HandlerSelectionFunction("foo.bar"));
+
+ // there may be no listeners initially
+ assertNoListeners(windowContext);
+ assertNoListeners(perspectiveContext);
+ assertNoListeners(partContext);
+
+ // cause a ValueComputation to be created
+ Object object = partContext.get("foo.bar");
+ assertEquals(object, handler);
+
+ // now invalidate the name; this should notify the part context
+ windowContext.set("foo.bar", null);
+ //windowContext.remove("foo.bar");
+
+ // all ValueComputation listeners must have been removed
+ assertNoListeners(windowContext);
+ assertNoListeners(perspectiveContext);
+ assertNoListeners(partContext);
+ }
+
+ @Test
+ public void testInvalidateDirectly() {
+ windowContext.set("x", 42);
+ windowContext.set("y", 11);
+ windowContext.set("some.handler", new AddContextFunction());
+ assertNoListeners(windowContext);
+ assertNoListeners(perspectiveContext);
+ assertNoListeners(partContext);
+
+ Object object = partContext.get("some.handler");
+ assertEquals(object, 53);
+
+ windowContext.set("some.handler", null); // invalidate
+ assertNoListeners(windowContext);
+ assertNoListeners(perspectiveContext);
+ assertNoListeners(partContext);
+ }
+
+ private void assertNoListeners(IEclipseContext context) {
+ EclipseContext c = (EclipseContext) context;
+ try {
+ assertTrue(c.getListeners().isEmpty());
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/EclipseContextTest.java b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/EclipseContextTest.java
new file mode 100644
index 00000000000..fe70d2d3143
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/EclipseContextTest.java
@@ -0,0 +1,397 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2021 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Lars Vogel - Bug 474274
+ *******************************************************************************/
+package org.eclipse.e4.core.internal.tests.contexts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import org.eclipse.e4.core.contexts.ContextFunction;
+import org.eclipse.e4.core.contexts.EclipseContextFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.contexts.RunAndTrack;
+import org.eclipse.e4.core.di.IInjector;
+import org.eclipse.e4.core.internal.contexts.EclipseContext;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.FrameworkUtil;
+
+@SuppressWarnings("restriction")
+public class EclipseContextTest {
+
+ private static class ComputedValueBar extends ContextFunction {
+ @Override
+ public Object compute(IEclipseContext context, String contextKey) {
+ return context.get("bar");
+ }
+ }
+
+ private IEclipseContext context;
+ private IEclipseContext parentContext;
+
+ private int runCounter;
+
+ @Before
+ public void setUp() throws Exception {
+ parentContext = EclipseContextFactory.create("EclipseContextTest" + "-parent");
+ context = parentContext.createChild("EclipseContextTest");
+ runCounter = 0;
+ }
+
+ @Test
+ public void testContainsKey() {
+ assertFalse("1.0", context.containsKey("function"));
+ assertFalse("1.1", context.containsKey("separator"));
+
+ context.set("separator", ",");
+ assertTrue("2.1", context.containsKey("separator"));
+
+ // null value is still a value
+ context.set("separator", null);
+ assertTrue("3.0", context.containsKey("separator"));
+
+ context.remove("separator");
+ assertFalse("4.0", context.containsKey("separator"));
+ }
+
+ @Test
+ public void testGet() {
+ assertNull(context.get("foo"));
+ context.set("foo", "bar");
+ assertEquals("bar", context.get("foo"));
+ assertNull(parentContext.get("foo"));
+ context.remove("foo");
+ assertNull(context.get("foo"));
+ parentContext.set("foo", "bar");
+ assertEquals("bar", context.get("foo"));
+ context.set("foo", new ComputedValueBar());
+ assertNull(context.get("foo"));
+ context.set("bar", "baz");
+ assertEquals("baz", context.get("foo"));
+ }
+
+ @Test
+ public void testGetLocal() {
+ assertNull(context.getLocal("foo"));
+ context.set("foo", "bar");
+ assertEquals("bar", context.getLocal("foo"));
+ assertNull(parentContext.getLocal("foo"));
+ context.remove("foo");
+ assertNull(context.getLocal("foo"));
+ parentContext.set("foo", "bar");
+ assertNull(context.getLocal("foo"));
+ context.set("foo", new ComputedValueBar());
+ assertNull(context.getLocal("foo"));
+ context.set("bar", "baz");
+ assertEquals("baz", context.getLocal("foo"));
+ }
+
+ /**
+ * Tests that a context no longer looks up values from its parent when disposed.
+ */
+ @Test
+ public void testDisposeRemovesParentReference() {
+ assertNull(context.get("foo"));
+ parentContext.set("foo", "bar");
+ assertEquals("bar", context.get("foo"));
+ context.dispose();
+ assertNull(context.get("foo"));
+ assertFalse(((EclipseContext) parentContext).getChildren().iterator().hasNext());
+ }
+
+ @Test
+ public void testDisposeClearsNotifyOnDisposalSet() {
+ ((EclipseContext) context).notifyOnDisposal(context -> runCounter++);
+ context.dispose();
+ assertEquals(1, runCounter);
+ context.dispose();
+ assertEquals(1, runCounter);
+ }
+
+ /**
+ * Tests handling of a context function defined in the parent that uses values defined in the
+ * child
+ */
+ @Test
+ public void testContextFunctionInParent() {
+ IEclipseContext parent = EclipseContextFactory.create();
+ final IEclipseContext child = parent.createChild();
+ parent.set("sum", new AddContextFunction());
+ parent.set("x", Integer.valueOf(3));
+ parent.set("y", Integer.valueOf(3));
+ child.set("x", Integer.valueOf(1));
+ child.set("y", Integer.valueOf(1));
+ assertEquals(6, ((Integer) parent.get("sum")).intValue());
+ assertEquals(2, ((Integer) child.get("sum")).intValue());
+ child.set("x", Integer.valueOf(5));
+ assertEquals(6, ((Integer) parent.get("sum")).intValue());
+ assertEquals(6, ((Integer) child.get("sum")).intValue());
+ child.remove("x");
+ assertEquals(6, ((Integer) parent.get("sum")).intValue());
+ assertEquals(4, ((Integer) child.get("sum")).intValue());
+ parent.set("x", Integer.valueOf(10));
+ assertEquals(13, ((Integer) parent.get("sum")).intValue());
+ assertEquals(11, ((Integer) child.get("sum")).intValue());
+ }
+
+ @Test
+ public void testRunAndTrack() {
+ final Object[] value = new Object[1];
+ context.runAndTrack(new RunAndTrack() {
+ @Override
+ public boolean changed(IEclipseContext context) {
+ runCounter++;
+ value[0] = context.get("foo");
+ return true;
+ }
+ });
+ assertEquals(1, runCounter);
+ assertEquals(null, value[0]);
+ context.set("foo", "bar");
+ assertEquals(2, runCounter);
+ assertEquals("bar", value[0]);
+ context.remove("foo");
+ assertEquals(3, runCounter);
+ assertEquals(null, value[0]);
+ context.set("foo", new ContextFunction() {
+ @Override
+ public Object compute(IEclipseContext context, String contextKey) {
+ return context.get("bar");
+ }
+ });
+ assertEquals(4, runCounter);
+ assertEquals(null, value[0]);
+ context.set("bar", "baz");
+ assertEquals(5, runCounter);
+ assertEquals("baz", value[0]);
+ context.set("bar", "baf");
+ assertEquals(6, runCounter);
+ assertEquals("baf", value[0]);
+ context.remove("bar");
+ assertEquals(7, runCounter);
+ assertEquals(null, value[0]);
+ parentContext.set("bar", "bam");
+ assertEquals(8, runCounter);
+ assertEquals("bam", value[0]);
+ }
+
+ /**
+ * Tests registering a single run and track instance multiple times with the same context.
+ */
+ @Test
+ public void testRegisterRunAndTrackTwice() {
+ final Object[] value = new Object[1];
+ RunAndTrack runnable = new RunAndTrack() {
+ @Override
+ public boolean changed(IEclipseContext context) {
+ runCounter++;
+ value[0] = context.get("foo");
+ return true;
+ }
+ };
+ context.runAndTrack(runnable);
+ assertEquals(1, runCounter);
+ context.runAndTrack(runnable);
+ assertEquals(2, runCounter);
+ assertEquals(null, value[0]);
+ context.set("foo", "bar");
+ assertEquals(3, runCounter);
+ assertEquals("bar", value[0]);
+ context.remove("foo");
+ assertEquals(4, runCounter);
+
+ }
+
+ @Test
+ public void testRunAndTrackMultipleValues() {
+ IEclipseContext parent = EclipseContextFactory.create("ParentContext");
+ final IEclipseContext child = parent.createChild("ChildContext");
+ parent.set("parentValue", "x");
+ child.set("childValue", "x");
+ RunAndTrack runnable = new RunAndTrack() {
+ @Override
+ public boolean changed(IEclipseContext context) {
+ runCounter++;
+ if (runCounter < 2) {
+ child.get("childValue");
+ return true;
+ }
+ if (runCounter < 3) {
+ child.get("parentValue");
+ return true;
+ }
+ return false;
+ }
+ };
+ child.runAndTrack(runnable);
+ assertEquals(1, runCounter);
+ child.set("childValue", "z");
+ assertEquals(2, runCounter);
+ parent.set("parentValue", "z");
+ assertEquals(3, runCounter);
+ }
+
+ @Test
+ public void testModify() {
+ IEclipseContext grandParent = EclipseContextFactory.create();
+ IEclipseContext parent = grandParent.createChild();
+ IEclipseContext child = parent.createChild();
+
+ child.set("a", "a1");
+ parent.set("b", "b2");
+ grandParent.set("c", "c3");
+
+ child.declareModifiable("a");
+ parent.declareModifiable("b");
+ grandParent.declareModifiable("c");
+
+ // test pre-conditions
+ assertNull(grandParent.get("b"));
+ assertEquals("b2", parent.get("b"));
+ assertEquals("b2", child.get("b"));
+ assertNull(child.getLocal("b"));
+
+ // modify value on the middle node via its child
+ child.modify("b", "abc");
+
+ assertFalse(grandParent.containsKey("b"));
+ assertEquals("abc", parent.get("b"));
+ assertEquals("abc", child.get("b"));
+ assertNull(child.getLocal("b"));
+
+ // modifying non-exist values adds it to the context
+ child.modify("d", "123");
+
+ assertFalse(grandParent.containsKey("d"));
+ assertFalse(parent.containsKey("d"));
+ assertNull(parent.get("d"));
+ assertEquals("123", child.get("d"));
+
+ // edge conditions: modify value in the top node
+ grandParent.modify("c", "cNew");
+ assertTrue(grandParent.containsKey("c"));
+ assertEquals("cNew", grandParent.get("c"));
+ assertNull(parent.getLocal("c"));
+ assertNull(child.getLocal("c"));
+ assertTrue(child.containsKey("c"));
+
+ // edge condition: modify value in the leaf node
+ child.modify("a", "aNew");
+ assertTrue(child.containsKey("a"));
+ assertFalse(parent.containsKey("a"));
+ assertFalse(grandParent.containsKey("a"));
+ assertEquals("aNew", child.get("a"));
+ assertNull(parent.get("a"));
+
+ // test access rules
+ child.set("aNo", "a1");
+ parent.set("bNo", "b2");
+ grandParent.set("cNo", "c3");
+
+ boolean exception = false;
+ try {
+ child.modify("bNo", "new");
+ } catch (IllegalArgumentException e) {
+ exception = true;
+ }
+ assertTrue(exception);
+
+ exception = false;
+ try {
+ grandParent.modify("cNo", "new");
+ } catch (IllegalArgumentException e) {
+ exception = true;
+ }
+ assertTrue(exception);
+
+ exception = false;
+ try {
+ child.modify("aNo", "new");
+ } catch (IllegalArgumentException e) {
+ exception = true;
+ }
+ assertTrue(exception);
+ }
+
+ @Test
+ public void testRemoveValueComputationOnDispose() {
+ IEclipseContext parent = EclipseContextFactory.create("ParentContext");
+ IEclipseContext child = parent.createChild("ChildContext");
+ parent.set("x", Integer.valueOf(1));
+ parent.set("y", Integer.valueOf(1));
+ parent.set("sum", new AddContextFunction());
+
+ child.get("sum");
+ assertEquals(1, listenersCount(child));
+ child.dispose();
+ assertEquals(0, listenersCount(parent));
+ }
+
+ @Test
+ public void testNullInheritance() {
+ IEclipseContext parent = EclipseContextFactory.create("ParentContext");
+ IEclipseContext child = parent.createChild("ChildContext");
+ parent.set("x", Integer.valueOf(1));
+ child.set("x", null);
+ assertNull(child.get("x"));
+ }
+
+ @Test
+ public void testGetCFNotAValue() {
+ IEclipseContext context = EclipseContextFactory.create("ParentContext");
+ context.set("x", new ContextFunction() {
+
+ @Override
+ public Object compute(IEclipseContext context, String contextKey) {
+ return IInjector.NOT_A_VALUE;
+ }
+ });
+
+ // must call several times as the underlying ValueComputation wrapper is
+ // created on the first time, but re-used for subsequent calls.
+ assertNull(context.get("x"));
+ assertNull(context.get("x"));
+ assertNull(context.get("x"));
+ context.dispose();
+ }
+
+ @Test
+ public void testGetCFNotAValueToParent() {
+ IEclipseContext parent = EclipseContextFactory.create("ParentContext");
+ IEclipseContext child = parent.createChild();
+ parent.set("x", Integer.valueOf(1));
+ child.set("x", new ContextFunction() {
+
+ @Override
+ public Object compute(IEclipseContext context, String contextKey) {
+ return IInjector.NOT_A_VALUE;
+ }
+ });
+
+ assertEquals(1, child.get("x"));
+ parent.dispose();
+ }
+
+ @Test
+ public void testContextFunctionOrdering() {
+ IEclipseContext osgiContext = EclipseContextFactory.getServiceContext(FrameworkUtil.getBundle(getClass()).getBundleContext());
+ assertEquals("High",osgiContext.get("test.contextfunction.ranking"));
+ }
+
+ private int listenersCount(IEclipseContext context) {
+ return ((EclipseContext) context).getListeners().size();
+ }
+}
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/NeutralValueTest.java b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/NeutralValueTest.java
new file mode 100644
index 00000000000..66ac56ba490
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/NeutralValueTest.java
@@ -0,0 +1,206 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Joerg Kubitz.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Joerg Kubitz - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.e4.core.internal.tests.contexts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.e4.core.internal.contexts.ConcurrentNeutralValueMap;
+import org.eclipse.e4.core.internal.contexts.ConcurrentNeutralValueMap.Value;
+import org.junit.Test;
+
+@SuppressWarnings("restriction")
+public class NeutralValueTest {
+
+ @Test
+ public void testConcurrentNeutralValueMap() {
+ ConcurrentNeutralValueMap map = new ConcurrentNeutralValueMap<>(Double.NaN);
+ map.put("nix", null); // modify
+ map.put("2", 2.0); // modify
+ map.put("3", 3.0); // modify
+ map.put("4", 4.0); // modify
+ map.put("garnix", null); // modify
+ assertTrue(map.containsKey("garnix"));
+ map.remove("garnix");
+
+ assertTrue(map.containsKey("nix"));
+ assertTrue(map.containsKey("2"));
+ assertFalse(map.containsKey("1"));
+ assertFalse(map.containsKey("garnix"));
+
+ assertEquals(4, map.size());
+
+ assertFalse(map.isEmpty());
+
+ assertEquals(null, map.get("nix"));
+ assertEquals(null, map.get("1"));
+ assertEquals(Double.valueOf(2.0), map.get("2"));
+ assertEquals(Double.valueOf(3.0), map.get("3"));
+ assertEquals(Double.valueOf(4.0), map.get("4"));
+
+ Set keys = new HashSet<>();
+ Set values = new HashSet<>();
+ map.forEach((k, v) -> keys.add(k));
+ map.forEach((k, v) -> values.add(v));
+ assertEquals(Set.of("nix", "2", "3", "4"), keys);
+ assertTrue(values.contains(null));
+ assertTrue(values.contains(2.0));
+
+ assertTrue(map.getValue("nix").isPresent());
+ assertFalse(map.getValue("1").isPresent());
+ assertTrue(map.getValue("2").isPresent());
+ assertTrue(map.getValue("3").isPresent());
+ assertTrue(map.getValue("4").isPresent());
+
+ {
+ Value v = map.getValue("nix");
+ assertTrue(v.isPresent());
+ assertEquals(null, v.unwrapped());
+ }
+ {
+ Value v = map.getValue("1");
+ assertFalse(v.isPresent());
+ assertEquals(null, v.unwrapped());
+ }
+ {
+ Value v = map.getValue("2");
+ assertTrue(v.isPresent());
+ assertEquals(Double.valueOf(2.0), v.unwrapped());
+ }
+
+ {
+ Value v = map.putAndGetOld("5", 5555.0); // modify
+ assertFalse(v.isPresent());
+ assertEquals(null, v.unwrapped());
+ assertEquals(Double.valueOf(5555.0), map.get("5"));
+ }
+ {
+ Value v = map.putAndGetOld("5", 5.0); // modify
+ assertTrue(v.isPresent());
+ assertEquals(Double.valueOf(5555.0), v.unwrapped());
+ assertEquals(Double.valueOf(5.0), map.get("5"));
+ }
+ map.putIfAbsent("5", 5555.0); // modify
+ assertEquals(Double.valueOf(5.0), map.get("5"));
+ map.remove("5"); // modify
+ assertFalse(map.containsKey("5"));
+
+ {
+ Value v = map.putAndGetOld("five", null); // modify
+ assertFalse(v.isPresent());
+ assertEquals(null, v.unwrapped());
+ assertEquals(null, map.get("five"));
+ }
+ {
+ Value v = map.putAndGetOld("five", 5.0); // modify
+ assertTrue(v.isPresent());
+ assertEquals(null, v.unwrapped());
+ assertEquals(Double.valueOf(5.0), map.get("five"));
+ }
+ {
+ map.putIfAbsent("five", null); // modify
+ Value v = map.getValue("five");
+ assertTrue(v.isPresent());
+ assertEquals(Double.valueOf(5.0), v.unwrapped());
+ }
+ map.remove("five"); // modify
+ {
+ map.putIfAbsent("five", null); // modify
+ Value v = map.getValue("five");
+ assertTrue(v.isPresent());
+ assertEquals(null, v.unwrapped());
+ }
+ map.remove("five"); // modify
+ assertFalse(map.containsKey("five"));
+
+ map.clear(); // modify
+ assertEquals(0, map.size());
+ assertTrue(map.isEmpty());
+ }
+
+ @Test
+ public void testToString() {
+ ConcurrentNeutralValueMap map1 = new ConcurrentNeutralValueMap<>();
+ map1.put("0", 0f);
+ map1.put("NULL", null);
+ map1.put("nothing", null);
+ map1.put("1", 1f);
+ map1.put("~2", 2.1f);
+ assertTrue(map1.toString().contains("0=0.0"));
+ assertTrue(map1.toString().contains("1=1.0"));
+ assertTrue(map1.toString().contains("~2=2.1"));
+ assertTrue(map1.toString().contains("NULL=null"));
+ assertTrue(map1.toString().contains("nothing=null"));
+ }
+
+ @Test
+ public void testCustomToString() {
+ ConcurrentNeutralValueMap map1 = new ConcurrentNeutralValueMap<>(Float.NaN);
+ map1.put("0", 0f);
+ map1.put("NULL", null);
+ assertTrue(map1.toString().contains("0=0.0"));
+ assertTrue(map1.toString().contains("NULL=NaN"));
+ }
+
+ @Test
+ public void testEquals() {
+ {
+ ConcurrentNeutralValueMap map1 = new ConcurrentNeutralValueMap<>();
+ ConcurrentNeutralValueMap map2 = new ConcurrentNeutralValueMap<>();
+ map1.put("0", 0f);
+ map1.put("NULL", null);
+ map2.put("NULL", null);
+ map2.put("0", 0f);
+ assertEquals(map1.hashCode(), map2.hashCode());
+ assertEquals(map1, map2);
+ }
+ {
+ ConcurrentNeutralValueMap map1 = new ConcurrentNeutralValueMap<>();
+ ConcurrentNeutralValueMap map2 = new ConcurrentNeutralValueMap<>();
+ map1.put("0", 0f);
+ map1.put("1", 1f);
+ map1.put("NULL", null);
+ map2.put("NULL", null);
+ map2.put("0", 0f);
+ assertNotEquals(map1.hashCode(), map2.hashCode());
+ assertNotEquals(map1, map2);
+ }
+ {
+ ConcurrentNeutralValueMap map1 = new ConcurrentNeutralValueMap<>(Float.NaN);
+ ConcurrentNeutralValueMap map2 = new ConcurrentNeutralValueMap<>(Float.NaN);
+ map1.put("0", 0f);
+ map1.put("NULL", null);
+ map2.put("NULL", null);
+ map2.put("0", 0f);
+ assertEquals(map1.hashCode(), map2.hashCode());
+ assertEquals(map1, map2);
+ }
+ {
+ ConcurrentNeutralValueMap map1 = new ConcurrentNeutralValueMap<>(Float.NaN);
+ ConcurrentNeutralValueMap map2 = new ConcurrentNeutralValueMap<>(Float.NaN);
+ map1.put("0", 0f);
+ map1.put("1", 1f);
+ map1.put("NULL", null);
+ map2.put("NULL", null);
+ map2.put("0", 0f);
+ assertNotEquals(map1.hashCode(), map2.hashCode());
+ assertNotEquals(map1, map2);
+ }
+ }
+}
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/ReparentingTest.java b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/ReparentingTest.java
new file mode 100644
index 00000000000..3476abb11c2
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/ReparentingTest.java
@@ -0,0 +1,387 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2015 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Lars Vogel - Bug 474274
+ ******************************************************************************/
+
+package org.eclipse.e4.core.internal.tests.contexts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.eclipse.e4.core.contexts.ContextFunction;
+import org.eclipse.e4.core.contexts.ContextInjectionFactory;
+import org.eclipse.e4.core.contexts.EclipseContextFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.contexts.RunAndTrack;
+import org.eclipse.e4.core.internal.tests.contexts.inject.ObjectSuperClass;
+import org.junit.Test;
+
+/**
+ * Test for changing a context's parent.
+ */
+public class ReparentingTest {
+
+
+ /**
+ * Tests handling of a context function defined in the parent when the parent is changed to no
+ * longer have the function.
+ */
+ @Test
+ public void testContextFunctionInParentRemove() {
+ IEclipseContext parent = EclipseContextFactory.create("parent");
+ final IEclipseContext child = parent.createChild("child");
+ parent.set("sum", new AddContextFunction());
+ parent.set("x", Integer.valueOf(3));
+ parent.set("y", Integer.valueOf(3));
+ child.set("x", Integer.valueOf(1));
+ child.set("y", Integer.valueOf(1));
+ assertEquals(6, ((Integer) parent.get("sum")).intValue());
+ assertEquals(2, ((Integer) child.get("sum")).intValue());
+ child.setParent(EclipseContextFactory.create());
+ assertEquals(6, ((Integer) parent.get("sum")).intValue());
+ assertNull("Expected null but was: " + child.get("sum"), child.get("sum"));
+ }
+
+ /**
+ * Tests handling of a context function defined in the parent when the parent is changed to have
+ * the function
+ */
+ @Test
+ public void testContextFunctionInParentAdd() {
+ // setup
+ IEclipseContext parent = EclipseContextFactory.create();
+ final IEclipseContext child = parent.createChild();
+ child.set("x", Integer.valueOf(1));
+ child.set("y", Integer.valueOf(1));
+ assertEquals(null, parent.get("sum"));
+ assertEquals(null, child.get("sum"));
+
+ // switch parent
+ IEclipseContext newParent = EclipseContextFactory.create();
+ child.setParent(newParent);
+ newParent.set("sum", new AddContextFunction());
+ assertEquals(0, ((Integer) newParent.get("sum")).intValue());
+ assertEquals(2, ((Integer) child.get("sum")).intValue());
+
+ // changed values in parent shouldn't affect child
+ newParent.set("x", Integer.valueOf(3));
+ newParent.set("y", Integer.valueOf(3));
+ assertEquals(6, ((Integer) newParent.get("sum")).intValue());
+ assertEquals(2, ((Integer) child.get("sum")).intValue());
+ }
+
+ @Test
+ public void testContextFunctionNullBecomeParent() {
+ final IEclipseContext child = EclipseContextFactory.create();
+ child.set("sum", new AddContextFunction());
+ assertEquals(0, ((Integer) child.get("sum")).intValue());
+ IEclipseContext parent = EclipseContextFactory.create();
+ parent.set("x", Integer.valueOf(3));
+ parent.set("y", Integer.valueOf(3));
+ child.setParent(parent);
+ assertEquals(6, ((Integer) child.get("sum")).intValue());
+
+ }
+
+ @Test
+ public void testContextFunctionParentBecomeNull() {
+ IEclipseContext parent = EclipseContextFactory.create();
+ final IEclipseContext child = parent.createChild();
+ parent.set("x", Integer.valueOf(3));
+ parent.set("y", Integer.valueOf(3));
+ child.set("sum", new AddContextFunction());
+ assertEquals(6, ((Integer) child.get("sum")).intValue());
+ child.setParent(null);
+ assertEquals(0, ((Integer) child.get("sum")).intValue());
+ }
+
+ @Test
+ public void testContextFunctionSwitchParent() {
+ IEclipseContext parent = EclipseContextFactory.create();
+ final IEclipseContext child = parent.createChild();
+ parent.set("x", Integer.valueOf(3));
+ parent.set("y", Integer.valueOf(3));
+ child.set("sum", new AddContextFunction());
+ assertEquals(6, ((Integer) child.get("sum")).intValue());
+ IEclipseContext newParent = EclipseContextFactory.create();
+ newParent.set("x", Integer.valueOf(1));
+ newParent.set("y", Integer.valueOf(1));
+ child.setParent(newParent);
+ assertEquals(2, ((Integer) child.get("sum")).intValue());
+ }
+
+ /**
+ * Tests a child switching from a null parent to a non-null parent.
+ */
+ @Test
+ public void testRunAndTrackNullBecomesParent() {
+ final String[] value = new String[1];
+ final IEclipseContext child = EclipseContextFactory.create();
+ child.runAndTrack(new RunAndTrack() {
+ @Override
+ public boolean changed(IEclipseContext context) {
+ value[0] = (String) child.get("x");
+ return true;
+ }
+ });
+ assertEquals(null, value[0]);
+ IEclipseContext parent = EclipseContextFactory.create();
+ parent.set("x", "newParent");
+ child.setParent(parent);
+ assertEquals("newParent", value[0]);
+ }
+
+ /**
+ * Tests a child switching from a non-null parent to a null parent.
+ */
+ @Test
+ public void testRunAndTrackParentBecomeNull() {
+ final String[] value = new String[1];
+ IEclipseContext parent = EclipseContextFactory.create();
+ final IEclipseContext child = parent.createChild();
+ parent.set("x", "oldParent");
+ child.runAndTrack(new RunAndTrack() {
+ @Override
+ public boolean changed(IEclipseContext context) {
+ value[0] = (String) child.get("x");
+ return true;
+ }
+ });
+ assertEquals("oldParent", value[0]);
+ child.setParent(null);
+ assertNull(value[0]);
+ }
+
+ @Test
+ public void testRunAndTrackSwitchParent() {
+ final String[] value = new String[1];
+ IEclipseContext parent = EclipseContextFactory.create();
+ final IEclipseContext child = parent.createChild();
+ parent.set("x", "oldParent");
+ child.runAndTrack(new RunAndTrack() {
+ @Override
+ public boolean changed(IEclipseContext context) {
+ value[0] = (String) child.get("x");
+ return true;
+ }
+ });
+ assertEquals("oldParent", value[0]);
+ IEclipseContext newParent = EclipseContextFactory.create();
+ newParent.set("x", "newParent");
+ child.setParent(newParent);
+ assertEquals("newParent", value[0]);
+ }
+
+ /**
+ * Tests an object consuming simple values from a parent context, and a parent change causes a
+ * change in simple values. TODO: Still fails
+ */
+ @Test
+ public void testInjectSwitchParent() {
+
+ IEclipseContext oldParent = EclipseContextFactory.create();
+ oldParent.set("String", "oldField");
+ oldParent.set(String.class.getName(), "old");
+ oldParent.set(Float.class.getName(), Float.valueOf(12.3f));
+ IEclipseContext newParent = EclipseContextFactory.create();
+ newParent.set("String", "newField");
+ newParent.set(String.class.getName(), "new");
+ newParent.set(Float.class.getName(), Float.valueOf(34.5f));
+ IEclipseContext child = oldParent.createChild();
+
+ ObjectSuperClass object = new ObjectSuperClass();
+ ContextInjectionFactory.inject(object, child);
+ assertEquals(1, object.setStringCalled);
+ assertEquals("old", object.getStringViaMethod());
+
+ child.setParent(newParent);
+ assertEquals("new", object.getStringViaMethod());
+ assertEquals(2, object.setStringCalled);
+
+ }
+
+ /**
+ * Tests an object consuming services from a grandparent. A parent switch where the grandparent
+ * stays unchanged should ideally not cause changes for the injected object.
+ */
+ @Test
+ public void testInjectSwitchParentSameGrandparent() {
+ IEclipseContext grandpa = EclipseContextFactory.create();
+ grandpa.set("String", "field");
+ grandpa.set(String.class.getName(), "s");
+ grandpa.set(Float.class.getName(), Float.valueOf(12.3f));
+
+ IEclipseContext oldParent = grandpa.createChild();
+ IEclipseContext newParent = grandpa.createChild();
+ IEclipseContext child = oldParent.createChild();
+
+ ObjectSuperClass object = new ObjectSuperClass();
+ ContextInjectionFactory.inject(object, child);
+ assertEquals(1, object.setStringCalled);
+
+ child.setParent(newParent);
+ assertEquals(1, object.setStringCalled);
+ }
+
+ @Test
+ public void testUpdateSameParent() {
+ final Boolean[] called = new Boolean[1] ;
+ IEclipseContext parent = EclipseContextFactory.create("parent");
+ IEclipseContext newParent = EclipseContextFactory.create("newParent");
+ IEclipseContext child = parent.createChild("child");
+ parent.set("x", "1");
+ newParent.set("x", "2");
+
+ child.runAndTrack(new RunAndTrack() {
+ @Override
+ public boolean changed(IEclipseContext context) {
+ called[0] = true;
+ context.get("x"); // creates a link
+ return true;
+ }
+ });
+ called[0] = false;
+
+ // make sure setting parent to the same value does not trigger updates
+ child.setParent(parent);
+ assertFalse(called[0]);
+
+ child.setParent(newParent);
+ assertTrue(called[0]);
+ }
+
+ static public class TestService {
+ // empty
+ }
+
+ @Test
+ public void testUpdateSameParentCalculated() {
+ final int[] testServiceCount = new int[1];
+ testServiceCount[0] = 0;
+ IEclipseContext parentContext = EclipseContextFactory.create("parent");
+ parentContext.set(TestService.class.getName(), new ContextFunction() {
+ @Override
+ public Object compute(IEclipseContext context, String contextKey) {
+ testServiceCount[0]++;
+ return ContextInjectionFactory.make(TestService.class, context);
+ }
+ });
+
+ IEclipseContext childContext = parentContext.createChild("child");
+ childContext.get(TestService.class);
+ assertEquals(1, testServiceCount[0]);
+
+ childContext.setParent(childContext.getParent());
+ assertEquals(1, testServiceCount[0]);
+ }
+
+ @Test
+ public void testBug468048_contextFunction() {
+ IEclipseContext p1 = EclipseContextFactory.create("parent1");
+ p1.set("sample", new ContextFunction() {
+ @Override
+ public Object compute(IEclipseContext context) {
+ return Integer.valueOf(1);
+ }
+ });
+
+ IEclipseContext p2 = EclipseContextFactory.create("parent2");
+ p2.set("sample", new ContextFunction() {
+ @Override
+ public Object compute(IEclipseContext context) {
+ return Integer.valueOf(2);
+ }
+ });
+
+ final IEclipseContext intermed = p1.createChild("intermed");
+
+ final IEclipseContext leaf = intermed.createChild("leaf");
+ assertEquals(Integer.valueOf(1), leaf.get("sample"));
+ intermed.setParent(p2);
+ assertEquals(Integer.valueOf(2), leaf.get("sample"));
+ }
+
+ @Test
+ public void testBug468048_injection() {
+ IEclipseContext p1 = EclipseContextFactory.create("parent1");
+ p1.set("sample", new ContextFunction() {
+ @Override
+ public Object compute(IEclipseContext context) {
+ return Integer.valueOf(1);
+ }
+ });
+
+ IEclipseContext p2 = EclipseContextFactory.create("parent2");
+ p2.set("sample", new ContextFunction() {
+ @Override
+ public Object compute(IEclipseContext context) {
+ return Integer.valueOf(2);
+ }
+ });
+
+ final IEclipseContext intermed = p1.createChild("intermed");
+
+ final IEclipseContext leaf = intermed.createChild("leaf");
+ Bug468048 b = ContextInjectionFactory.make(Bug468048.class, leaf);
+
+ assertEquals(Integer.valueOf(1), b.sample);
+ intermed.setParent(p2);
+ assertEquals(Integer.valueOf(2), b.sample);
+ }
+
+ @Test
+ public void testContextFunctionSwitchParent_2() {
+ IEclipseContext superParent = EclipseContextFactory.create("root");
+
+ IEclipseContext parent = superParent.createChild("parent-1");
+ final IEclipseContext child = parent.createChild("child-1");
+ child.set("x", Integer.valueOf(3));
+ child.set("y", Integer.valueOf(3));
+
+ superParent.set("sum", new ContextFunction() {
+ @Override
+ public Object compute(IEclipseContext context, String contextKey) {
+ if (context != child) {
+ throw new IllegalStateException("Invalid context state");
+ }
+ return (Integer) context.get("x") + (Integer) context.get("y");
+ }
+ });
+
+ Bug541498 bug = ContextInjectionFactory.make(Bug541498.class, child);
+ assertEquals(Integer.valueOf(6), bug.value);
+
+ IEclipseContext newParent = superParent.createChild("parent-2");
+ child.setParent(newParent);
+
+ assertEquals(Integer.valueOf(6), bug.value);
+ }
+
+ public static class Bug541498 {
+ @Inject
+ @Named("sum")
+ Integer value;
+ }
+
+ public static class Bug468048 {
+ @Inject
+ @Named("sample")
+ public Integer sample;
+
+ }
+}
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/RunAndTrackTest.java b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/RunAndTrackTest.java
new file mode 100644
index 00000000000..96eded7070b
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/RunAndTrackTest.java
@@ -0,0 +1,433 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2015 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Lars Vogel - Bug 474274
+ ******************************************************************************/
+
+package org.eclipse.e4.core.internal.tests.contexts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.e4.core.contexts.ContextFunction;
+import org.eclipse.e4.core.contexts.EclipseContextFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.contexts.RunAndTrack;
+import org.eclipse.e4.core.internal.tests.CoreTestsActivator;
+import org.junit.After;
+import org.junit.Test;
+
+/**
+ * Tests for {@link org.eclipse.e4.core.RunAndTrack.context.IRunAndTrack}.
+ */
+public class RunAndTrackTest {
+
+ private static final class TestRAT extends RunAndTrack {
+
+
+ private final String varName;
+ private Object varValue;
+ private int calls = 0;
+
+ public TestRAT(String varName) {
+ this.varName = varName;
+ }
+
+ @Override
+ public boolean changed(IEclipseContext context) {
+ ++calls;
+ varValue = context.get(varName);
+ return true;
+ }
+
+ public int getCalls() {
+ return calls;
+ }
+
+ public Object getVarValue() {
+ return varValue;
+ }
+
+ public void resetCalls() {
+ calls = 0;
+ }
+
+ }
+
+ private static class ActivePartLookupFunction extends ContextFunction {
+
+ @Override
+ public Object compute(IEclipseContext context, String contextKey) {
+ IEclipseContext childContext = (IEclipseContext) context.getLocal(ACTIVE_CHILD);
+ if (childContext != null) {
+ return childContext.get(ACTIVE_PART);
+ }
+ return context.get(INTERNAL_LOCAL_PART);
+ }
+
+ }
+
+ static final String ACTIVE_CHILD = "activeChild";
+
+ static final String ACTIVE_PART = "activePart";
+
+ static final String ACTIVE_PART_ID = "activePartId";
+
+ static final String INTERNAL_LOCAL_PART = "localPart";
+
+ private final List createdContexts = new ArrayList<>();
+
+ private IEclipseContext createContext(IEclipseContext parentContext, String level) {
+ IEclipseContext childContext = parentContext.createChild(level);
+ createdContexts.add(childContext);
+ return childContext;
+ }
+
+ private IEclipseContext getGlobalContext() {
+ IEclipseContext serviceContext = EclipseContextFactory
+ .getServiceContext(CoreTestsActivator.getDefault().getBundleContext());
+ // global initialization and setup, usually done by workbench
+ IEclipseContext appContext = createContext(serviceContext, "globalContext");
+
+ appContext.set("globalContext", appContext);
+
+ return appContext;
+ }
+
+ private IEclipseContext[] createNextLevel(IEclipseContext parent, String prefix, int num) {
+ assertTrue(num > 0);
+ IEclipseContext[] contexts = new IEclipseContext[num];
+ for (int i = 0; i < num; i++) {
+ contexts[i] = createContext(parent, prefix + i);
+ contexts[i].set(INTERNAL_LOCAL_PART, prefix + i);
+ }
+ parent.set(ACTIVE_CHILD, contexts[0]);
+ return contexts;
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ for (IEclipseContext context : createdContexts) {
+ context.dispose();
+ }
+ createdContexts.clear();
+ }
+
+ @Test
+ public void testActiveChain() throws Exception {
+ final IEclipseContext workbenchContext = getGlobalContext();
+ workbenchContext.set("activePart", new ActivePartLookupFunction());
+ final IEclipseContext[] windows = createNextLevel(workbenchContext, "window", 1);
+ createNextLevel(windows[0], "part", 2);
+ assertEquals("part0", workbenchContext.get(ACTIVE_PART));
+ }
+
+ @Test
+ public void testActiveChange() throws Exception {
+ final IEclipseContext workbenchContext = getGlobalContext();
+ workbenchContext.set("activePart", new ActivePartLookupFunction());
+ final IEclipseContext[] windows = createNextLevel(workbenchContext, "window", 1);
+ final IEclipseContext[] parts = createNextLevel(windows[0], "part", 2);
+ assertEquals("part0", workbenchContext.get(ACTIVE_PART));
+
+ windows[0].set(ACTIVE_CHILD, parts[1]);
+ assertEquals("part1", workbenchContext.get(ACTIVE_PART));
+ }
+
+ /**
+ * There was a failing scenario in the legacy workbench support. This captures the hierarchy and
+ * function (without any workbench level references). It should be updated when we figure out
+ * the failing scenario :-)
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testRunAndTrackComplex() throws Exception {
+ final IEclipseContext workbenchContext = getGlobalContext();
+ workbenchContext.set("activePart", new ActivePartLookupFunction());
+ final IEclipseContext[] windows = createNextLevel(workbenchContext, "window", 1);
+ windows[0].runAndTrack(new RunAndTrack() {
+ @Override
+ public boolean changed(IEclipseContext context) {
+ final Object part = windows[0].get(ACTIVE_PART);
+ windows[0].set(ACTIVE_PART_ID, part);
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return ACTIVE_PART_ID;
+ }
+ });
+
+ final IEclipseContext[] mainSashes = createNextLevel(windows[0], "mainSash", 2);
+ createNextLevel(mainSashes[1], "editorArea", 1);
+ final IEclipseContext[] viewSashes = createNextLevel(mainSashes[0], "viewSashes", 2);
+
+ // create package explorer stack
+ final IEclipseContext[] packageStack = createNextLevel(viewSashes[0], "packageStack", 1);
+ final IEclipseContext[] packageViews = createNextLevel(packageStack[0], "packageViews", 3);
+ assertNotNull(packageViews);
+ assertEquals("packageViews0", windows[0].get(ACTIVE_PART));
+ assertEquals("packageViews0", windows[0].get(ACTIVE_PART_ID));
+
+ // create problems stack
+ final IEclipseContext[] problemsStack = createNextLevel(viewSashes[1], "problemsStack", 1);
+ final IEclipseContext[] problemsViews = createNextLevel(problemsStack[0], "problemViews", 5);
+ assertNotNull(problemsViews);
+ assertEquals("packageViews0", windows[0].get(ACTIVE_PART));
+ assertEquals("packageViews0", windows[0].get(ACTIVE_PART_ID));
+
+ assertEquals("problemViews0", problemsStack[0].get(ACTIVE_PART));
+ // this won't change since it is a "runAndTrack" at the window context
+ // level
+ assertEquals("packageViews0", problemsStack[0].get(ACTIVE_PART_ID));
+
+ // set the "problems view" active, propagating the information up
+ // the active chain.
+ problemsStack[0].set(ACTIVE_CHILD, problemsViews[0]);
+ viewSashes[1].set(ACTIVE_CHILD, problemsStack[0]);
+ mainSashes[0].set(ACTIVE_CHILD, viewSashes[1]);
+ windows[0].set(ACTIVE_CHILD, mainSashes[0]);
+ workbenchContext.set(ACTIVE_CHILD, windows[0]);
+
+ assertEquals("problemViews0", windows[0].get(ACTIVE_PART));
+ assertEquals("problemViews0", windows[0].get(ACTIVE_PART_ID));
+
+ assertEquals("packageViews0", packageStack[0].get(ACTIVE_PART));
+ assertEquals("problemViews0", packageStack[0].get(ACTIVE_PART_ID));
+ }
+
+ @Test
+ public void testRunAndTrackSimple() throws Exception {
+ final IEclipseContext workbenchContext = getGlobalContext();
+ workbenchContext.set("activePart", new ActivePartLookupFunction());
+ final IEclipseContext[] windows = createNextLevel(workbenchContext, "window", 1);
+ windows[0].runAndTrack(new RunAndTrack() {
+ @Override
+ public boolean changed(IEclipseContext context) {
+ final Object part = windows[0].get(ACTIVE_PART);
+ windows[0].set(ACTIVE_PART_ID, part);
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return ACTIVE_PART_ID;
+ }
+ });
+
+ final IEclipseContext[] parts = createNextLevel(windows[0], "part", 2);
+ assertEquals("part0", workbenchContext.get(ACTIVE_PART));
+ assertEquals("part0", windows[0].get(ACTIVE_PART_ID));
+
+ windows[0].set(ACTIVE_CHILD, parts[1]);
+ assertEquals("part1", windows[0].get(ACTIVE_PART));
+ assertEquals("part1", windows[0].get(ACTIVE_PART_ID));
+ }
+
+ /**
+ * Test how a RAT responds to a change hidden from it; changed value is == to child value
+ */
+ @Test
+ public void testSetHiddenValueToChildObject() {
+ final String newRootValue = "child";
+
+ doHiddenValueChangeTest(newRootValue);
+ }
+
+ /**
+ * Test how a RAT responds to a change hidden from it; changed value is != to child value
+ */
+ @Test
+ public void testSetHiddenValueToDifferentObject() {
+ final String newRootValue = "other";
+
+ doHiddenValueChangeTest(newRootValue);
+ }
+
+ /**
+ * Test how a RAT responds to a change hidden from it; changed value is != to child value (but is .equals())
+ */
+ @Test
+ public void testSetHiddenValueToObjectEqualToChild() {
+ // avoid compiler's pushing all my strings into a single string pool
+ final String newRootValue = new String("child");
+
+ doHiddenValueChangeTest(newRootValue);
+ }
+
+ /**
+ * Test how a RAT responds to a change hidden from it; changed value is == to root value
+ */
+ @Test
+ public void testSetHiddenValueToRootObject() {
+ final String newRootValue = "root";
+
+ doHiddenValueChangeTest(newRootValue);
+ }
+
+ /**
+ * Test how a RAT responds to a change hidden from it; changed value is != to root value (but is .equals())
+ */
+ @Test
+ public void testSetHiddenValueToEqualRootObject() {
+ // avoid compiler's pushing all my strings into a single string pool
+ final String newRootValue = new String("root");
+
+ doHiddenValueChangeTest(newRootValue);
+ }
+
+ /**
+ * Test how a RAT responds to a change hidden from it; changed value is == to root value
+ */
+ @Test
+ public void testSetHiddenValueToNull() {
+ final String newRootValue = null;
+
+ doHiddenValueChangeTest(newRootValue);
+ }
+
+ /**
+ * Perform a hidden value test that verifies that the test RAT does not run, and
+ * that has last seen the initial value in the child context (namely "child").
+ * @param newRootValue the new value for the variable 'v' in the root context.
+ * @see #doHiddenValueChangeTest(ITestAction, Object, int)
+ */
+ void doHiddenValueChangeTest(final String newRootValue) {
+ doHiddenValueChangeTest((IEclipseContext root, String var) -> {
+ root.set(var, newRootValue);
+ }, "child", 0);
+ }
+
+ /**
+ * Interface defining function
+ *
+ */
+ private interface ITestAction {
+
+ void execute(IEclipseContext root, String var);
+
+ }
+ /**
+ * Create a two level hierarchy of contexts, each defining a variable 'v' with values 'root' and 'child', respectively.
+ * Create and install a RAT on the child context that is dependent on 'v'.
+ * Run testAction.
+ * Tests whether the RAT ran the expected number of times,
+ * and tests last value of 'v' that the RAT saw.
+ * @param testAction the context action to perform as part of the test
+ * @param expectedValue the expected last value of variable 'v' that the RAT saw.
+ * @param expectedRATCalls the expected number of times the RAT was run in response to testAction
+ */
+ void doHiddenValueChangeTest(ITestAction testAction, Object expectedValue, int expectedRATCalls) {
+ final IEclipseContext root = getGlobalContext();
+ final IEclipseContext child = root.createChild("child");
+
+ root.set("v", "root");
+ child.set("v", "child");
+ final TestRAT testRAT = new TestRAT("v");
+
+ // install the RAT
+ child.runAndTrack(testRAT);
+ assertEquals("child", testRAT.getVarValue());
+ assertEquals(1, testRAT.getCalls());
+
+ testRAT.resetCalls();
+ // set the new root value
+ testAction.execute(root, "v");
+ assertEquals(expectedValue, testRAT.getVarValue());
+ assertEquals(expectedRATCalls, testRAT.getCalls());
+ }
+
+ /**
+ * Test that a variable change in a context hidden from a RAT in
+ * a child context does not re-run the RAT.
+ */
+ @Test
+ public void testRemoveHiddenVariable() {
+ doHiddenValueChangeTest((IEclipseContext root, String var) -> {
+ root.remove(var);
+ }, "child", 0);
+ }
+
+ /**
+ * Test that setting a context variable to it's existing
+ * value does not re-run dependent RATs
+ */
+ @Test
+ public void testSetContextVarToSameObject() {
+ doSingleContextChangeTest((IEclipseContext root, String var) -> {
+ root.set(var, "root");
+ }, "root", 0);
+ }
+
+ /**
+ * Test that setting a context variable to a value that {@link Object#equals(Object) equals}
+ * the current value, but is same object DOES re-run dependent RATs.
+ */
+ @Test
+ public void testSetContextVarToEqualObject() {
+ doSingleContextChangeTest((IEclipseContext root, String var) -> {
+ root.set(var, new String("root"));
+ }, "root", 1);
+ }
+
+ /**
+ * Test that setting a context variable to a different object, not equal to the
+ * current value re-runs dependent RATs.
+ */
+ @Test
+ public void testSetContextVarToOtherObject() {
+ doSingleContextChangeTest((IEclipseContext root, String var) -> {
+ root.set(var, "other");
+ }, "other", 1);
+ }
+
+ /**
+ * Test that removing a context variable re-runs dependent RATs.
+ */
+ @Test
+ public void testRemoveContextVar() {
+ doSingleContextChangeTest((root, var) -> root.remove(var), null, 1);
+
+ }
+
+ /**
+ * Creates a context, sets a variable 'v' to "root", creates a RAT dependent on 'v' in the context,
+ * then executes testAction and tests whether the RAT ran the expected number of times,
+ * and tests last value of 'v' that the RAT saw.
+ * @param testAction the context action to perform as part of the test
+ * @param expectedValue the expected last value of variable 'v' that the RAT saw.
+ * @param expectedRATCalls the expected number of times the RAT was run in response to testAction
+ */
+ private void doSingleContextChangeTest(ITestAction testAction, Object expectedValue, int expectedRATCalls) {
+ final IEclipseContext root = getGlobalContext();
+
+ root.set("v", "root");
+
+ final TestRAT testRAT = new TestRAT("v");
+ // install the RAT
+ root.runAndTrack(testRAT);
+ assertEquals("root", testRAT.getVarValue());
+ assertEquals(1, testRAT.getCalls());
+
+ testRAT.resetCalls();
+ testAction.execute(root, "v");
+ assertEquals(expectedRATCalls, testRAT.getCalls());
+ assertEquals(expectedValue, testRAT.getVarValue());
+
+ }
+}
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/StrongIterableTest.java b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/StrongIterableTest.java
new file mode 100644
index 00000000000..3e86a21f46f
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/StrongIterableTest.java
@@ -0,0 +1,273 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Joerg Kubitz.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Joerg Kubitz - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.e4.core.internal.tests.contexts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.concurrent.ConcurrentLinkedDeque;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.function.Supplier;
+import java.util.stream.StreamSupport;
+
+import org.eclipse.e4.core.internal.contexts.StrongIterable;
+import org.junit.Test;
+
+@SuppressWarnings("restriction")
+public class StrongIterableTest {
+
+ @Test
+ public void testStrongIterableDeque() {
+ testStrongIterable(ConcurrentLinkedDeque::new);
+ }
+
+ @Test
+ public void testStrongIterableQueue() {
+ testStrongIterable(ConcurrentLinkedQueue::new);
+ }
+
+ void testStrongIterable(Supplier>> constructor) {
+ testIterate(constructor.get());
+ testRemoveWhileIterate(constructor.get());
+ testRemoveAll(constructor.get());
+ testRemoveByClear(constructor.get());
+ testNextWithoutHasNext(constructor.get());
+ }
+
+ private void testNextWithoutHasNext(Collection> iterable) {
+ WeakReference EMPTY1 = new WeakReference<>(null);
+ WeakReference EMPTY2 = new WeakReference<>(null);
+ WeakReference ONE = new WeakReference<>(1);
+ WeakReference TWO = new WeakReference<>(2);
+ WeakReference THREE = new WeakReference<>(3);
+ iterable.add(EMPTY1); // ignored
+ iterable.add(ONE);
+ iterable.add(TWO);
+ iterable.add(EMPTY2); // ignored
+ iterable.add(THREE);
+ StrongIterable strongIterable = new StrongIterable<>(iterable);
+ {
+ Iterator i = strongIterable.iterator();
+ assertEquals(1, i.next().intValue());
+ assertEquals(2, i.next().intValue());
+ assertEquals(3, i.next().intValue());
+ try {
+ i.next();
+ } catch (NoSuchElementException e) {
+ assertNotNull(e);
+ }
+ }
+ {
+ Iterator i = strongIterable.iterator();
+ assertEquals(1, i.next().intValue());
+ assertEquals(3L, count(strongIterable));
+ assertEquals(3L, poorMansCount(strongIterable));
+ i.remove();
+ assertEquals(2L, count(strongIterable));
+ assertEquals(2L, poorMansCount(strongIterable));
+ assertEquals(2, i.next().intValue());
+ i.remove();
+ assertEquals(3, i.next().intValue());
+ i.remove();
+ try {
+ i.next();
+ } catch (NoSuchElementException e) {
+ assertNotNull(e);
+ }
+ }
+ assertEquals(0L, count(strongIterable));
+ assertEquals(0L, poorMansCount(strongIterable));
+ }
+
+ void testRemoveWhileIterate(Collection> iterable) {
+ WeakReference ONE = new WeakReference<>(1);
+ WeakReference TWO = new WeakReference<>(2);
+ WeakReference THREE = new WeakReference<>(3);
+ iterable.add(ONE);
+ iterable.add(TWO);
+ iterable.add(THREE);
+
+ assertEquals(3L, poorMansCount(iterable));
+ StrongIterable strongIterable = new StrongIterable<>(iterable);
+ {
+ Iterator i = strongIterable.iterator();
+ assertEquals(3L, count(strongIterable));
+ assertEquals(3L, poorMansCount(strongIterable));
+
+ assertTrue(i.hasNext());
+ assertEquals(1, i.next().intValue());
+ assertTrue(i.hasNext());
+ assertEquals(2, i.next().intValue());
+ i.remove(); // remove TWO
+ assertEquals(2L, count(strongIterable));
+ assertEquals(2L, poorMansCount(strongIterable));
+ assertTrue(i.hasNext());
+ assertEquals(3, i.next().intValue());
+ i.remove(); // remove THREE
+ assertEquals(1L, count(strongIterable));
+ assertEquals(1L, poorMansCount(strongIterable));
+ assertFalse(i.hasNext());
+ try {
+ i.next();
+ } catch (NoSuchElementException e) {
+ assertNotNull(e);
+ }
+ }
+ }
+
+ void testRemoveAll(Collection> iterable) {
+ WeakReference ONE = new WeakReference<>(1);
+ WeakReference TWO = new WeakReference<>(2);
+ WeakReference THREE = new WeakReference<>(3);
+ iterable.add(ONE);
+ iterable.add(TWO);
+ iterable.add(THREE);
+
+ StrongIterable strongIterable = new StrongIterable<>(iterable);
+ assertEquals(3L, count(strongIterable));
+ for (Iterator i = strongIterable.iterator(); i.hasNext();) {
+ i.next();
+ i.remove();
+ }
+ assertEquals(0L, count(strongIterable));
+ assertEquals(0L, poorMansCount(strongIterable));
+ }
+
+ void testRemoveByClear(Collection> iterable) {
+ WeakReference ONE = new WeakReference<>(1);
+ WeakReference TWO = new WeakReference<>(2);
+ WeakReference THREE = new WeakReference<>(3);
+ iterable.add(ONE);
+ iterable.add(TWO);
+ iterable.add(THREE);
+
+ StrongIterable strongIterable = new StrongIterable<>(iterable);
+ assertEquals(3L, count(strongIterable));
+ for (Reference ref : iterable) {
+ ref.clear();
+ }
+ assertEquals(0L, count(strongIterable));
+ }
+
+ void testIterate(Collection> iterable) {
+ WeakReference EMPTY1 = new WeakReference<>(null);
+ WeakReference EMPTY2 = new WeakReference<>(null);
+ WeakReference ONE = new WeakReference<>(1);
+ WeakReference TWO = new WeakReference<>(2);
+ WeakReference THREE = new WeakReference<>(3);
+ iterable.add(EMPTY1); // ignored
+ iterable.add(ONE);
+ iterable.add(TWO);
+ iterable.add(EMPTY2); // ignored
+ iterable.add(THREE);
+
+ StrongIterable strongIterable = new StrongIterable<>(iterable);
+ {
+ Iterator i = strongIterable.iterator();
+ assertEquals(3L, count(strongIterable));
+ assertTrue(i.hasNext());
+ assertEquals(1, i.next().intValue());
+ assertTrue(i.hasNext());
+ assertEquals(2, i.next().intValue());
+ assertTrue(i.hasNext());
+ assertEquals(3, i.next().intValue());
+ assertFalse(i.hasNext());
+ try {
+ i.next();
+ } catch (NoSuchElementException e) {
+ assertNotNull(e);
+ }
+ }
+ for (Integer strong : strongIterable) {
+ assertNotNull(strong);
+ }
+
+ assertTrue(iterable.remove(TWO)); // remove
+
+ for (Integer strong : strongIterable) {
+ assertNotNull(strong);
+ }
+ {
+ Iterator i = strongIterable.iterator();
+ assertEquals(2L, count(strongIterable));
+ assertTrue(i.hasNext());
+ assertEquals(1, i.next().intValue());
+ assertTrue(i.hasNext());
+ assertEquals(3, i.next().intValue());
+ assertFalse(i.hasNext());
+ try {
+ i.next();
+ } catch (NoSuchElementException e) {
+ assertNotNull(e);
+ }
+ }
+
+ ONE.clear(); // remove on iterate
+
+ {
+ Iterator i = strongIterable.iterator();
+ assertEquals(1L, count(strongIterable));
+ assertTrue(i.hasNext());
+ assertEquals(3, i.next().intValue());
+ assertFalse(i.hasNext());
+ try {
+ i.next();
+ } catch (NoSuchElementException e) {
+ assertNotNull(e);
+ }
+ for (Integer strong : strongIterable) {
+ assertNotNull(strong);
+ }
+ }
+
+ THREE.clear(); // remove on iterate
+
+ {
+ Iterator i = strongIterable.iterator();
+ assertEquals(0L, count(strongIterable));
+ assertFalse(i.hasNext());
+ try {
+ i.next();
+ } catch (NoSuchElementException e) {
+ assertNotNull(e);
+ }
+ for (Integer strong : strongIterable) {
+ assertNotNull(strong);
+ }
+ }
+ }
+
+ private long count(Iterable> i) {
+ return StreamSupport.stream(i.spliterator(), false).count();
+ }
+
+ private long poorMansCount(Iterable> i) {
+ long count = -1;
+ try {
+ for (Iterator> it = i.iterator();; it.next()) {
+ count++;
+ }
+ } catch (NoSuchElementException expected) {
+ }
+ return count;
+ }
+}
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/ActivationInjectionTest.java b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/ActivationInjectionTest.java
new file mode 100644
index 00000000000..9b83bdcb0e1
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/ActivationInjectionTest.java
@@ -0,0 +1,221 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2015 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Lars Vogel - Bug 474274
+ ******************************************************************************/
+
+package org.eclipse.e4.core.internal.tests.contexts.inject;
+
+import static org.junit.Assert.assertEquals;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.eclipse.e4.core.contexts.Active;
+import org.eclipse.e4.core.contexts.ContextFunction;
+import org.eclipse.e4.core.contexts.ContextInjectionFactory;
+import org.eclipse.e4.core.contexts.EclipseContextFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.di.annotations.Optional;
+import org.junit.Test;
+
+public class ActivationInjectionTest {
+
+ static public class TestRAT extends ContextFunction {
+ @Override
+ public Object compute(IEclipseContext context, String contextKey) {
+ IEclipseContext activeContext = context.getActiveLeaf();
+ // returns name of the context
+ return "_" + activeContext.get("debugString") + "_";
+ }
+ }
+
+ static public class TestObject {
+
+ public String name;
+
+ @Inject
+ public TestObject() {
+ //
+ }
+
+ @Inject
+ public void setActiveContextName(@Named("testRAT") String name) {
+ this.name = name;
+ }
+ }
+
+ @Test
+ public void testContextActivation() {
+ IEclipseContext rootContext = EclipseContextFactory.create("root");
+ rootContext.set("testRAT", new TestRAT());
+
+ IEclipseContext child1 = rootContext.createChild("child1");
+ IEclipseContext child11 = child1.createChild("child11");
+ IEclipseContext child12 = child1.createChild("child12");
+
+ IEclipseContext child2 = rootContext.createChild("child2");
+ IEclipseContext child21 = child2.createChild("child21");
+ IEclipseContext child22 = child2.createChild("child22");
+
+ TestObject testObject = ContextInjectionFactory.make(TestObject.class, rootContext);
+
+ child12.activateBranch();
+ assertEquals(child12, rootContext.getActiveLeaf());
+ assertEquals("_child12_", testObject.name);
+
+ child21.activateBranch();
+ assertEquals(child21, rootContext.getActiveLeaf());
+ assertEquals("_child21_", testObject.name);
+
+ child21.deactivate();
+ assertEquals(child2, rootContext.getActiveLeaf());
+ assertEquals("_child2_", testObject.name);
+
+ child22.activateBranch();
+ assertEquals(child22, rootContext.getActiveLeaf());
+ assertEquals("_child22_", testObject.name);
+
+ child11.activateBranch();
+ assertEquals(child11, rootContext.getActiveLeaf());
+ assertEquals("_child11_", testObject.name);
+
+ child11.deactivate();
+ assertEquals(child1, rootContext.getActiveLeaf());
+ assertEquals("_child1_", testObject.name);
+
+ child1.dispose();
+ child2.activateBranch();
+ assertEquals(child22, rootContext.getActiveLeaf());
+ assertEquals("_child22_", testObject.name);
+ }
+
+ static public class TestObjectInject {
+ public String name;
+ @Inject
+ public TestObjectInject() {
+ //
+ }
+ @Inject
+ public void setActiveContextName(@Active @Named("debugString") String name) {
+ this.name = "_" + name + "_";
+ }
+ }
+
+ @Test
+ public void testActivationInjection() {
+ IEclipseContext rootContext = EclipseContextFactory.create("root");
+
+ IEclipseContext child1 = rootContext.createChild("child1");
+ IEclipseContext child11 = child1.createChild("child11");
+ IEclipseContext child12 = child1.createChild("child12");
+
+ IEclipseContext child2 = rootContext.createChild("child2");
+ IEclipseContext child21 = child2.createChild("child21");
+ IEclipseContext child22 = child2.createChild("child22");
+
+ TestObjectInject testObject = ContextInjectionFactory.make(TestObjectInject.class, rootContext);
+
+ child12.activateBranch();
+ assertEquals(child12, rootContext.getActiveLeaf());
+ assertEquals("_child12_", testObject.name);
+
+ child21.activateBranch();
+ assertEquals(child21, rootContext.getActiveLeaf());
+ assertEquals("_child21_", testObject.name);
+
+ child21.deactivate();
+ assertEquals(child2, rootContext.getActiveLeaf());
+ assertEquals("_child2_", testObject.name);
+
+ child22.activateBranch();
+ assertEquals(child22, rootContext.getActiveLeaf());
+ assertEquals("_child22_", testObject.name);
+
+ child11.activateBranch();
+ assertEquals(child11, rootContext.getActiveLeaf());
+ assertEquals("_child11_", testObject.name);
+
+ child11.deactivate();
+ assertEquals(child1, rootContext.getActiveLeaf());
+ assertEquals("_child1_", testObject.name);
+
+ child1.dispose();
+ child2.activateBranch();
+ assertEquals(child22, rootContext.getActiveLeaf());
+ assertEquals("_child22_", testObject.name);
+ }
+
+ static public class TestInject {
+ @Optional @Inject @Active
+ public Integer number;
+ }
+
+ @Test
+ public void testInjection() {
+ IEclipseContext rootContext = EclipseContextFactory.create("root");
+
+ IEclipseContext child1 = rootContext.createChild("child1");
+ child1.set(Integer.class, Integer.valueOf(1));
+ IEclipseContext child11 = child1.createChild("child11");
+ child11.set(Integer.class, Integer.valueOf(2));
+ IEclipseContext child12 = child1.createChild("child12");
+ child12.set(Integer.class, Integer.valueOf(3));
+
+ IEclipseContext child2 = rootContext.createChild("child2");
+ child2.set(Integer.class, Integer.valueOf(4));
+ IEclipseContext child21 = child2.createChild("child21");
+ child21.set(Integer.class, Integer.valueOf(5));
+ IEclipseContext child22 = child2.createChild("child22");
+ child22.set(Integer.class, Integer.valueOf(6));
+
+ TestInject testObjectRoot = ContextInjectionFactory.make(TestInject.class, rootContext);
+ TestInject testObjectChild1 = ContextInjectionFactory.make(TestInject.class, child1);
+ TestInject testObjectChild2 = ContextInjectionFactory.make(TestInject.class, child2);
+
+ child12.activateBranch();
+ assertEquals(Integer.valueOf(3), testObjectRoot.number);
+ assertEquals(Integer.valueOf(3), testObjectChild1.number);
+ assertEquals(Integer.valueOf(4), testObjectChild2.number);
+
+ child21.activateBranch();
+ assertEquals(Integer.valueOf(5), testObjectRoot.number);
+ assertEquals(Integer.valueOf(3), testObjectChild1.number);
+ assertEquals(Integer.valueOf(5), testObjectChild2.number);
+
+ child21.deactivate();
+ assertEquals(Integer.valueOf(4), testObjectRoot.number);
+ assertEquals(Integer.valueOf(3), testObjectChild1.number);
+ assertEquals(Integer.valueOf(4), testObjectChild2.number);
+
+ child22.activateBranch();
+ assertEquals(Integer.valueOf(6), testObjectRoot.number);
+ assertEquals(Integer.valueOf(3), testObjectChild1.number);
+ assertEquals(Integer.valueOf(6), testObjectChild2.number);
+
+ child11.activateBranch();
+ assertEquals(Integer.valueOf(2), testObjectRoot.number);
+ assertEquals(Integer.valueOf(2), testObjectChild1.number);
+ assertEquals(Integer.valueOf(6), testObjectChild2.number);
+
+ child11.deactivate();
+ assertEquals(Integer.valueOf(1), testObjectRoot.number);
+ assertEquals(Integer.valueOf(1), testObjectChild1.number);
+ assertEquals(Integer.valueOf(6), testObjectChild2.number);
+
+ child1.dispose();
+ child2.activateBranch();
+ assertEquals(Integer.valueOf(6), testObjectRoot.number);
+ assertEquals(Integer.valueOf(6), testObjectChild2.number);
+ }
+
+}
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/AnnotationsInjectionTest.java b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/AnnotationsInjectionTest.java
new file mode 100644
index 00000000000..4aaf0282406
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/AnnotationsInjectionTest.java
@@ -0,0 +1,367 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2015 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Lars Vogel - Bug 474274
+ *******************************************************************************/
+package org.eclipse.e4.core.internal.tests.contexts.inject;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.eclipse.e4.core.contexts.ContextInjectionFactory;
+import org.eclipse.e4.core.contexts.EclipseContextFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.e4.core.di.annotations.Optional;
+import org.junit.Test;
+
+import junit.framework.AssertionFailedError;
+/**
+ * Tests for the basic context injection functionality
+ */
+public class AnnotationsInjectionTest {
+
+
+ @Test
+ public void testContextSetOneArg() {
+ class TestData {
+ // empty
+ }
+ class Injected {
+ int contextSetCalled = 0;
+ int setMethodCalled = 0;
+
+ public TestData value;
+
+ @Inject
+ public void settings(IEclipseContext context) {
+ contextSetCalled++;
+ }
+
+ @Inject
+ public void injectedMethod(@Named("testing123") TestData arg) {
+ setMethodCalled++;
+ value = arg;
+ }
+ }
+ IEclipseContext context = EclipseContextFactory.create();
+ TestData methodValue = new TestData();
+ context.set("testing123", methodValue);
+ Injected object = new Injected();
+ ContextInjectionFactory.inject(object, context);
+ assertEquals(1, object.setMethodCalled);
+ assertEquals(1, object.contextSetCalled);
+
+ TestData methodValue2 = new TestData();
+ context.set("testing123", methodValue2);
+ assertEquals(2, object.setMethodCalled);
+ assertEquals(methodValue2, object.value);
+ assertEquals(1, object.contextSetCalled);
+ }
+
+ @Test
+ public void testPostConstruct() {
+ class TestData {
+ // empty
+ }
+ class Injected {
+ int postConstructCalled = 0;
+ int setMethodCalled = 0;
+ public TestData value;
+
+ @PostConstruct
+ public void init() {
+ postConstructCalled++;
+ }
+
+ @Inject
+ public void setData(TestData arg) {
+ setMethodCalled++;
+ value = arg;
+ }
+ }
+ IEclipseContext context = EclipseContextFactory.create();
+ TestData methodValue = new TestData();
+ context.set(TestData.class, methodValue);
+ Injected object = new Injected();
+ ContextInjectionFactory.inject(object, context);
+ assertEquals(1, object.setMethodCalled);
+ assertEquals(1, object.postConstructCalled);
+
+ TestData methodValue2 = new TestData();
+ context.set(TestData.class, methodValue2);
+ assertEquals(2, object.setMethodCalled);
+ assertEquals(1, object.postConstructCalled);
+ assertEquals(methodValue2, object.value);
+ }
+
+ /**
+ * Tests basic context injection
+ */
+ @Test
+ public synchronized void testInjection() {
+ Integer testInt = Integer.valueOf(123);
+ String testString = "abc";
+ Double testDouble = Double.valueOf(1.23);
+ Float testFloat = Float.valueOf(12.3f);
+ Character testChar = Character.valueOf('v');
+
+ // create context
+ IEclipseContext context = EclipseContextFactory.create();
+ context.set(Integer.class, testInt);
+ context.set(String.class, testString);
+ context.set(Double.class, testDouble);
+ context.set(Float.class, testFloat);
+ context.set(Character.class, testChar);
+
+ ObjectBasic userObject = new ObjectBasic();
+ ContextInjectionFactory.inject(userObject, context);
+
+ // check field injection
+ assertEquals(testString, userObject.injectedString);
+ assertEquals(testInt, userObject.getInt());
+ assertEquals(context, userObject.context);
+
+ // check method injection
+ assertEquals(1, userObject.setMethodCalled);
+ assertEquals(1, userObject.setMethodCalled2);
+ assertEquals(testDouble, userObject.d);
+ assertEquals(testFloat, userObject.f);
+ assertEquals(testChar, userObject.c);
+
+ // check post processing
+ assertTrue(userObject.finalized);
+ }
+
+ /**
+ * Tests that fields are injected before methods.
+ */
+ @Test
+ public void testFieldMethodOrder() {
+ final AssertionFailedError[] error = new AssertionFailedError[1];
+ class TestData {
+ // empty
+ }
+ class Injected {
+ @Inject @Named("valueField")
+ Object injectedField;
+ Object methodValue;
+
+ @Inject
+ public void injectedMethod(@Optional @Named("valueMethod") Object arg) {
+ try {
+ assertTrue(injectedField != null);
+ } catch (AssertionFailedError e) {
+ error[0] = e;
+ }
+ methodValue = arg;
+ }
+ }
+ IEclipseContext context = EclipseContextFactory.create();
+ TestData fieldValue = new TestData();
+ TestData methodValue = new TestData();
+ context.set("valueField", fieldValue);
+ context.set("valueMethod", methodValue);
+ Injected object = new Injected();
+ ContextInjectionFactory.inject(object, context);
+ if (error[0] != null) {
+ throw error[0];
+ }
+ assertEquals(fieldValue, object.injectedField);
+ assertEquals(methodValue, object.methodValue);
+
+ // removing method value, the field should still have value
+ context.remove("valueMethod");
+ if (error[0] != null) {
+ throw error[0];
+ }
+ assertEquals(fieldValue, object.injectedField);
+ assertNull(object.methodValue);
+
+ context.dispose();
+ if (error[0] != null) {
+ throw error[0];
+ }
+ }
+
+ @Test
+ public void testOptionalInjection() {
+ Integer testInt = Integer.valueOf(123);
+ IEclipseContext context = EclipseContextFactory.create();
+ context.set(Integer.class, testInt);
+
+ OptionalAnnotations userObject = new OptionalAnnotations();
+ ContextInjectionFactory.inject(userObject, context);
+
+ assertEquals(0, userObject.methodOptionalCalled);
+ assertEquals(1, userObject.methodRequiredCalled);
+ assertEquals(testInt, userObject.i);
+ assertNull(userObject.s);
+ assertNull(userObject.d);
+ assertNull(userObject.f);
+
+ // add optional services
+ String testString = "abc";
+ Double testDouble = Double.valueOf(1.23);
+ Float testFloat = Float.valueOf(12.3f);
+ context.set(String.class, testString);
+ context.set(Double.class, testDouble);
+ context.set(Float.class, testFloat);
+
+ assertEquals(1, userObject.methodOptionalCalled);
+ assertEquals(2, userObject.methodRequiredCalled);
+ assertEquals(testInt, userObject.i);
+ assertEquals(testString, userObject.s);
+ assertEquals(testDouble, userObject.d);
+ assertEquals(testFloat, userObject.f);
+ }
+
+ @Test
+ public void testOptionalInvoke() {
+
+ class TestObject {
+ public int called = 0;
+
+ @Execute
+ public String something(@Optional String param) {
+ called++;
+ return param;
+ }
+ }
+
+ IEclipseContext context = EclipseContextFactory.create();
+ Object notAnObject = new Object();
+ TestObject testObject = new TestObject();
+ context.set(String.class.getName(), testObject);
+
+ Object result = ContextInjectionFactory.invoke(testObject, Execute.class, context, notAnObject);
+ assertNull(result);
+ assertEquals(1, testObject.called);
+
+ String string = "sample";
+ context.set(String.class, string);
+ result = ContextInjectionFactory.invoke(testObject, Execute.class, context, notAnObject);
+ assertEquals(string, result);
+ assertEquals(2, testObject.called);
+ }
+
+ /**
+ * Tests that a class with multiple inherited post-construct / pre-destroy methods.
+ */
+ @Test
+ public void testInheritedSpecialMethods() {
+ IEclipseContext context = EclipseContextFactory.create();
+ context.set(Integer.class, Integer.valueOf(123));
+ context.set(String.class, "abc");
+ context.set(Float.class, Float.valueOf(12.3f));
+
+ ObjectSubClass userObject = new ObjectSubClass();
+ ContextInjectionFactory.inject(userObject, context);
+ assertEquals(1, userObject.superPostConstructCount);
+ assertEquals(1, userObject.subPostConstructCount);
+ assertEquals(0, userObject.superPreDestroyCount);
+ assertEquals(0, userObject.subPreDestroyCount);
+ assertEquals(0, userObject.overriddenPreDestroyCount);
+
+ context.set(Float.class, Float.valueOf(45.6f));
+ assertEquals(1, userObject.superPostConstructCount);
+ assertEquals(1, userObject.subPostConstructCount);
+ assertEquals(0, userObject.superPreDestroyCount);
+ assertEquals(0, userObject.subPreDestroyCount);
+ assertEquals(0, userObject.overriddenPreDestroyCount);
+
+ context.dispose();
+ assertEquals(1, userObject.superPreDestroyCount);
+ assertEquals(1, userObject.subPreDestroyCount);
+ assertEquals(1, userObject.overriddenPreDestroyCount);
+ }
+
+ @Test
+ public void testInvoke() {
+ class TestData {
+ public String value;
+
+ public TestData(String tmp) {
+ value = tmp;
+ }
+ }
+ class Injected {
+ public String myString;
+
+ public Injected() {
+ // placeholder
+ }
+
+ @Execute
+ public String something(@Named("testing123") TestData data) {
+ myString = data.value;
+ return "true";
+ }
+ }
+ IEclipseContext context = EclipseContextFactory.create();
+
+ TestData methodValue = new TestData("abc");
+ context.set("testing123", methodValue);
+ Injected object = new Injected();
+ assertNull(object.myString);
+
+ assertEquals("true", ContextInjectionFactory.invoke(object, Execute.class, context, null));
+ assertEquals("abc", object.myString);
+ }
+
+ @Test
+ public void testPreDestroy() {
+ class TestData {
+ // empty
+ }
+ class Injected {
+ int preDestoryCalled = 0;
+ public TestData value;
+
+ @Inject
+ public TestData directFieldInjection;
+
+ @PreDestroy
+ public void aboutToClose() {
+ preDestoryCalled++;
+ assertNotNull(value);
+ assertNotNull(directFieldInjection);
+ }
+
+ @Inject
+ public void setData(TestData arg) {
+ value = arg;
+ }
+ }
+ IEclipseContext context = EclipseContextFactory.create();
+ TestData methodValue = new TestData();
+ context.set(TestData.class, methodValue);
+
+ Injected object = new Injected();
+ ContextInjectionFactory.inject(object, context);
+ assertNotNull(object.value);
+ assertNotNull(object.directFieldInjection);
+
+ context.dispose();
+
+ assertEquals(1, object.preDestoryCalled);
+ assertNotNull(object.value);
+ assertNotNull(object.directFieldInjection);
+ }
+}
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/Bug317183Test.java b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/Bug317183Test.java
new file mode 100644
index 00000000000..085d6cf738a
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/Bug317183Test.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2015 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Lars Vogel - Bug 474274
+ ******************************************************************************/
+
+package org.eclipse.e4.core.internal.tests.contexts.inject;
+
+import static org.junit.Assert.assertTrue;
+
+import org.eclipse.e4.core.contexts.EclipseContextFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.contexts.RunAndTrack;
+import org.junit.Test;
+
+public class Bug317183Test {
+
+ @Test
+ public void testX() {
+ IEclipseContext appContext = EclipseContextFactory.create();
+ IEclipseContext windowContext = appContext.createChild();
+ IEclipseContext partContextA = windowContext.createChild();
+ IEclipseContext partContextB = windowContext.createChild();
+
+ partContextA.activateBranch();
+
+ RunAndTrackImpl impl = new RunAndTrackImpl();
+ windowContext.runAndTrack(impl);
+
+ impl.called = false;
+
+ partContextA.dispose();
+ partContextB.activate();
+ assertTrue(impl.called); // this fails
+ }
+
+ @Test
+ public void testY() {
+ IEclipseContext appContext = EclipseContextFactory.create();
+ IEclipseContext windowContext = appContext.createChild();
+ IEclipseContext partContextA = windowContext.createChild();
+ IEclipseContext partContextB = windowContext.createChild();
+ IEclipseContext partContextC = windowContext.createChild();
+
+ partContextA.activateBranch();
+
+ RunAndTrackImpl impl = new RunAndTrackImpl();
+ windowContext.runAndTrack(impl);
+
+ partContextB.activate();
+ partContextA.dispose();
+
+ impl.called = false;
+
+ partContextC.activate();
+ assertTrue(impl.called); // this fails
+ }
+
+ static class RunAndTrackImpl extends RunAndTrack {
+
+ boolean called = false;
+
+ @Override
+ public boolean changed(IEclipseContext context) {
+ context.getActiveLeaf();
+ called = true;
+ return true;
+ }
+
+ }
+
+}
+
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/ComplexDisposalTest.java b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/ComplexDisposalTest.java
new file mode 100644
index 00000000000..7e6ea12038c
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/ComplexDisposalTest.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2015 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Lars Vogel - Bug 474274
+ ******************************************************************************/
+package org.eclipse.e4.core.internal.tests.contexts.inject;
+
+import static org.junit.Assert.assertEquals;
+
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.eclipse.e4.core.contexts.ContextFunction;
+import org.eclipse.e4.core.contexts.ContextInjectionFactory;
+import org.eclipse.e4.core.contexts.EclipseContextFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.junit.Test;
+
+/**
+ * See bug 296337: duplicate disposal of an object
+ */
+public class ComplexDisposalTest {
+
+ public static class MyTest {
+ private int count = 0;
+
+ @Inject
+ @Named("aString")
+ String string;
+
+ public int getCount() {
+ return count;
+ }
+
+ @PreDestroy
+ void preDestroy() {
+ count++;
+ }
+ }
+
+ public static class TestFunction extends ContextFunction {
+ @Override
+ public Object compute(IEclipseContext context, String contextKey) {
+ return ContextInjectionFactory.make(MyTest.class, context);
+ }
+ }
+
+ @Test
+ public void testU() {
+ IEclipseContext parentContext = EclipseContextFactory.create();
+ parentContext.set("aString", "");
+ parentContext.set(MyTest.class.getName(), new TestFunction());
+ IEclipseContext context = parentContext.createChild();
+
+ MyTest test = context.get(MyTest.class);
+
+ assertEquals(0, test.getCount());
+ context.dispose();
+ assertEquals("Context disposed, @PreDestroy should've been called", 1, test.getCount());
+ parentContext.dispose();
+ assertEquals("Parent context disposed, @PreDestroy should not have been called again", 1, test.getCount());
+ }
+
+ @Test
+ public void testV() {
+ IEclipseContext parentContext = EclipseContextFactory.create();
+ parentContext.set("aString", "");
+ IEclipseContext context = parentContext.createChild();
+
+ MyTest test = ContextInjectionFactory.make(MyTest.class, context);
+
+ assertEquals(0, test.getCount());
+ context.dispose();
+ assertEquals("Context disposed, @PreDestroy should've been called", 1, test.getCount());
+ parentContext.dispose();
+ assertEquals("Parent context disposed, @PreDestroy should not have been called again", 1, test.getCount());
+ }
+
+ @Test
+ public void testW() {
+ IEclipseContext parentContext = EclipseContextFactory.create();
+ parentContext.set("aString", "");
+ IEclipseContext context = parentContext.createChild();
+
+ MyTest test = new MyTest();
+ ContextInjectionFactory.inject(test, context);
+
+ assertEquals(0, test.getCount());
+ context.dispose();
+ assertEquals("Context disposed, @PreDestroy should've been called", 1, test.getCount());
+ parentContext.dispose();
+ assertEquals("Parent context disposed, @PreDestroy should not have been called again", 1, test.getCount());
+ }
+}
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/ContextFunctionDynamicsTest.java b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/ContextFunctionDynamicsTest.java
new file mode 100644
index 00000000000..1f2b8c82e81
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/ContextFunctionDynamicsTest.java
@@ -0,0 +1,181 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2015 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Lars Vogel - Bug 474274
+ ******************************************************************************/
+package org.eclipse.e4.core.internal.tests.contexts.inject;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.eclipse.e4.core.contexts.ContextFunction;
+import org.eclipse.e4.core.contexts.ContextInjectionFactory;
+import org.eclipse.e4.core.contexts.EclipseContextFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.di.annotations.Optional;
+import org.junit.Test;
+
+public class ContextFunctionDynamicsTest {
+
+ private static final String SELECTION = "selection"; //$NON-NLS-1$
+
+ static class InjectTarget {
+ Object input;
+
+ @Inject
+ @Optional
+ void setInput(@Named(SELECTION) Object input) {
+ this.input = input;
+ }
+ }
+
+ /**
+ * Changing context function should update injected values
+ */
+ @Test
+ public void testChangeICF() {
+ IEclipseContext context1 = EclipseContextFactory.create("context1");
+ IEclipseContext context2 = context1.createChild("context2");
+
+ context1.set(SELECTION, new ContextFunction() {
+ @Override
+ public Object compute(IEclipseContext context, String contextKey) {
+ return "func1";
+ }
+ });
+
+ InjectTarget target = new InjectTarget();
+ ContextInjectionFactory.inject(target, context2);
+
+ assertEquals("func1", target.input);
+
+ context1.set(SELECTION, new ContextFunction() {
+ @Override
+ public Object compute(IEclipseContext context, String contextKey) {
+ return "func2";
+ }
+ });
+
+ assertEquals("func2", target.input);
+ }
+
+ /**
+ * Overriding context function with a regular value on a child node
+ */
+ @Test
+ public void testOverrideICF() {
+ IEclipseContext context1 = EclipseContextFactory.create("context1");
+ IEclipseContext context2 = context1.createChild("context2");
+ IEclipseContext context3 = context2.createChild("context3");
+
+ context1.set(SELECTION, new ContextFunction() {
+ @Override
+ public Object compute(IEclipseContext context, String contextKey) {
+ return "func1";
+ }
+ });
+
+ InjectTarget target = new InjectTarget();
+ ContextInjectionFactory.inject(target, context3);
+
+ assertEquals("func1", target.input);
+
+ Object o = new Object();
+ context2.set(SELECTION, o);
+
+ assertEquals(o, target.input);
+ }
+
+ /**
+ * Tests updates in a chain of 4 contexts
+ */
+ @Test
+ public void testLongChain() {
+ IEclipseContext context1 = EclipseContextFactory.create("context1");
+ IEclipseContext context2 = context1.createChild("context2");
+ IEclipseContext context3 = context2.createChild("context3");
+ IEclipseContext context4 = context3.createChild("context4");
+
+ // ICF set on top context
+ context1.set(SELECTION, new ContextFunction() {
+ @Override
+ public Object compute(IEclipseContext context, String contextKey) {
+ return "func1";
+ }
+ });
+
+ InjectTarget target = new InjectTarget();
+ ContextInjectionFactory.inject(target, context4);
+
+ assertEquals("func1", target.input);
+
+ // Override ICF set on the 2nd context
+ context2.set(SELECTION, new ContextFunction() {
+ @Override
+ public Object compute(IEclipseContext context, String contextKey) {
+ return "func2";
+ }
+ });
+
+ assertEquals("func2", target.input);
+
+ // Override removed
+ context2.remove(SELECTION);
+ assertEquals("func1", target.input);
+
+ // Override simple value set on 3rd context
+ context3.set(SELECTION, "abc");
+ assertEquals("abc", target.input);
+
+ // Simple value override removed from 3rd context
+ context3.remove(SELECTION);
+ assertEquals("func1", target.input);
+ }
+
+
+
+ @Test
+ public void testBug315109() throws Exception {
+ IEclipseContext appContext = EclipseContextFactory.create();
+ IEclipseContext windowContext = appContext.createChild();
+ IEclipseContext partContext = windowContext.createChild();
+
+ partContext.activateBranch();
+
+ appContext.set(SELECTION, new ContextFunction() {
+ @Override
+ public Object compute(IEclipseContext context, String contextKey) {
+ IEclipseContext parent = context.getParent();
+ while (parent != null) {
+ context = parent;
+ parent = context.getParent();
+ }
+ return context.getActiveLeaf().get("out.selection");
+ }
+ });
+
+ InjectTarget target = new InjectTarget();
+ ContextInjectionFactory.inject(target, partContext);
+
+ assertNull("No selection has been set, should be null", target.input); //$NON-NLS-1$
+
+ Object o = new Object();
+ windowContext.set(SELECTION, o);
+
+ assertEquals(
+ "A selection was set into the window, should have been injected into the part", //$NON-NLS-1$
+ o, target.input);
+ }
+}
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/ContextInjectionDisposeTest.java b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/ContextInjectionDisposeTest.java
new file mode 100644
index 00000000000..7b832082b77
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/ContextInjectionDisposeTest.java
@@ -0,0 +1,138 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2015 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Lars Vogel - Bug 474274
+ *******************************************************************************/
+package org.eclipse.e4.core.internal.tests.contexts.inject;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+
+import org.eclipse.e4.core.contexts.ContextInjectionFactory;
+import org.eclipse.e4.core.contexts.EclipseContextFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.di.annotations.Optional;
+import org.junit.Test;
+
+/**
+ * Tests for injection handling of context dispose, and handling disposal of
+ * injected objects.
+ */
+public class ContextInjectionDisposeTest {
+
+ @Test
+ public void testContextDisposedNoArg() {
+ class Injected {
+
+ boolean disposeInvoked = false;
+
+ @SuppressWarnings("unused")
+ @Inject
+ private String Field;
+
+ @PreDestroy
+ public void dispose() {
+ disposeInvoked = true;
+ }
+ }
+
+ IEclipseContext context = EclipseContextFactory.create();
+ context.set(String.class, "hello");
+ Injected object = new Injected();
+ ContextInjectionFactory.inject(object, context);
+ context.dispose();
+ assertTrue(object.disposeInvoked);
+ }
+
+ @Test
+ public void testDisposeContext() {
+ class Injected {
+ boolean disposeInvoked = false;
+
+ @Inject
+ Object Field;
+ String methodValue;
+
+ @PreDestroy
+ public void dispose() {
+ disposeInvoked = true;
+ }
+
+ @Inject
+ public void InjectedMethod(String arg) {
+ methodValue = arg;
+ }
+ }
+ IEclipseContext context = EclipseContextFactory.create();
+ Object fieldValue = new Object();
+ Object methodValue = "abc";
+ context.set(Object.class, fieldValue);
+ context.set(String.class.getName(), methodValue);
+ Injected object = new Injected();
+ ContextInjectionFactory.inject(object, context);
+
+ assertEquals(fieldValue, object.Field);
+ assertEquals(methodValue, object.methodValue);
+
+ // disposing context calls @PreDestory, but does not clear injected
+ // values
+ context.dispose();
+ assertNotNull(object.Field);
+ assertNotNull(object.methodValue);
+ assertTrue(object.disposeInvoked);
+ }
+
+ @Test
+ public void testReleaseObject() {
+ class Injected {
+ boolean disposeInvoked = false;
+
+ @Inject
+ Integer Field;
+ Object methodValue;
+
+ @PreDestroy
+ public void dispose() {
+ disposeInvoked = true;
+ }
+
+ @Inject
+ public void InjectedMethod(@Optional String arg) {
+ methodValue = arg;
+ }
+ }
+ IEclipseContext context = EclipseContextFactory.create();
+ Integer fieldValue = Integer.valueOf(123);
+ String methodValue = "abc";
+ context.set(Integer.class, fieldValue);
+ context.set(String.class, methodValue);
+ Injected object = new Injected();
+ ContextInjectionFactory.inject(object, context);
+
+ assertEquals(fieldValue, object.Field);
+ assertEquals(methodValue, object.methodValue);
+
+ // releasing should have the same effect on the single object as
+ // disposing the context does.
+ ContextInjectionFactory.uninject(object, context);
+
+ assertEquals(fieldValue, object.Field);
+ assertNull(object.methodValue);
+ assertTrue(object.disposeInvoked);
+ }
+
+}
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/ContextInjectionFactoryTest.java b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/ContextInjectionFactoryTest.java
new file mode 100644
index 00000000000..873a1c6f921
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/ContextInjectionFactoryTest.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2015 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Lars Vogel - Bug 474274
+ ******************************************************************************/
+
+package org.eclipse.e4.core.internal.tests.contexts.inject;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.eclipse.e4.core.contexts.ContextInjectionFactory;
+import org.eclipse.e4.core.contexts.EclipseContextFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.di.annotations.CanExecute;
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ContextInjectionFactoryTest {
+
+ static class TestObject {
+
+ private int executed = 0;
+
+ private int executedWithParams = 0;
+
+ @Execute
+ public void execute() {
+ executed++;
+ }
+
+ @CanExecute
+ public void executeWithParams(String string) {
+ executedWithParams++;
+ }
+
+ public int getExecuted() {
+ return executed;
+ }
+
+ public int getExecutedWithParams() {
+ return executedWithParams;
+ }
+
+ }
+
+ static class TestConstructorObjectBasic {
+ public boolean defaultConstructorCalled = false;
+
+ public TestConstructorObjectBasic() {
+ defaultConstructorCalled = true;
+ }
+ }
+
+ private TestObject testObject;
+ private IEclipseContext context;
+
+ @Before
+ public void setUp() throws Exception {
+ testObject = new TestObject();
+ context = EclipseContextFactory.create();
+ }
+
+ @Test
+ public void testInvoke() throws Exception {
+ ContextInjectionFactory.invoke(testObject, Execute.class, context, null);
+
+ assertEquals(1, testObject.getExecuted());
+ assertEquals(0, testObject.getExecutedWithParams());
+ }
+
+ @Test
+ public void testInvokeWithParameters() throws Exception {
+ context.set(String.class.getName(), "");
+
+ ContextInjectionFactory.invoke(testObject, CanExecute.class, context, null);
+
+ assertEquals(0, testObject.getExecuted());
+ assertEquals(1, testObject.getExecutedWithParams());
+ }
+
+ /**
+ * If no other constructors are available, the default constructor should be used
+ */
+ @Test
+ public void testConstructorInjectionBasic() {
+ IEclipseContext context = EclipseContextFactory.create();
+ // add an extra argument for the inner class constructors
+ context.set(ContextInjectionFactoryTest.class.getName(), this);
+
+ Object basicResult = ContextInjectionFactory
+ .make(TestConstructorObjectBasic.class, context);
+ assertNotNull(basicResult);
+ assertTrue(basicResult instanceof TestConstructorObjectBasic);
+ assertTrue(((TestConstructorObjectBasic) basicResult).defaultConstructorCalled);
+ }
+}
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/ContextInjectionTest.java b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/ContextInjectionTest.java
new file mode 100644
index 00000000000..b9d9ebd0e85
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/ContextInjectionTest.java
@@ -0,0 +1,325 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2015 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Lars Vogel - Bug 474274
+ *******************************************************************************/
+package org.eclipse.e4.core.internal.tests.contexts.inject;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+
+import org.eclipse.e4.core.contexts.ContextInjectionFactory;
+import org.eclipse.e4.core.contexts.EclipseContextFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.contexts.RunAndTrack;
+import org.junit.Test;
+
+/**
+ * Tests for the basic context injection functionality
+ */
+public class ContextInjectionTest {
+
+
+ /**
+ * Test trivial method injection and finalize method with context as an argument
+ */
+ @Test
+ public void testContextSetOneArg() {
+ class TestData {
+ }
+ class Injected {
+ int contextSetCalled = 0;
+ int setMethodCalled = 0;
+
+ public TestData value;
+
+ @Inject
+ public void contextSet(IEclipseContext context) {
+ contextSetCalled++;
+ }
+
+ @Inject
+ public void InjectedMethod(TestData arg) {
+ setMethodCalled++;
+ value = arg;
+ }
+ }
+ IEclipseContext context = EclipseContextFactory.create();
+ TestData methodValue = new TestData();
+ context.set(TestData.class.getName(), methodValue);
+ Injected object = new Injected();
+ ContextInjectionFactory.inject(object, context);
+ assertEquals(1, object.setMethodCalled);
+ assertEquals(1, object.contextSetCalled);
+
+ TestData methodValue2 = new TestData();
+ context.set(TestData.class.getName(), methodValue2);
+ assertEquals(2, object.setMethodCalled);
+ assertEquals(methodValue2, object.value);
+ assertEquals(1, object.contextSetCalled);
+ }
+
+ /**
+ * Test filnalize method - no args
+ */
+ @Test
+ public void testContextSetZeroArgs() {
+ class TestData {
+ }
+ class Injected {
+ int contextSetCalled = 0;
+ int setMethodCalled = 0;
+
+ public TestData value;
+
+ @Inject
+ public void contextSet() {
+ contextSetCalled++;
+ }
+
+ @Inject
+ public void InjectedMethod(TestData arg) {
+ setMethodCalled++;
+ value = arg;
+ }
+ }
+ IEclipseContext context = EclipseContextFactory.create();
+ TestData methodValue = new TestData();
+ context.set(TestData.class.getName(), methodValue);
+ Injected object = new Injected();
+ ContextInjectionFactory.inject(object, context);
+ assertEquals(1, object.setMethodCalled);
+ assertEquals(1, object.contextSetCalled);
+
+ TestData methodValue2 = new TestData();
+ context.set(TestData.class.getName(), methodValue2);
+ assertEquals(2, object.setMethodCalled);
+ assertEquals(methodValue2, object.value);
+ assertEquals(1, object.contextSetCalled);
+ }
+
+ /**
+ * Tests basic context injection
+ */
+ @Test
+ public synchronized void testInjection() {
+ Integer testInt = Integer.valueOf(123);
+ String testString = "abc";
+ Double testDouble = Double.valueOf(1.23);
+ Float testFloat = Float.valueOf(12.3f);
+ Character testChar = Character.valueOf('v');
+
+ // create context
+ IEclipseContext context = EclipseContextFactory.create();
+ context.set(Integer.class, testInt);
+ context.set(String.class, testString);
+ context.set(Double.class, testDouble);
+ context.set(Float.class, testFloat);
+ context.set(Character.class, testChar);
+
+ ObjectBasic userObject = new ObjectBasic();
+ ContextInjectionFactory.inject(userObject, context);
+
+ // check field injection
+ assertEquals(testString, userObject.injectedString);
+ assertEquals(testInt, userObject.getInt());
+ // assertEquals(context, userObject.context);
+
+ // check method injection
+ assertEquals(1, userObject.setMethodCalled);
+ assertEquals(1, userObject.setMethodCalled2);
+ assertEquals(testDouble, userObject.d);
+ assertEquals(testFloat, userObject.f);
+ assertEquals(testChar, userObject.c);
+
+ // check post processing
+ assertTrue(userObject.finalized);
+ }
+
+ /**
+ * Tests injection of objects from parent context
+ */
+ @Test
+ public synchronized void testInjectionFromParent() {
+ Integer testInt = Integer.valueOf(123);
+ String testString = "abc";
+ Double testDouble = Double.valueOf(1.23);
+ Float testFloat = Float.valueOf(12.3f);
+ Character testChar = Character.valueOf('v');
+
+ // create parent context
+ IEclipseContext parentContext = EclipseContextFactory.create();
+ parentContext.set(Integer.class.getName(), testInt);
+ parentContext.set(String.class.getName(), testString);
+
+ // create child context
+ IEclipseContext context = parentContext.createChild();
+ context.set(Double.class.getName(), testDouble);
+ context.set(Float.class.getName(), testFloat);
+ context.set(Character.class.getName(), testChar);
+
+ ObjectBasic userObject = new ObjectBasic();
+ ContextInjectionFactory.inject(userObject, context);
+
+ // check field injection
+ assertEquals(testString, userObject.injectedString);
+ assertEquals(testInt, userObject.getInt());
+ // assertEquals(context, userObject.context);
+
+ // check method injection
+ assertEquals(1, userObject.setMethodCalled);
+ assertEquals(1, userObject.setMethodCalled2);
+ assertEquals(testDouble, userObject.d);
+ assertEquals(testFloat, userObject.f);
+ assertEquals(testChar, userObject.c);
+
+ // check post processing
+ assertTrue(userObject.finalized);
+ }
+
+ /**
+ * Tests injection into classes with inheritance
+ */
+ @Test
+ public synchronized void testInjectionAndInheritance() {
+ Integer testInt = Integer.valueOf(123);
+ String testString = "abc";
+ Float testFloat = Float.valueOf(12.3f);
+
+ // create context
+ IEclipseContext context = EclipseContextFactory.create();
+ context.set(Integer.class.getName(), testInt);
+ context.set(String.class.getName(), testString);
+ context.set(Float.class.getName(), testFloat);
+
+ ObjectSubClass userObject = new ObjectSubClass();
+ ContextInjectionFactory.inject(userObject, context);
+
+ // check inherited portion
+ assertEquals(testString, userObject.getString());
+ // assertEquals(context, userObject.getContext());
+ assertEquals(testString, userObject.getStringViaMethod());
+ assertEquals(1, userObject.setStringCalled);
+
+ // check declared portion
+ assertEquals(testInt, userObject.getInteger());
+ assertEquals(testFloat, userObject.getObjectViaMethod());
+ assertEquals(1, userObject.setObjectCalled);
+
+ // make sure overridden injected method was called only once
+ assertEquals(1, userObject.setOverriddenCalled);
+
+ // check post processing
+ assertEquals(1, userObject.getFinalizedCalled());
+ }
+
+ static public class BaseOverrideTest {
+ public String selectionString;
+ public String inputString;
+ public boolean finishCalled = false;
+
+ @Inject
+ public void setSelection(String selectionString) {
+ this.selectionString = selectionString;
+ }
+
+ @Inject
+ public void setInput(String inputString) {
+ this.inputString = inputString;
+ }
+
+ @PostConstruct
+ public void finish() {
+ finishCalled = true;
+ }
+ }
+
+ static public class OverrideTest extends BaseOverrideTest {
+ public Integer selectionNum;
+ public String inputStringSubclass;
+ public Double inputDouble;
+ public Boolean arg;
+ public boolean finishOverrideCalled = false;
+
+ @Inject
+ public void setSelection(Integer selectionNum) {
+ this.selectionNum = selectionNum;
+ }
+
+ @Inject
+ public void setInput(String inputString, Double inputDouble) {
+ this.inputStringSubclass = inputString;
+ this.inputDouble = inputDouble;
+
+ }
+
+ @PostConstruct
+ public void finish(Boolean arg) {
+ finishOverrideCalled = true;
+ this.arg = arg;
+ }
+ }
+
+ /**
+ * Tests injection of similar, but not overridden methods
+ */
+ @Test
+ public synchronized void testInjectionCloseOverride() {
+ Integer testInt = Integer.valueOf(123);
+ String testString = "abc";
+ Double testDouble = Double.valueOf(12.3);
+ Boolean testBoolean = Boolean.TRUE;
+
+ // create context
+ IEclipseContext context = EclipseContextFactory.create();
+ context.set(Integer.class, testInt);
+ context.set(String.class, testString);
+ context.set(Double.class, testDouble);
+ context.set(Boolean.class, testBoolean);
+
+ OverrideTest userObject = new OverrideTest();
+ ContextInjectionFactory.inject(userObject, context);
+
+ // check inherited portion
+ assertEquals(testString, userObject.selectionString);
+ assertEquals(testString, userObject.inputString);
+ assertTrue(userObject.finishCalled);
+
+ // check similar methods portion
+ assertEquals(testInt, userObject.selectionNum);
+ assertEquals(testString, userObject.inputStringSubclass);
+ assertEquals(testDouble, userObject.inputDouble);
+ assertTrue(userObject.finishOverrideCalled);
+ }
+
+ @Test
+ public void testBug374421() {
+ try {
+ IEclipseContext context = EclipseContextFactory.create();
+ context.runAndTrack(new RunAndTrack() {
+ @Override
+ public boolean changed(IEclipseContext context) {
+ IEclipseContext staticContext = EclipseContextFactory.create();
+ ContextInjectionFactory.make(Object.class, context, staticContext);
+ return true;
+ }
+ });
+ } catch (StackOverflowError e) {
+ fail("See bug 374421 for details.");
+ }
+ }
+
+}
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/DisposingReferencedContextTest.java b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/DisposingReferencedContextTest.java
new file mode 100644
index 00000000000..e28429fdc71
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/DisposingReferencedContextTest.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2015 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Lars Vogel - Bug 474274
+ ******************************************************************************/
+package org.eclipse.e4.core.internal.tests.contexts.inject;
+
+import static org.junit.Assert.assertEquals;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.eclipse.e4.core.contexts.ContextInjectionFactory;
+import org.eclipse.e4.core.contexts.EclipseContextFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.di.annotations.Optional;
+import org.eclipse.e4.core.internal.contexts.EclipseContext;
+import org.junit.Test;
+
+@SuppressWarnings("restriction")
+public class DisposingReferencedContextTest {
+
+ static class MandatoryTarget {
+ @Inject @Named("object")
+ Object object;
+
+ @Inject
+ void setActiveContext(@Named(EclipseContext.ACTIVE_CHILD) IEclipseContext partContext) {
+ if (partContext != null) {
+ partContext.get("someVar");
+ }
+ }
+ }
+
+ static class OptionalTarget {
+ @Inject @Named("object")
+ Object object;
+
+ @Inject
+ void setActiveContext(@Optional @Named(EclipseContext.ACTIVE_CHILD) IEclipseContext partContext) {
+ if (partContext != null) {
+ partContext.get("someVar");
+ }
+ }
+ }
+
+ @Test
+ public void testContextDisposeCausesCompleteUninjection_Mandatory_True() {
+ testContextDisposeCausesCompleteUninjection_Mandatory(true);
+ }
+
+ @Test
+ public void testContextDisposeCausesCompleteUninjection_Mandatory_False() {
+ testContextDisposeCausesCompleteUninjection_Mandatory(false);
+ }
+
+ @Test
+ public void testContextDisposeCausesCompleteUninjection_Optional_True() {
+ testContextDisposeCausesCompleteUninjection_Optional(true);
+ }
+
+ @Test
+ public void testContextDisposeCausesCompleteUninjection_Optional_False() {
+ testContextDisposeCausesCompleteUninjection_Optional(false);
+ }
+
+ private void testContextDisposeCausesCompleteUninjection_Mandatory(boolean disposeFirst) {
+ IEclipseContext windowContext = EclipseContextFactory.create("windowContext");
+ IEclipseContext partContext = windowContext.createChild("partContext");
+
+ partContext.activate();
+
+ Object o = new Object();
+ windowContext.set("object", o);
+
+ MandatoryTarget target = new MandatoryTarget();
+ ContextInjectionFactory.inject(target, windowContext);
+ assertEquals("The object should have been injected", o, target.object);
+
+ partContext.dispose();
+
+ assertEquals("The object should not have been uninjected", o, target.object);
+ }
+
+ private void testContextDisposeCausesCompleteUninjection_Optional(boolean disposeFirst) {
+ IEclipseContext windowContext = EclipseContextFactory.create();
+ IEclipseContext partContext = windowContext.createChild();
+
+ partContext.activate();
+
+ Object o = new Object();
+ windowContext.set("object", o);
+
+ OptionalTarget target = new OptionalTarget();
+ ContextInjectionFactory.inject(target, windowContext);
+ assertEquals("The object should have been injected", o, target.object);
+
+ partContext.dispose();
+
+ assertEquals("The object should not have been uninjected", o, target.object);
+ }
+}
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/ExtraDependenciesTest.java b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/ExtraDependenciesTest.java
new file mode 100644
index 00000000000..50b1adbea35
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/ExtraDependenciesTest.java
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2015 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Lars Vogel - Bug 474274
+ *******************************************************************************/
+package org.eclipse.e4.core.internal.tests.contexts.inject;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.lang.reflect.InvocationTargetException;
+
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.eclipse.e4.core.contexts.ContextInjectionFactory;
+import org.eclipse.e4.core.contexts.EclipseContextFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.junit.Test;
+
+public class ExtraDependenciesTest {
+
+ static public class TestObject {
+
+ public String string;
+ public Integer integer;
+ public String other;
+
+ public boolean disposed = false;
+
+ @Inject
+ public void injectedMethod(@Named("arg1") String strValue, @Named("arg2") Integer intValue, IEclipseContext context) {
+ string = strValue;
+ integer = intValue;
+ if (context == null) {
+ other = null;
+ return;
+ }
+ IEclipseContext otherContext = (IEclipseContext) context.get("otherContext");
+ if (otherContext == null) {
+ other = null;
+ } else {
+ other = (String) otherContext.get("arg3");
+ }
+ }
+
+ @PreDestroy
+ public void finita() {
+ disposed = true;
+ }
+ }
+
+ @Test
+ public void testExtraDependencies() throws InvocationTargetException, InstantiationException {
+ IEclipseContext context = EclipseContextFactory.create();
+ context.set("arg1", "abc");
+ context.set("arg2", Integer.valueOf (123));
+
+ IEclipseContext otherContext = EclipseContextFactory.create();
+ otherContext.set("arg3", "other");
+
+ context.set("otherContext", otherContext);
+
+ TestObject object = ContextInjectionFactory.make(TestObject.class, context);
+
+ // check that initial values are properly injected
+ assertEquals("abc", object.string);
+ assertEquals(Integer.valueOf(123), object.integer);
+ assertEquals("other", object.other);
+
+ // modify argument value to cause update - bug 308650
+ context.set("arg2", Integer.valueOf (789));
+
+ // change the "other" value; should not be propagated
+ otherContext.set("arg3", "wrong");
+ assertEquals("other", object.other);
+
+ // dispose the other context; should not cause disposal of the test object
+ otherContext.dispose();
+ assertEquals("other", object.other);
+ assertFalse(object.disposed);
+
+ // remove "other" context, should not be propagated
+ context.remove("otherContext");
+ assertEquals("other", object.other);
+
+ // check that changes in the method arguments are propagated
+ context.set("arg1", "xyz");
+ context.set("arg2", Integer.valueOf (456));
+ assertEquals("xyz", object.string);
+ assertEquals(Integer.valueOf(456), object.integer);
+ assertNull(object.other);
+
+ // check that disposal of the injected context causes disposal of the injected object
+ context.dispose();
+ assertTrue(object.disposed);
+ assertNotNull(object.string);
+ assertNotNull(object.integer);
+ assertNull(object.other);
+ }
+
+}
diff --git a/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/GenericsInjectionTest.java b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/GenericsInjectionTest.java
new file mode 100644
index 00000000000..210d385c459
--- /dev/null
+++ b/runtime/tests/org.eclipse.e4.core.javax.tests/src/org/eclipse/e4/core/internal/tests/contexts/inject/GenericsInjectionTest.java
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2015 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Lars Vogel - Bug 474274
+ *******************************************************************************/
+package org.eclipse.e4.core.internal.tests.contexts.inject;
+
+import static org.junit.Assert.assertEquals;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.eclipse.e4.core.contexts.ContextInjectionFactory;
+import org.eclipse.e4.core.contexts.EclipseContextFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.junit.Test;
+
+/**
+ * Tests for the generics context injection functionality
+ */
+public class GenericsInjectionTest {
+
+ static public class Animal {
+ }
+
+ static public class Bird extends Animal {
+ }
+
+ static public class Feeder {
+ }
+
+ static public class BirdHouse extends Feeder {
+ }
+
+ static public class TestNamedObject {
+ public Feeder field;
+
+ @Inject
+ public void setFeeder(@Named("test") Feeder value) {
+ field = value;
+ }
+ }
+
+ static public class TestGenericObject {
+ public Feeder field;
+
+ @Inject
+ public void setFeeder(Feeder value) {
+ field = value;
+ }
+ }
+
+ @Test
+ public synchronized void testNamedInjection() {
+ Animal testAnimal = new Animal();
+ Bird testBird = new Bird();
+ BirdHouse testBirdHouse = new BirdHouse();
+
+ // create context
+ IEclipseContext context = EclipseContextFactory.create();
+ context.set(Animal.class, testAnimal);
+ context.set(Bird.class, testBird);
+ context.set("test", testBirdHouse);
+
+ TestNamedObject userObject = new TestNamedObject();
+ ContextInjectionFactory.inject(userObject, context);
+
+ // check field injection
+ assertEquals(testBirdHouse, userObject.field);
+ }
+
+ @Test
+ public synchronized void testGenericInjection() {
+ Animal testAnimal = new Animal();
+ Bird testBird = new Bird();
+ BirdHouse testBirdHouse = new BirdHouse();
+
+ // create context
+ IEclipseContext context = EclipseContextFactory.create();
+ context.set(Animal.class, testAnimal);
+ context.set(Bird.class, testBird);
+ context.set(Feeder.class, testBirdHouse); // note that BirdHouse is
+ // added as Feeder class
+
+ TestGenericObject userObject = new TestGenericObject();
+ ContextInjectionFactory.inject(userObject, context);
+
+ // check field injection
+ assertEquals(testBirdHouse, userObject.field);
+ }
+
+ static public interface Interface {
+ }
+
+ static public class Implementation implements Interface