DATAREST-93 - Fixed formatting in Spring Data REST.
Added formatter to be used within Eclipse going forward.
This commit is contained in:
291
formatter.xml
Normal file
291
formatter.xml
Normal file
@@ -0,0 +1,291 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<profiles version="12">
|
||||
<profile kind="CodeFormatterProfile" name="Spring Data" version="12">
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_binary_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_binary_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.source" value="1.7"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="120"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="2"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.problem.assertIdentifier" value="error"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="tab"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.problem.enumIdentifier" value="error"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="2"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.compliance" value="1.7"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_binary_expression" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode" value="enabled"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="120"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_binary_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.codegen.targetPlatform" value="1.7"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
|
||||
</profile>
|
||||
</profiles>
|
||||
@@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.rest.convert;
|
||||
|
||||
import java.util.Stack;
|
||||
@@ -5,89 +20,91 @@ import java.util.Stack;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.ConverterNotFoundException;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* This {@link ConversionService} implementation delegates the actual conversion to the {@literal ConversionService} it
|
||||
* finds in its internal {@link Stack} that claims to be able to convert a given class. It will roll through the
|
||||
* {@literal ConversionService}s until it finds one that can convert the given type.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
* @authot Oliver Gierke
|
||||
*/
|
||||
public class DelegatingConversionService implements ConversionService {
|
||||
|
||||
private Stack<ConversionService> conversionServices = new Stack<ConversionService>();
|
||||
private final Stack<ConversionService> conversionServices;
|
||||
|
||||
public DelegatingConversionService() {
|
||||
}
|
||||
public DelegatingConversionService(ConversionService... svcs) {
|
||||
|
||||
public DelegatingConversionService(ConversionService... svcs) {
|
||||
addConversionServices(svcs);
|
||||
}
|
||||
this.conversionServices = new Stack<ConversionService>();
|
||||
|
||||
/**
|
||||
* Add {@link ConversionService}s to the internal list of those to delegate to.
|
||||
*
|
||||
* @param svcs
|
||||
* The ConversionServices to delegate to (in order).
|
||||
*
|
||||
* @return @this
|
||||
*/
|
||||
public DelegatingConversionService addConversionServices(ConversionService... svcs) {
|
||||
for(ConversionService svc : svcs) {
|
||||
conversionServices.add(svc);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
for (ConversionService svc : svcs) {
|
||||
Assert.notNull(svc);
|
||||
conversionServices.add(svc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a {@link ConversionService} to the internal list at a specific index for controlling the priority.
|
||||
*
|
||||
* @param atIndex
|
||||
* Where in the stack to add this ConversionService.
|
||||
* @param svc
|
||||
* The ConversionService to add.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public DelegatingConversionService addConversionService(int atIndex, ConversionService svc) {
|
||||
conversionServices.add(atIndex, svc);
|
||||
return this;
|
||||
}
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.ConversionService#canConvert(java.lang.Class, java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public boolean canConvert(Class<?> from, Class<?> to) {
|
||||
|
||||
@Override public boolean canConvert(Class<?> from, Class<?> to) {
|
||||
for(ConversionService svc : conversionServices) {
|
||||
if(svc.canConvert(from, to)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
for (ConversionService svc : conversionServices) {
|
||||
if (svc.canConvert(from, to)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override public boolean canConvert(TypeDescriptor from, TypeDescriptor to) {
|
||||
for(ConversionService svc : conversionServices) {
|
||||
if(svc.canConvert(from, to)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public <T> T convert(Object o, Class<T> type) {
|
||||
for(ConversionService svc : conversionServices) {
|
||||
if(svc.canConvert(o.getClass(), type)) {
|
||||
return svc.convert(o, type);
|
||||
}
|
||||
}
|
||||
throw new ConverterNotFoundException(TypeDescriptor.forObject(o), TypeDescriptor.valueOf(type));
|
||||
}
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.ConversionService#canConvert(org.springframework.core.convert.TypeDescriptor, org.springframework.core.convert.TypeDescriptor)
|
||||
*/
|
||||
@Override
|
||||
public boolean canConvert(TypeDescriptor from, TypeDescriptor to) {
|
||||
|
||||
@Override public Object convert(Object o, TypeDescriptor from, TypeDescriptor to) {
|
||||
for(ConversionService svc : conversionServices) {
|
||||
if(svc.canConvert(from, to)) {
|
||||
return svc.convert(o, from, to);
|
||||
}
|
||||
}
|
||||
throw new ConverterNotFoundException(from, to);
|
||||
}
|
||||
for (ConversionService svc : conversionServices) {
|
||||
if (svc.canConvert(from, to)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.ConversionService#convert(java.lang.Object, java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <T> T convert(Object o, Class<T> type) {
|
||||
|
||||
for (ConversionService svc : conversionServices) {
|
||||
if (svc.canConvert(o.getClass(), type)) {
|
||||
return svc.convert(o, type);
|
||||
}
|
||||
}
|
||||
|
||||
throw new ConverterNotFoundException(TypeDescriptor.forObject(o), TypeDescriptor.valueOf(type));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.ConversionService#convert(java.lang.Object, org.springframework.core.convert.TypeDescriptor, org.springframework.core.convert.TypeDescriptor)
|
||||
*/
|
||||
@Override
|
||||
public Object convert(Object o, TypeDescriptor from, TypeDescriptor to) {
|
||||
|
||||
for (ConversionService svc : conversionServices) {
|
||||
if (svc.canConvert(from, to)) {
|
||||
return svc.convert(o, from, to);
|
||||
}
|
||||
}
|
||||
|
||||
throw new ConverterNotFoundException(from, to);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.rest.convert;
|
||||
|
||||
import java.text.DateFormat;
|
||||
@@ -15,62 +30,81 @@ import org.springframework.core.convert.converter.Converter;
|
||||
/**
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
public class ISO8601DateConverter implements ConditionalGenericConverter,
|
||||
Converter<String[], Date> {
|
||||
public class ISO8601DateConverter implements ConditionalGenericConverter, Converter<String[], Date> {
|
||||
|
||||
public static final ConditionalGenericConverter INSTANCE = new ISO8601DateConverter();
|
||||
public static final ConditionalGenericConverter INSTANCE = new ISO8601DateConverter();
|
||||
|
||||
private static final Set<ConvertiblePair> CONVERTIBLE_PAIRS = new HashSet<ConvertiblePair>();
|
||||
private static final Set<ConvertiblePair> CONVERTIBLE_PAIRS = new HashSet<ConvertiblePair>();
|
||||
|
||||
static {
|
||||
CONVERTIBLE_PAIRS.add(new ConvertiblePair(String.class, Date.class));
|
||||
CONVERTIBLE_PAIRS.add(new ConvertiblePair(Date.class, String.class));
|
||||
}
|
||||
static {
|
||||
CONVERTIBLE_PAIRS.add(new ConvertiblePair(String.class, Date.class));
|
||||
CONVERTIBLE_PAIRS.add(new ConvertiblePair(Date.class, String.class));
|
||||
}
|
||||
|
||||
@Override public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
if(String.class.isAssignableFrom(sourceType.getType())) {
|
||||
return Date.class.isAssignableFrom(targetType.getType());
|
||||
}
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.ConditionalConverter#matches(org.springframework.core.convert.TypeDescriptor, org.springframework.core.convert.TypeDescriptor)
|
||||
*/
|
||||
@Override
|
||||
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
|
||||
return Date.class.isAssignableFrom(sourceType.getType())
|
||||
&& String.class.isAssignableFrom(targetType.getType());
|
||||
}
|
||||
if (String.class.isAssignableFrom(sourceType.getType())) {
|
||||
return Date.class.isAssignableFrom(targetType.getType());
|
||||
}
|
||||
|
||||
@Override public Set<ConvertiblePair> getConvertibleTypes() {
|
||||
return CONVERTIBLE_PAIRS;
|
||||
}
|
||||
return Date.class.isAssignableFrom(sourceType.getType()) && String.class.isAssignableFrom(targetType.getType());
|
||||
}
|
||||
|
||||
@Override public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
DateFormat dateFmt = iso8601DateFormat();
|
||||
if(String.class.isAssignableFrom(sourceType.getType())) {
|
||||
return dateFmt.format(source);
|
||||
} else {
|
||||
try {
|
||||
return dateFmt.parse(source.toString());
|
||||
} catch(ParseException e) {
|
||||
throw new ConversionFailedException(sourceType, targetType, source, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.GenericConverter#getConvertibleTypes()
|
||||
*/
|
||||
@Override
|
||||
public Set<ConvertiblePair> getConvertibleTypes() {
|
||||
return CONVERTIBLE_PAIRS;
|
||||
}
|
||||
|
||||
@Override public Date convert(String[] source) {
|
||||
if(source.length > 0) {
|
||||
try {
|
||||
return iso8601DateFormat().parse(source[0]);
|
||||
} catch(ParseException e) {
|
||||
throw new ConversionFailedException(
|
||||
TypeDescriptor.valueOf(String[].class),
|
||||
TypeDescriptor.valueOf(Date.class),
|
||||
source[0],
|
||||
new IllegalArgumentException("Source does not conform to ISO8601 date format (YYYY-MM-DDTHH:MM:SS-0000")
|
||||
);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.GenericConverter#convert(java.lang.Object, org.springframework.core.convert.TypeDescriptor, org.springframework.core.convert.TypeDescriptor)
|
||||
*/
|
||||
@Override
|
||||
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
|
||||
private DateFormat iso8601DateFormat() {
|
||||
return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
|
||||
}
|
||||
DateFormat dateFmt = iso8601DateFormat();
|
||||
|
||||
if (String.class.isAssignableFrom(sourceType.getType())) {
|
||||
return dateFmt.format(source);
|
||||
}
|
||||
|
||||
try {
|
||||
return dateFmt.parse(source.toString());
|
||||
} catch (ParseException e) {
|
||||
throw new ConversionFailedException(sourceType, targetType, source, e);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public Date convert(String[] source) {
|
||||
|
||||
if (source.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return iso8601DateFormat().parse(source[0]);
|
||||
} catch (ParseException e) {
|
||||
throw new ConversionFailedException(TypeDescriptor.valueOf(String[].class), TypeDescriptor.valueOf(Date.class),
|
||||
source[0], new IllegalArgumentException(
|
||||
"Source does not conform to ISO8601 date format (YYYY-MM-DDTHH:MM:SS-0000"));
|
||||
}
|
||||
}
|
||||
|
||||
private DateFormat iso8601DateFormat() {
|
||||
return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.rest.convert;
|
||||
|
||||
import java.util.HashSet;
|
||||
@@ -9,38 +24,51 @@ import org.springframework.core.convert.converter.ConditionalGenericConverter;
|
||||
|
||||
/**
|
||||
* For converting a {@link UUID} into a {@link String}.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
public class UUIDConverter implements ConditionalGenericConverter {
|
||||
|
||||
public static final UUIDConverter INSTANCE = new UUIDConverter();
|
||||
private static final Set<ConvertiblePair> CONVERTIBLE_PAIRS = new HashSet<ConvertiblePair>();
|
||||
public static final UUIDConverter INSTANCE = new UUIDConverter();
|
||||
private static final Set<ConvertiblePair> CONVERTIBLE_PAIRS = new HashSet<ConvertiblePair>();
|
||||
|
||||
static {
|
||||
CONVERTIBLE_PAIRS.add(new ConvertiblePair(String.class, UUID.class));
|
||||
CONVERTIBLE_PAIRS.add(new ConvertiblePair(UUID.class, String.class));
|
||||
}
|
||||
static {
|
||||
CONVERTIBLE_PAIRS.add(new ConvertiblePair(String.class, UUID.class));
|
||||
CONVERTIBLE_PAIRS.add(new ConvertiblePair(UUID.class, String.class));
|
||||
}
|
||||
|
||||
@Override public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
if(String.class.isAssignableFrom(sourceType.getType())) {
|
||||
return UUID.class.isAssignableFrom(targetType.getType());
|
||||
}
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.ConditionalConverter#matches(org.springframework.core.convert.TypeDescriptor, org.springframework.core.convert.TypeDescriptor)
|
||||
*/
|
||||
@Override
|
||||
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
if (String.class.isAssignableFrom(sourceType.getType())) {
|
||||
return UUID.class.isAssignableFrom(targetType.getType());
|
||||
}
|
||||
|
||||
return UUID.class.isAssignableFrom(sourceType.getType())
|
||||
&& String.class.isAssignableFrom(targetType.getType());
|
||||
}
|
||||
return UUID.class.isAssignableFrom(sourceType.getType()) && String.class.isAssignableFrom(targetType.getType());
|
||||
}
|
||||
|
||||
@Override public Set<ConvertiblePair> getConvertibleTypes() {
|
||||
return CONVERTIBLE_PAIRS;
|
||||
}
|
||||
|
||||
@Override public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
if(String.class.isAssignableFrom(sourceType.getType())) {
|
||||
return UUID.fromString(source.toString());
|
||||
} else {
|
||||
return source.toString();
|
||||
}
|
||||
}
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.GenericConverter#getConvertibleTypes()
|
||||
*/
|
||||
@Override
|
||||
public Set<ConvertiblePair> getConvertibleTypes() {
|
||||
return CONVERTIBLE_PAIRS;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.GenericConverter#convert(java.lang.Object, org.springframework.core.convert.TypeDescriptor, org.springframework.core.convert.TypeDescriptor)
|
||||
*/
|
||||
@Override
|
||||
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
if (String.class.isAssignableFrom(sourceType.getType())) {
|
||||
return UUID.fromString(source.toString());
|
||||
} else {
|
||||
return source.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,3 +2,4 @@
|
||||
* {@link org.springframework.core.convert.ConversionService} and {@link org.springframework.core.convert.converter.Converter} integration for Spring Data REST.
|
||||
*/
|
||||
package org.springframework.data.rest.convert;
|
||||
|
||||
|
||||
@@ -2,3 +2,4 @@
|
||||
* Core components used across Spring Data REST.
|
||||
*/
|
||||
package org.springframework.data.rest.core;
|
||||
|
||||
|
||||
@@ -38,14 +38,14 @@ public abstract class MapUtils {
|
||||
* @return
|
||||
*/
|
||||
public static <K, V> Map<K, Collection<V>> toMap(MultiValueMap<K, V> map) {
|
||||
|
||||
|
||||
Assert.notNull(map, "Given map must not be null!");
|
||||
Map<K, Collection<V>> result = new LinkedHashMap<K, Collection<V>>(map.size());
|
||||
|
||||
for (Entry<K, List<V>> entry : map.entrySet()) {
|
||||
result.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,210 +1,25 @@
|
||||
package org.springframework.data.rest.core.util;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
/**
|
||||
* Helper methods for dealing with URIs.
|
||||
*
|
||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
public abstract class UriUtils {
|
||||
|
||||
private UriUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the given {@link URI} based on the "base" {@link URI}?
|
||||
* <p>e.g. given a base URI of {@literal http://localhost:8080/data} and a URI of {@code
|
||||
* http://localhost:8080/data/person}, this method would report the baseUri being a valid base of the given URI.
|
||||
* </p>
|
||||
*
|
||||
* @param baseUri
|
||||
* {@link URI} to check.
|
||||
* @param uri
|
||||
* {@link URI} against which to compare the base.
|
||||
*
|
||||
* @return {@literal true} if the baseUri is valid against the given {@link URI}, {@literal false} otherwise.
|
||||
*/
|
||||
public static boolean validBaseUri(URI baseUri, URI uri) {
|
||||
String path = UriUtils.path(baseUri.relativize(uri));
|
||||
return !StringUtils.hasText(path) || path.charAt(0) != '/';
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the given {@link Function} for each segment in the {@link URI}.
|
||||
* <p>e.g. given a URI of {@literal http://localhost:8080/data/person/1} and a base URI of {@code
|
||||
* http://localhost:8080/data}, this method will explode the URI into it's components, as compared to the base URI.
|
||||
* The result would be: the given handler gets called twice, once passing a relative {@link URI} of "person" and a
|
||||
* second time passing a relative {@link URI} of "1".
|
||||
* </p>
|
||||
*
|
||||
* @param baseUri
|
||||
* base {@link URI}
|
||||
* @param uri
|
||||
* {@link URI} to explode and iterate over.
|
||||
* @param handler
|
||||
* {@link Function} to call for each segment of the URI's path.
|
||||
* @param <V>
|
||||
* Return type of the handler.
|
||||
*
|
||||
* @return Handler return value, or possibly {@literal null}.
|
||||
*/
|
||||
public static <V> V foreach(URI baseUri, URI uri, Function<URI, V> handler) {
|
||||
List<URI> uris = explode(baseUri, uri);
|
||||
V v = null;
|
||||
for(URI u : uris) {
|
||||
v = handler.apply(u);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Explode the given {@link URI} into its component parts, as compared to the base {@link URI}.
|
||||
* <p>Given a base URI of {@literal http://localhost:8080/data}, exploding the URI {@code
|
||||
* http://localhost:8080/data/person/1} strips the first part of the URI, leaving {@literal person/1}. This results
|
||||
* in
|
||||
* a {@link Stack} of relative {@link URI}s of size 2--one for "person" and one for "1".</p>
|
||||
*
|
||||
* @param baseUri
|
||||
* base {@link URI}
|
||||
* @param uri
|
||||
* {@link URI} to explode
|
||||
*
|
||||
* @return {@link Stack} of relative {@link URI}s.
|
||||
*/
|
||||
public static Stack<URI> explode(URI baseUri, URI uri) {
|
||||
Stack<URI> uris = new Stack<URI>();
|
||||
if(StringUtils.hasText(uri.getPath())) {
|
||||
URI relativeUri = baseUri.relativize(uri);
|
||||
if(StringUtils.hasText(relativeUri.getPath())) {
|
||||
for(String part : relativeUri.getPath().split("/")) {
|
||||
uris.add(URI.create(part + (StringUtils.hasText(uri.getQuery()) ? "?" + uri.getQuery() : "")));
|
||||
}
|
||||
}
|
||||
}
|
||||
return uris;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge the components of these {@link URI}s into a single URI. Useful for combining a relative URI with a base URI
|
||||
* and coming up with a full absolute URI.
|
||||
* <p>e.g. merging base URI {@literal http://localhost:8080/data} and relative uri {@literal person/1?name=John+Doe}
|
||||
* would result in an absolute URI of {@literal http://localhost:8080/data/person/1?name=John+Doe}</p>
|
||||
*
|
||||
* @param baseUri
|
||||
* base {@link URI}
|
||||
* @param uris
|
||||
* {@link URI}s to merge
|
||||
*
|
||||
* @return {@link URI} that is the combination of all the given (possibly relative, possibly absolute) URIs.
|
||||
*/
|
||||
public static URI merge(URI baseUri, URI... uris) {
|
||||
StringBuilder query = new StringBuilder();
|
||||
|
||||
UriComponentsBuilder ub = UriComponentsBuilder.fromUri(baseUri);
|
||||
for(URI uri : uris) {
|
||||
String s = uri.getScheme();
|
||||
if(null != s) {
|
||||
ub.scheme(s);
|
||||
}
|
||||
|
||||
s = uri.getUserInfo();
|
||||
if(null != s) {
|
||||
ub.userInfo(s);
|
||||
}
|
||||
|
||||
s = uri.getHost();
|
||||
if(null != s) {
|
||||
ub.host(s);
|
||||
}
|
||||
|
||||
int i = uri.getPort();
|
||||
if(i > 0) {
|
||||
ub.port(i);
|
||||
}
|
||||
|
||||
s = uri.getPath();
|
||||
if(null != s) {
|
||||
if(!uri.isAbsolute() && StringUtils.hasText(s)) {
|
||||
ub.pathSegment(s);
|
||||
} else {
|
||||
ub.path(s);
|
||||
}
|
||||
}
|
||||
|
||||
s = uri.getQuery();
|
||||
if(null != s) {
|
||||
if(query.length() > 0) {
|
||||
query.append("&");
|
||||
}
|
||||
query.append(s);
|
||||
}
|
||||
|
||||
s = uri.getFragment();
|
||||
if(null != s) {
|
||||
ub.fragment(s);
|
||||
}
|
||||
}
|
||||
|
||||
if(query.length() > 0) {
|
||||
ub.query(query.toString());
|
||||
}
|
||||
|
||||
return ub.build().toUri();
|
||||
}
|
||||
|
||||
/**
|
||||
* Just the path portion of the {@link URI}, but with any trailing slash "/" removed.
|
||||
*
|
||||
* @param uri
|
||||
* path URI
|
||||
*
|
||||
* @return the path portion of the URI, but with any trailing slash removed
|
||||
*/
|
||||
public static String path(URI uri) {
|
||||
if(null == uri) {
|
||||
return null;
|
||||
}
|
||||
String s = uri.getPath();
|
||||
if(s.endsWith("/")) {
|
||||
return s.substring(0, s.length() - 1);
|
||||
} else {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The very last segment of the {@link URI}.
|
||||
*
|
||||
* @param baseUri
|
||||
* base {@link URI}
|
||||
* @param uri
|
||||
* {@link URI} to explode
|
||||
*
|
||||
* @return Relative {@link URI} that is the last segment of the path for the given URI.
|
||||
*/
|
||||
public static URI tail(URI baseUri, URI uri) {
|
||||
Stack<URI> uris = explode(baseUri, uri);
|
||||
return uris.size() > 0 ? uris.get(Math.max(uris.size() - 1, 0)) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link URI} out of the components.
|
||||
*
|
||||
* @param baseUri
|
||||
* The base URI these path segments are relative to.
|
||||
* @param pathSegments
|
||||
* The path segments to add to the given base URI.
|
||||
*
|
||||
* @return A new URI built from the given base URI and additional path segments.
|
||||
*/
|
||||
public static URI buildUri(URI baseUri, String... pathSegments) {
|
||||
return UriComponentsBuilder.fromUri(baseUri).pathSegment(pathSegments).build().toUri();
|
||||
}
|
||||
/**
|
||||
* Create a new {@link URI} out of the components.
|
||||
*
|
||||
* @param baseUri The base URI these path segments are relative to.
|
||||
* @param pathSegments The path segments to add to the given base URI.
|
||||
* @return A new URI built from the given base URI and additional path segments.
|
||||
*/
|
||||
public static URI buildUri(URI baseUri, String... pathSegments) {
|
||||
return UriComponentsBuilder.fromUri(baseUri).pathSegment(pathSegments).build().toUri();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,3 +2,4 @@
|
||||
* Spring Data REST
|
||||
*/
|
||||
package org.springframework.data.rest;
|
||||
|
||||
|
||||
@@ -1,7 +1,23 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.rest.convert;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.mockito.Matchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.UUID;
|
||||
@@ -16,48 +32,53 @@ import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.format.support.DefaultFormattingConversionService;
|
||||
|
||||
/**
|
||||
* Tests to ensure the {@link DelegatingConversionService} properly delegates conversions to the {@link
|
||||
* org.springframework.core.convert.ConversionService} that is appropriate for the given source and return types.
|
||||
*
|
||||
* Tests to ensure the {@link DelegatingConversionService} properly delegates conversions to the
|
||||
* {@link org.springframework.core.convert.ConversionService} that is appropriate for the given source and return types.
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class DelegatingConversionServiceUnitTests {
|
||||
|
||||
private static final UUID RANDOM_UUID = UUID.fromString("9deccfd7-f892-4e26-a4d5-c92893392e78");
|
||||
private static final UUID RANDOM_UUID = UUID.fromString("9deccfd7-f892-4e26-a4d5-c92893392e78");
|
||||
|
||||
@Mock ConversionService conversionService;
|
||||
DelegatingConversionService delegatingConversionService;
|
||||
@Mock ConversionService conversionService;
|
||||
DelegatingConversionService delegatingConversionService;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
@Before
|
||||
public void setup() {
|
||||
|
||||
DefaultFormattingConversionService cs = new DefaultFormattingConversionService(false);
|
||||
cs.addConverter(UUIDConverter.INSTANCE);
|
||||
DefaultFormattingConversionService cs = new DefaultFormattingConversionService(false);
|
||||
cs.addConverter(UUIDConverter.INSTANCE);
|
||||
|
||||
delegatingConversionService = new DelegatingConversionService(conversionService, cs);
|
||||
|
||||
when(conversionService.canConvert(String.class, UUID.class)).thenReturn(false);
|
||||
when(conversionService.canConvert(UUID.class, String.class)).thenReturn(false);
|
||||
}
|
||||
delegatingConversionService = new DelegatingConversionService(conversionService, cs);
|
||||
|
||||
@Test
|
||||
public void shouldDelegateToProperConversionService() throws Exception {
|
||||
assertThat(delegatingConversionService.canConvert(String.class, UUID.class), is(true));
|
||||
assertThat(delegatingConversionService.convert(RANDOM_UUID.toString(), UUID.class), is(RANDOM_UUID));
|
||||
verifyConversionService();
|
||||
}
|
||||
when(conversionService.canConvert(String.class, UUID.class)).thenReturn(false);
|
||||
when(conversionService.canConvert(UUID.class, String.class)).thenReturn(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldConvertUUIDToString() throws Exception {
|
||||
assertThat(delegatingConversionService.canConvert(UUID.class, String.class), is(true));
|
||||
assertThat(delegatingConversionService.convert(RANDOM_UUID, String.class), is(RANDOM_UUID.toString()));
|
||||
verifyConversionService();
|
||||
}
|
||||
@Test
|
||||
public void shouldDelegateToProperConversionService() {
|
||||
|
||||
private void verifyConversionService() {
|
||||
verify(conversionService, times(0)).convert(Matchers.any(String.class), eq(UUID.class));
|
||||
verify(conversionService, times(0)).convert(Matchers.any(UUID.class), eq(String.class));
|
||||
}
|
||||
assertThat(delegatingConversionService.canConvert(String.class, UUID.class), is(true));
|
||||
assertThat(delegatingConversionService.convert(RANDOM_UUID.toString(), UUID.class), is(RANDOM_UUID));
|
||||
|
||||
verifyConversionService();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldConvertUUIDToString() {
|
||||
|
||||
assertThat(delegatingConversionService.canConvert(UUID.class, String.class), is(true));
|
||||
assertThat(delegatingConversionService.convert(RANDOM_UUID, String.class), is(RANDOM_UUID.toString()));
|
||||
|
||||
verifyConversionService();
|
||||
}
|
||||
|
||||
private void verifyConversionService() {
|
||||
|
||||
verify(conversionService, times(0)).convert(Matchers.any(String.class), eq(UUID.class));
|
||||
verify(conversionService, times(0)).convert(Matchers.any(UUID.class), eq(String.class));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,92 +1,44 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.rest.core.util;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Tests to verify that {@link UriUtils} can manipulate {@link URI}s.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
public class UriUtilsUnitTests {
|
||||
|
||||
private static final String BASE_URI_STR = "http://localhost:8080/data";
|
||||
private static final URI BASE_URI = URI.create(BASE_URI_STR);
|
||||
private static final String BASE_URI_STR = "http://localhost:8080/data";
|
||||
private static final URI BASE_URI = URI.create(BASE_URI_STR);
|
||||
|
||||
private static final String PERSON_2LVL_STR = BASE_URI_STR + "/person/1";
|
||||
private static final URI PERSON_2LVL_URI = URI.create(PERSON_2LVL_STR);
|
||||
private static final String PERSON_2LVL_STR = BASE_URI_STR + "/person/1";
|
||||
private static final URI PERSON_2LVL_URI = URI.create(PERSON_2LVL_STR);
|
||||
|
||||
@Test
|
||||
public void shouldValidateBaseURI() throws Exception {
|
||||
URI uri = new URI(BASE_URI + "/person/1");
|
||||
|
||||
assertThat(UriUtils.validBaseUri(BASE_URI, uri), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldIterateOverPathElements() throws Exception {
|
||||
final List<String> paths = new ArrayList<String>();
|
||||
Function<URI, Void> fn = new Function<URI, Void>() {
|
||||
@Override public Void apply(URI uri) {
|
||||
paths.add(uri.getPath());
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
UriUtils.foreach(BASE_URI, PERSON_2LVL_URI, fn);
|
||||
|
||||
assertThat(paths, hasSize(2));
|
||||
assertThat(paths, contains("person", "1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldExplodeRelativeURI() throws Exception {
|
||||
Stack<URI> uris = UriUtils.explode(BASE_URI, PERSON_2LVL_URI);
|
||||
|
||||
assertThat(uris, hasSize(2));
|
||||
assertThat(uris, contains(URI.create("person"), URI.create("1")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldMergeDifferentURIsIntoOne() throws Exception {
|
||||
String qrystr = "?queryParam=testValue";
|
||||
|
||||
URI uriWithQuery = URI.create(qrystr);
|
||||
URI uriWithPath = URI.create("person/1");
|
||||
|
||||
URI uri = UriUtils.merge(BASE_URI, uriWithPath, uriWithQuery);
|
||||
|
||||
assertThat(uri.toString(), is(PERSON_2LVL_STR + qrystr));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldStripTrailingSlashFromPath() throws Exception {
|
||||
URI uri = URI.create("person/");
|
||||
|
||||
String path = UriUtils.path(uri);
|
||||
|
||||
assertThat(path, is("person"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldStripTheLastPathSegmentFromAURI() throws Exception {
|
||||
URI uri = UriUtils.tail(BASE_URI, PERSON_2LVL_URI);
|
||||
|
||||
assertThat(uri, is(URI.create("1")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldBuildURIFromPathSegments() throws Exception {
|
||||
URI uri = UriUtils.buildUri(BASE_URI, "person", "1");
|
||||
|
||||
assertThat(uri, is(PERSON_2LVL_URI));
|
||||
}
|
||||
@Test
|
||||
public void shouldBuildURIFromPathSegments() throws Exception {
|
||||
|
||||
URI uri = UriUtils.buildUri(BASE_URI, "person", "1");
|
||||
assertThat(uri, is(PERSON_2LVL_URI));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,22 +30,22 @@ import org.springframework.util.Assert;
|
||||
@SuppressWarnings("deprecation")
|
||||
public class RepositoryRestConfiguration {
|
||||
|
||||
private URI baseUri = null;
|
||||
private int defaultPageSize = 20;
|
||||
private int maxPageSize = 1000;
|
||||
private String pageParamName = "page";
|
||||
private String limitParamName = "limit";
|
||||
private String sortParamName = "sort";
|
||||
private MediaType defaultMediaType = MediaType.APPLICATION_JSON;
|
||||
private boolean returnBodyOnCreate = false;
|
||||
private boolean returnBodyOnUpdate = false;
|
||||
private List<Class<?>> exposeIdsFor = new ArrayList<Class<?>>();
|
||||
private ResourceMappingConfiguration domainMappings = new ResourceMappingConfiguration();
|
||||
private ResourceMappingConfiguration repoMappings = new ResourceMappingConfiguration();
|
||||
private URI baseUri = null;
|
||||
private int defaultPageSize = 20;
|
||||
private int maxPageSize = 1000;
|
||||
private String pageParamName = "page";
|
||||
private String limitParamName = "limit";
|
||||
private String sortParamName = "sort";
|
||||
private MediaType defaultMediaType = MediaType.APPLICATION_JSON;
|
||||
private boolean returnBodyOnCreate = false;
|
||||
private boolean returnBodyOnUpdate = false;
|
||||
private List<Class<?>> exposeIdsFor = new ArrayList<Class<?>>();
|
||||
private ResourceMappingConfiguration domainMappings = new ResourceMappingConfiguration();
|
||||
private ResourceMappingConfiguration repoMappings = new ResourceMappingConfiguration();
|
||||
|
||||
/**
|
||||
* The base URI against which the exporter should calculate its links.
|
||||
*
|
||||
*
|
||||
* @return The base URI.
|
||||
*/
|
||||
public URI getBaseUri() {
|
||||
@@ -54,9 +54,8 @@ public class RepositoryRestConfiguration {
|
||||
|
||||
/**
|
||||
* The base URI against which the exporter should calculate its links.
|
||||
*
|
||||
* @param baseUri
|
||||
* The base URI.
|
||||
*
|
||||
* @param baseUri The base URI.
|
||||
*/
|
||||
public RepositoryRestConfiguration setBaseUri(URI baseUri) {
|
||||
Assert.notNull(baseUri, "The baseUri cannot be null.");
|
||||
@@ -66,7 +65,7 @@ public class RepositoryRestConfiguration {
|
||||
|
||||
/**
|
||||
* Get the default size of {@link org.springframework.data.domain.Pageable}s. Default is 20.
|
||||
*
|
||||
*
|
||||
* @return The default page size.
|
||||
*/
|
||||
public int getDefaultPageSize() {
|
||||
@@ -75,10 +74,8 @@ public class RepositoryRestConfiguration {
|
||||
|
||||
/**
|
||||
* Set the default size of {@link org.springframework.data.domain.Pageable}s.
|
||||
*
|
||||
* @param defaultPageSize
|
||||
* The default page size.
|
||||
*
|
||||
*
|
||||
* @param defaultPageSize The default page size.
|
||||
* @return {@literal this}
|
||||
*/
|
||||
public RepositoryRestConfiguration setDefaultPageSize(int defaultPageSize) {
|
||||
@@ -89,7 +86,7 @@ public class RepositoryRestConfiguration {
|
||||
|
||||
/**
|
||||
* Get the maximum size of pages.
|
||||
*
|
||||
*
|
||||
* @return Maximum page size.
|
||||
*/
|
||||
public int getMaxPageSize() {
|
||||
@@ -98,10 +95,8 @@ public class RepositoryRestConfiguration {
|
||||
|
||||
/**
|
||||
* Set the maximum size of pages.
|
||||
*
|
||||
* @param maxPageSize
|
||||
* Maximum page size.
|
||||
*
|
||||
*
|
||||
* @param maxPageSize Maximum page size.
|
||||
* @return {@literal this}
|
||||
*/
|
||||
public RepositoryRestConfiguration setMaxPageSize(int maxPageSize) {
|
||||
@@ -112,7 +107,7 @@ public class RepositoryRestConfiguration {
|
||||
|
||||
/**
|
||||
* Get the name of the URL query string parameter that indicates what page to return. Default is 'page'.
|
||||
*
|
||||
*
|
||||
* @return Name of the query parameter used to indicate the page number to return.
|
||||
*/
|
||||
public String getPageParamName() {
|
||||
@@ -121,10 +116,8 @@ public class RepositoryRestConfiguration {
|
||||
|
||||
/**
|
||||
* Set the name of the URL query string parameter that indicates what page to return.
|
||||
*
|
||||
* @param pageParamName
|
||||
* Name of the query parameter used to indicate the page number to return.
|
||||
*
|
||||
*
|
||||
* @param pageParamName Name of the query parameter used to indicate the page number to return.
|
||||
* @return {@literal this}
|
||||
*/
|
||||
public RepositoryRestConfiguration setPageParamName(String pageParamName) {
|
||||
@@ -136,7 +129,7 @@ public class RepositoryRestConfiguration {
|
||||
/**
|
||||
* Get the name of the URL query string parameter that indicates how many results to return at once. Default is
|
||||
* 'limit'.
|
||||
*
|
||||
*
|
||||
* @return Name of the query parameter used to indicate the maximum number of entries to return at a time.
|
||||
*/
|
||||
public String getLimitParamName() {
|
||||
@@ -145,10 +138,9 @@ public class RepositoryRestConfiguration {
|
||||
|
||||
/**
|
||||
* Set the name of the URL query string parameter that indicates how many results to return at once.
|
||||
*
|
||||
* @param limitParamName
|
||||
* Name of the query parameter used to indicate the maximum number of entries to return at a time.
|
||||
*
|
||||
*
|
||||
* @param limitParamName Name of the query parameter used to indicate the maximum number of entries to return at a
|
||||
* time.
|
||||
* @return {@literal this}
|
||||
*/
|
||||
public RepositoryRestConfiguration setLimitParamName(String limitParamName) {
|
||||
@@ -159,7 +151,7 @@ public class RepositoryRestConfiguration {
|
||||
|
||||
/**
|
||||
* Get the name of the URL query string parameter that indicates what direction to sort results. Default is 'sort'.
|
||||
*
|
||||
*
|
||||
* @return Name of the query string parameter used to indicate what field to sort on.
|
||||
*/
|
||||
public String getSortParamName() {
|
||||
@@ -168,10 +160,8 @@ public class RepositoryRestConfiguration {
|
||||
|
||||
/**
|
||||
* Set the name of the URL query string parameter that indicates what direction to sort results.
|
||||
*
|
||||
* @param sortParamName
|
||||
* Name of the query string parameter used to indicate what field to sort on.
|
||||
*
|
||||
*
|
||||
* @param sortParamName Name of the query string parameter used to indicate what field to sort on.
|
||||
* @return {@literal this}
|
||||
*/
|
||||
public RepositoryRestConfiguration setSortParamName(String sortParamName) {
|
||||
@@ -182,7 +172,7 @@ public class RepositoryRestConfiguration {
|
||||
|
||||
/**
|
||||
* Get the {@link MediaType} to use as a default when none is specified.
|
||||
*
|
||||
*
|
||||
* @return Default content type if none has been specified.
|
||||
*/
|
||||
public MediaType getDefaultMediaType() {
|
||||
@@ -191,10 +181,8 @@ public class RepositoryRestConfiguration {
|
||||
|
||||
/**
|
||||
* Set the {@link MediaType} to use as a default when none is specified.
|
||||
*
|
||||
* @param defaultMediaType
|
||||
* Default content type if none has been specified.
|
||||
*
|
||||
*
|
||||
* @param defaultMediaType Default content type if none has been specified.
|
||||
* @return {@literal this}
|
||||
*/
|
||||
public RepositoryRestConfiguration setDefaultMediaType(MediaType defaultMediaType) {
|
||||
@@ -204,7 +192,7 @@ public class RepositoryRestConfiguration {
|
||||
|
||||
/**
|
||||
* Whether to return a response body after creating an entity.
|
||||
*
|
||||
*
|
||||
* @return {@literal true} to return a body on create, {@literal false} otherwise.
|
||||
*/
|
||||
public boolean isReturnBodyOnCreate() {
|
||||
@@ -213,10 +201,8 @@ public class RepositoryRestConfiguration {
|
||||
|
||||
/**
|
||||
* Set whether to return a response body after creating an entity.
|
||||
*
|
||||
* @param returnBodyOnCreate
|
||||
* {@literal true} to return a body on create, {@literal false} otherwise.
|
||||
*
|
||||
*
|
||||
* @param returnBodyOnCreate {@literal true} to return a body on create, {@literal false} otherwise.
|
||||
* @return {@literal this}
|
||||
*/
|
||||
public RepositoryRestConfiguration setReturnBodyOnCreate(boolean returnBodyOnCreate) {
|
||||
@@ -226,7 +212,7 @@ public class RepositoryRestConfiguration {
|
||||
|
||||
/**
|
||||
* Whether to return a response body after updating an entity.
|
||||
*
|
||||
*
|
||||
* @return {@literal true} to return a body on update, {@literal false} otherwise.
|
||||
*/
|
||||
public boolean isReturnBodyOnUpdate() {
|
||||
@@ -235,9 +221,8 @@ public class RepositoryRestConfiguration {
|
||||
|
||||
/**
|
||||
* Sets whether to return a response body after updating an entity.
|
||||
*
|
||||
*
|
||||
* @param returnBodyOnUpdate
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public RepositoryRestConfiguration setReturnBodyOnUpdate(boolean returnBodyOnUpdate) {
|
||||
@@ -247,10 +232,8 @@ public class RepositoryRestConfiguration {
|
||||
|
||||
/**
|
||||
* Start configuration a {@link ResourceMapping} for a specific domain type.
|
||||
*
|
||||
* @param domainType
|
||||
* The {@link Class} of the domain type to configure a mapping for.
|
||||
*
|
||||
*
|
||||
* @param domainType The {@link Class} of the domain type to configure a mapping for.
|
||||
* @return A new {@link ResourceMapping} for configuring how a domain type is mapped.
|
||||
*/
|
||||
public ResourceMapping setResourceMappingForDomainType(Class<?> domainType) {
|
||||
@@ -259,10 +242,8 @@ public class RepositoryRestConfiguration {
|
||||
|
||||
/**
|
||||
* Get the {@link ResourceMapping} for a specific domain type.
|
||||
*
|
||||
* @param domainType
|
||||
* The {@link Class} of the domain type.
|
||||
*
|
||||
*
|
||||
* @param domainType The {@link Class} of the domain type.
|
||||
* @return A {@link ResourceMapping} for that domain type or {@literal null} if none exists.
|
||||
*/
|
||||
public ResourceMapping getResourceMappingForDomainType(Class<?> domainType) {
|
||||
@@ -271,10 +252,8 @@ public class RepositoryRestConfiguration {
|
||||
|
||||
/**
|
||||
* Whether there is a {@link ResourceMapping} for the given domain type.
|
||||
*
|
||||
* @param domainType
|
||||
* The domain type to find a {@link ResourceMapping} for.
|
||||
*
|
||||
*
|
||||
* @param domainType The domain type to find a {@link ResourceMapping} for.
|
||||
* @return {@literal true} if a {@link ResourceMapping} exists for this domain class, {@literal false} otherwise.
|
||||
*/
|
||||
public boolean hasResourceMappingForDomainType(Class<?> domainType) {
|
||||
@@ -283,7 +262,7 @@ public class RepositoryRestConfiguration {
|
||||
|
||||
/**
|
||||
* Get the {@link ResourceMappingConfiguration} that is currently configured.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ResourceMappingConfiguration getDomainTypesResourceMappingConfiguration() {
|
||||
@@ -292,10 +271,8 @@ public class RepositoryRestConfiguration {
|
||||
|
||||
/**
|
||||
* Start configuration a {@link ResourceMapping} for a specific repository interface.
|
||||
*
|
||||
* @param repositoryInterface
|
||||
* The {@link Class} of the repository interface to configure a mapping for.
|
||||
*
|
||||
*
|
||||
* @param repositoryInterface The {@link Class} of the repository interface to configure a mapping for.
|
||||
* @return A new {@link ResourceMapping} for configuring how a repository interface is mapped.
|
||||
*/
|
||||
public ResourceMapping setResourceMappingForRepository(Class<?> repositoryInterface) {
|
||||
@@ -304,10 +281,8 @@ public class RepositoryRestConfiguration {
|
||||
|
||||
/**
|
||||
* Get the {@link ResourceMapping} for a specific repository interface.
|
||||
*
|
||||
* @param repositoryInterface
|
||||
* The {@link Class} of the repository interface.
|
||||
*
|
||||
*
|
||||
* @param repositoryInterface The {@link Class} of the repository interface.
|
||||
* @return A {@link ResourceMapping} for that repository interface or {@literal null} if none exists.
|
||||
*/
|
||||
public ResourceMapping getResourceMappingForRepository(Class<?> repositoryInterface) {
|
||||
@@ -316,9 +291,8 @@ public class RepositoryRestConfiguration {
|
||||
|
||||
/**
|
||||
* Whether there is a {@link ResourceMapping} configured for this {@literal Repository} class.
|
||||
*
|
||||
*
|
||||
* @param repositoryInterface
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean hasResourceMappingForRepository(Class<?> repositoryInterface) {
|
||||
@@ -327,7 +301,7 @@ public class RepositoryRestConfiguration {
|
||||
|
||||
public ResourceMapping findRepositoryMappingForPath(String path) {
|
||||
Class<?> type = repoMappings.findTypeForPath(path);
|
||||
if(null == type) {
|
||||
if (null == type) {
|
||||
return null;
|
||||
}
|
||||
return repoMappings.getResourceMappingFor(type);
|
||||
@@ -335,10 +309,8 @@ public class RepositoryRestConfiguration {
|
||||
|
||||
/**
|
||||
* Should we expose the ID property for this domain type?
|
||||
*
|
||||
* @param domainType
|
||||
* The domain type we may need to expose the ID for.
|
||||
*
|
||||
*
|
||||
* @param domainType The domain type we may need to expose the ID for.
|
||||
* @return {@literal true} is the ID is to be exposed, {@literal false} otherwise.
|
||||
*/
|
||||
public boolean isIdExposedFor(Class<?> domainType) {
|
||||
@@ -347,10 +319,8 @@ public class RepositoryRestConfiguration {
|
||||
|
||||
/**
|
||||
* Set the list of domain types for which we will expose the ID value as a normal property.
|
||||
*
|
||||
* @param domainTypes
|
||||
* Array of types to expose IDs for.
|
||||
*
|
||||
*
|
||||
* @param domainTypes Array of types to expose IDs for.
|
||||
* @return {@literal this}
|
||||
*/
|
||||
public RepositoryRestConfiguration exposeIdsFor(Class<?>... domainTypes) {
|
||||
|
||||
@@ -26,101 +26,97 @@ import java.util.Map;
|
||||
@Deprecated
|
||||
public class ResourceMapping {
|
||||
|
||||
private String rel;
|
||||
private String path;
|
||||
private boolean exported = true;
|
||||
private final Map<String, ResourceMapping> resourceMappings = new HashMap<String, ResourceMapping>();
|
||||
private String rel;
|
||||
private String path;
|
||||
private boolean exported = true;
|
||||
private final Map<String, ResourceMapping> resourceMappings = new HashMap<String, ResourceMapping>();
|
||||
|
||||
public ResourceMapping() {
|
||||
}
|
||||
public ResourceMapping() {}
|
||||
|
||||
public ResourceMapping(Class<?> type) {
|
||||
rel = findRel(type);
|
||||
path = findPath(type);
|
||||
exported = findExported(type);
|
||||
}
|
||||
public ResourceMapping(Class<?> type) {
|
||||
rel = findRel(type);
|
||||
path = findPath(type);
|
||||
exported = findExported(type);
|
||||
}
|
||||
|
||||
public ResourceMapping(String rel, String path) {
|
||||
this.rel = rel;
|
||||
this.path = path;
|
||||
}
|
||||
public ResourceMapping(String rel, String path) {
|
||||
this.rel = rel;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public ResourceMapping(String rel, String path, boolean exported) {
|
||||
this.rel = rel;
|
||||
this.path = path;
|
||||
this.exported = exported;
|
||||
}
|
||||
public ResourceMapping(String rel, String path, boolean exported) {
|
||||
this.rel = rel;
|
||||
this.path = path;
|
||||
this.exported = exported;
|
||||
}
|
||||
|
||||
public String getRel() {
|
||||
return rel;
|
||||
}
|
||||
public String getRel() {
|
||||
return rel;
|
||||
}
|
||||
|
||||
public ResourceMapping setRel(String rel) {
|
||||
this.rel = rel;
|
||||
return this;
|
||||
}
|
||||
public ResourceMapping setRel(String rel) {
|
||||
this.rel = rel;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public ResourceMapping setPath(String path) {
|
||||
this.path = path;
|
||||
return this;
|
||||
}
|
||||
public ResourceMapping setPath(String path) {
|
||||
this.path = path;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isExported() {
|
||||
return exported;
|
||||
}
|
||||
public boolean isExported() {
|
||||
return exported;
|
||||
}
|
||||
|
||||
public ResourceMapping setExported(boolean exported) {
|
||||
this.exported = exported;
|
||||
return this;
|
||||
}
|
||||
public ResourceMapping setExported(boolean exported) {
|
||||
this.exported = exported;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ResourceMapping addResourceMappings(Map<String, ResourceMapping> mappings) {
|
||||
if(null == mappings) {
|
||||
return this;
|
||||
}
|
||||
public ResourceMapping addResourceMappings(Map<String, ResourceMapping> mappings) {
|
||||
if (null == mappings) {
|
||||
return this;
|
||||
}
|
||||
|
||||
resourceMappings.putAll(mappings);
|
||||
return this;
|
||||
}
|
||||
resourceMappings.putAll(mappings);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ResourceMapping addResourceMappingFor(String name) {
|
||||
ResourceMapping rm = new ResourceMapping();
|
||||
resourceMappings.put(name, rm);
|
||||
return rm;
|
||||
}
|
||||
public ResourceMapping addResourceMappingFor(String name) {
|
||||
ResourceMapping rm = new ResourceMapping();
|
||||
resourceMappings.put(name, rm);
|
||||
return rm;
|
||||
}
|
||||
|
||||
public ResourceMapping getResourceMappingFor(String name) {
|
||||
return resourceMappings.get(name);
|
||||
}
|
||||
public ResourceMapping getResourceMappingFor(String name) {
|
||||
return resourceMappings.get(name);
|
||||
}
|
||||
|
||||
public boolean hasResourceMappingFor(String name) {
|
||||
return resourceMappings.containsKey(name);
|
||||
}
|
||||
public boolean hasResourceMappingFor(String name) {
|
||||
return resourceMappings.containsKey(name);
|
||||
}
|
||||
|
||||
public Map<String, ResourceMapping> getResourceMappings() {
|
||||
return resourceMappings;
|
||||
}
|
||||
public Map<String, ResourceMapping> getResourceMappings() {
|
||||
return resourceMappings;
|
||||
}
|
||||
|
||||
public String getNameForPath(String path) {
|
||||
for(Map.Entry<String, ResourceMapping> mapping : resourceMappings.entrySet()) {
|
||||
if(mapping.getValue().getPath().equals(path)) {
|
||||
return mapping.getKey();
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
public String getNameForPath(String path) {
|
||||
for (Map.Entry<String, ResourceMapping> mapping : resourceMappings.entrySet()) {
|
||||
if (mapping.getValue().getPath().equals(path)) {
|
||||
return mapping.getKey();
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "ResourceMapping{" +
|
||||
"rel='" + rel + '\'' +
|
||||
", path='" + path + '\'' +
|
||||
", exported=" + exported +
|
||||
", resourceMappings=" + resourceMappings +
|
||||
'}';
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ResourceMapping{" + "rel='" + rel + '\'' + ", path='" + path + '\'' + ", exported=" + exported
|
||||
+ ", resourceMappings=" + resourceMappings + '}';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,41 +21,41 @@ import java.util.Map;
|
||||
/**
|
||||
* Manages the {@link ResourceMapping} configurations for any resources being exported. This includes domain entities
|
||||
* and repositories.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class ResourceMappingConfiguration {
|
||||
|
||||
private final Map<Class<?>, ResourceMapping> resourceMappings = new HashMap<Class<?>, ResourceMapping>();
|
||||
private final Map<Class<?>, ResourceMapping> resourceMappings = new HashMap<Class<?>, ResourceMapping>();
|
||||
|
||||
public ResourceMapping setResourceMappingFor(Class<?> type) {
|
||||
ResourceMapping rm = resourceMappings.get(type);
|
||||
if(null == rm) {
|
||||
rm = new ResourceMapping(type);
|
||||
resourceMappings.put(type, rm);
|
||||
}
|
||||
return rm;
|
||||
}
|
||||
public ResourceMapping setResourceMappingFor(Class<?> type) {
|
||||
ResourceMapping rm = resourceMappings.get(type);
|
||||
if (null == rm) {
|
||||
rm = new ResourceMapping(type);
|
||||
resourceMappings.put(type, rm);
|
||||
}
|
||||
return rm;
|
||||
}
|
||||
|
||||
public ResourceMapping getResourceMappingFor(Class<?> type) {
|
||||
return resourceMappings.get(type);
|
||||
}
|
||||
public ResourceMapping getResourceMappingFor(Class<?> type) {
|
||||
return resourceMappings.get(type);
|
||||
}
|
||||
|
||||
public boolean hasResourceMappingFor(Class<?> type) {
|
||||
return resourceMappings.containsKey(type);
|
||||
}
|
||||
public boolean hasResourceMappingFor(Class<?> type) {
|
||||
return resourceMappings.containsKey(type);
|
||||
}
|
||||
|
||||
public Class<?> findTypeForPath(String path) {
|
||||
if(null == path) {
|
||||
return null;
|
||||
}
|
||||
for(Map.Entry<Class<?>, ResourceMapping> entry : resourceMappings.entrySet()) {
|
||||
if(path.equals(entry.getValue().getPath())) {
|
||||
return entry.getKey();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public Class<?> findTypeForPath(String path) {
|
||||
if (null == path) {
|
||||
return null;
|
||||
}
|
||||
for (Map.Entry<Class<?>, ResourceMapping> entry : resourceMappings.entrySet()) {
|
||||
if (path.equals(entry.getValue().getPath())) {
|
||||
return entry.getKey();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,22 +5,22 @@ import org.springframework.validation.Errors;
|
||||
|
||||
/**
|
||||
* Exception that is thrown when a Spring {@link org.springframework.validation.Validator} throws an error.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
public class RepositoryConstraintViolationException extends DataIntegrityViolationException {
|
||||
|
||||
private static final long serialVersionUID = -4789377071564956366L;
|
||||
|
||||
|
||||
private final Errors errors;
|
||||
|
||||
public RepositoryConstraintViolationException(Errors errors) {
|
||||
super("Validation failed");
|
||||
this.errors = errors;
|
||||
}
|
||||
public RepositoryConstraintViolationException(Errors errors) {
|
||||
super("Validation failed");
|
||||
this.errors = errors;
|
||||
}
|
||||
|
||||
public Errors getErrors() {
|
||||
return errors;
|
||||
}
|
||||
public Errors getErrors() {
|
||||
return errors;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,58 +15,51 @@ import org.springframework.data.rest.repository.support.RepositoryInformationSup
|
||||
|
||||
/**
|
||||
* A {@link ConditionalGenericConverter} that can convert a {@link URI} domain entity.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
public class UriDomainClassConverter
|
||||
extends RepositoryInformationSupport
|
||||
implements ConditionalGenericConverter,
|
||||
InitializingBean {
|
||||
public class UriDomainClassConverter extends RepositoryInformationSupport implements ConditionalGenericConverter,
|
||||
InitializingBean {
|
||||
|
||||
private static TypeDescriptor STRING_TYPE = TypeDescriptor.valueOf(String.class);
|
||||
private static TypeDescriptor STRING_TYPE = TypeDescriptor.valueOf(String.class);
|
||||
|
||||
@Autowired
|
||||
private DomainClassConverter<?> domainClassConverter;
|
||||
private Set<ConvertiblePair> convertiblePairs = new HashSet<ConvertiblePair>();
|
||||
@Autowired private DomainClassConverter<?> domainClassConverter;
|
||||
private Set<ConvertiblePair> convertiblePairs = new HashSet<ConvertiblePair>();
|
||||
|
||||
@Override public void afterPropertiesSet() throws Exception {
|
||||
for(Class<?> domainType : repositories) {
|
||||
convertiblePairs.add(new ConvertiblePair(URI.class, domainType));
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
for (Class<?> domainType : repositories) {
|
||||
convertiblePairs.add(new ConvertiblePair(URI.class, domainType));
|
||||
}
|
||||
}
|
||||
|
||||
@Override public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
return URI.class.isAssignableFrom(sourceType.getType())
|
||||
&& (null != repositories.getPersistentEntity(targetType.getType()));
|
||||
}
|
||||
@Override
|
||||
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
return URI.class.isAssignableFrom(sourceType.getType())
|
||||
&& (null != repositories.getPersistentEntity(targetType.getType()));
|
||||
}
|
||||
|
||||
@Override public Set<ConvertiblePair> getConvertibleTypes() {
|
||||
return convertiblePairs;
|
||||
}
|
||||
@Override
|
||||
public Set<ConvertiblePair> getConvertibleTypes() {
|
||||
return convertiblePairs;
|
||||
}
|
||||
|
||||
@Override public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
PersistentEntity<?, ?> entity = repositories.getPersistentEntity(targetType.getType());
|
||||
if(null == entity || !domainClassConverter.matches(STRING_TYPE, targetType)) {
|
||||
throw new ConversionFailedException(
|
||||
sourceType,
|
||||
targetType,
|
||||
source,
|
||||
new IllegalArgumentException("No PersistentEntity information available for " + targetType.getType())
|
||||
);
|
||||
}
|
||||
@Override
|
||||
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
PersistentEntity<?, ?> entity = repositories.getPersistentEntity(targetType.getType());
|
||||
if (null == entity || !domainClassConverter.matches(STRING_TYPE, targetType)) {
|
||||
throw new ConversionFailedException(sourceType, targetType, source, new IllegalArgumentException(
|
||||
"No PersistentEntity information available for " + targetType.getType()));
|
||||
}
|
||||
|
||||
URI uri = (URI)source;
|
||||
String[] parts = uri.getPath().split("/");
|
||||
if(parts.length < 2) {
|
||||
throw new ConversionFailedException(
|
||||
sourceType,
|
||||
targetType,
|
||||
source,
|
||||
new IllegalArgumentException("Cannot resolve URI " + uri + ". Is it local or remote? Only local URIs are resolvable.")
|
||||
);
|
||||
}
|
||||
URI uri = (URI) source;
|
||||
String[] parts = uri.getPath().split("/");
|
||||
if (parts.length < 2) {
|
||||
throw new ConversionFailedException(sourceType, targetType, source, new IllegalArgumentException(
|
||||
"Cannot resolve URI " + uri + ". Is it local or remote? Only local URIs are resolvable."));
|
||||
}
|
||||
|
||||
return domainClassConverter.convert(parts[parts.length - 1], STRING_TYPE, targetType);
|
||||
}
|
||||
return domainClassConverter.convert(parts[parts.length - 1], STRING_TYPE, targetType);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,71 +16,73 @@ import org.springframework.validation.ObjectError;
|
||||
|
||||
/**
|
||||
* An {@link Errors} implementation for use in the events mechanism of Spring Data REST.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
public class ValidationErrors extends AbstractErrors {
|
||||
|
||||
private static final long serialVersionUID = 8141826537389141361L;
|
||||
|
||||
private String name;
|
||||
private Object entity;
|
||||
private PersistentEntity<?, ?> persistentEntity;
|
||||
private List<ObjectError> globalErrors = new ArrayList<ObjectError>();
|
||||
private List<FieldError> fieldErrors = new ArrayList<FieldError>();
|
||||
|
||||
public ValidationErrors(String name, Object entity, PersistentEntity<?, ?> persistentEntity) {
|
||||
this.name = name;
|
||||
this.entity = entity;
|
||||
this.persistentEntity = persistentEntity;
|
||||
}
|
||||
private String name;
|
||||
private Object entity;
|
||||
private PersistentEntity<?, ?> persistentEntity;
|
||||
private List<ObjectError> globalErrors = new ArrayList<ObjectError>();
|
||||
private List<FieldError> fieldErrors = new ArrayList<FieldError>();
|
||||
|
||||
@Override public String getObjectName() {
|
||||
return name;
|
||||
}
|
||||
public ValidationErrors(String name, Object entity, PersistentEntity<?, ?> persistentEntity) {
|
||||
this.name = name;
|
||||
this.entity = entity;
|
||||
this.persistentEntity = persistentEntity;
|
||||
}
|
||||
|
||||
@Override public void reject(String errorCode, Object[] errorArgs, String defaultMessage) {
|
||||
globalErrors.add(new ObjectError(name, new String[]{errorCode}, errorArgs, defaultMessage));
|
||||
}
|
||||
@Override
|
||||
public String getObjectName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override public void rejectValue(String field, String errorCode, Object[] errorArgs, String defaultMessage) {
|
||||
fieldErrors.add(new FieldError(name,
|
||||
field,
|
||||
getFieldValue(field),
|
||||
true,
|
||||
new String[]{errorCode},
|
||||
errorArgs,
|
||||
defaultMessage));
|
||||
}
|
||||
@Override
|
||||
public void reject(String errorCode, Object[] errorArgs, String defaultMessage) {
|
||||
globalErrors.add(new ObjectError(name, new String[] { errorCode }, errorArgs, defaultMessage));
|
||||
}
|
||||
|
||||
@Override public void addAllErrors(Errors errors) {
|
||||
globalErrors.addAll(errors.getAllErrors());
|
||||
}
|
||||
@Override
|
||||
public void rejectValue(String field, String errorCode, Object[] errorArgs, String defaultMessage) {
|
||||
fieldErrors.add(new FieldError(name, field, getFieldValue(field), true, new String[] { errorCode }, errorArgs,
|
||||
defaultMessage));
|
||||
}
|
||||
|
||||
@Override public List<ObjectError> getGlobalErrors() {
|
||||
return globalErrors;
|
||||
}
|
||||
@Override
|
||||
public void addAllErrors(Errors errors) {
|
||||
globalErrors.addAll(errors.getAllErrors());
|
||||
}
|
||||
|
||||
@Override public List<FieldError> getFieldErrors() {
|
||||
return fieldErrors;
|
||||
}
|
||||
@Override
|
||||
public List<ObjectError> getGlobalErrors() {
|
||||
return globalErrors;
|
||||
}
|
||||
|
||||
@Override public Object getFieldValue(String field) {
|
||||
PersistentProperty<?> prop = persistentEntity != null ? persistentEntity.getPersistentProperty(field) : null;
|
||||
if(null == prop) {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public List<FieldError> getFieldErrors() {
|
||||
return fieldErrors;
|
||||
}
|
||||
|
||||
Method getter = prop.getGetter();
|
||||
if(null != getter) {
|
||||
return invokeMethod(getter, entity);
|
||||
}
|
||||
Field fld = prop.getField();
|
||||
if(null != fld) {
|
||||
return getField(fld, entity);
|
||||
}
|
||||
@Override
|
||||
public Object getFieldValue(String field) {
|
||||
PersistentProperty<?> prop = persistentEntity != null ? persistentEntity.getPersistentProperty(field) : null;
|
||||
if (null == prop) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
Method getter = prop.getGetter();
|
||||
if (null != getter) {
|
||||
return invokeMethod(getter, entity);
|
||||
}
|
||||
Field fld = prop.getField();
|
||||
if (null != fld) {
|
||||
return getField(fld, entity);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,11 +11,11 @@ import org.springframework.core.convert.converter.Converter;
|
||||
/**
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@Target({ElementType.PARAMETER})
|
||||
@Target({ ElementType.PARAMETER })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
public @interface ConvertWith {
|
||||
|
||||
Class<? extends Converter<?, ?>> value();
|
||||
Class<? extends Converter<?, ?>> value();
|
||||
|
||||
}
|
||||
|
||||
@@ -8,12 +8,8 @@ import java.lang.annotation.Target;
|
||||
/**
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@Target({
|
||||
ElementType.TYPE,
|
||||
ElementType.FIELD,
|
||||
ElementType.METHOD
|
||||
})
|
||||
@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Description {
|
||||
String value();
|
||||
String value();
|
||||
}
|
||||
|
||||
@@ -9,10 +9,7 @@ import java.lang.annotation.Target;
|
||||
/**
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@Target({
|
||||
ElementType.TYPE,
|
||||
ElementType.METHOD
|
||||
})
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
public @interface HandleAfterCreate {
|
||||
|
||||
@@ -8,17 +8,14 @@ import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Denotes a component that should handle the {@literal afterDelete} event.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@Target({
|
||||
ElementType.TYPE,
|
||||
ElementType.METHOD
|
||||
})
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
public @interface HandleAfterDelete {
|
||||
|
||||
Class<?>[] value() default {};
|
||||
Class<?>[] value() default {};
|
||||
|
||||
}
|
||||
|
||||
@@ -8,17 +8,14 @@ import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Denotes a component that should handle the {@literal afterLinkDelete} event.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@Target({
|
||||
ElementType.TYPE,
|
||||
ElementType.METHOD
|
||||
})
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
public @interface HandleAfterLinkDelete {
|
||||
|
||||
Class<?>[] value() default {};
|
||||
Class<?>[] value() default {};
|
||||
|
||||
}
|
||||
|
||||
@@ -8,17 +8,14 @@ import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Denotes a component that should handle the {@literal afterLinkSave} event.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@Target({
|
||||
ElementType.TYPE,
|
||||
ElementType.METHOD
|
||||
})
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
public @interface HandleAfterLinkSave {
|
||||
|
||||
Class<?>[] value() default {};
|
||||
Class<?>[] value() default {};
|
||||
|
||||
}
|
||||
|
||||
@@ -8,17 +8,14 @@ import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Denotes a component that should handle the {@literal afterSave} event.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@Target({
|
||||
ElementType.TYPE,
|
||||
ElementType.METHOD
|
||||
})
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
public @interface HandleAfterSave {
|
||||
|
||||
Class<?>[] value() default {};
|
||||
Class<?>[] value() default {};
|
||||
|
||||
}
|
||||
|
||||
@@ -9,10 +9,7 @@ import java.lang.annotation.Target;
|
||||
/**
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@Target({
|
||||
ElementType.TYPE,
|
||||
ElementType.METHOD
|
||||
})
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
public @interface HandleBeforeCreate {
|
||||
|
||||
@@ -8,17 +8,14 @@ import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Denotes a component that should handle the {@literal beforeDelete} event.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@Target({
|
||||
ElementType.TYPE,
|
||||
ElementType.METHOD
|
||||
})
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
public @interface HandleBeforeDelete {
|
||||
|
||||
Class<?>[] value() default {};
|
||||
Class<?>[] value() default {};
|
||||
|
||||
}
|
||||
|
||||
@@ -8,17 +8,14 @@ import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Denotes a component that should handle the {@literal beforeLinkDelete} event.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@Target({
|
||||
ElementType.TYPE,
|
||||
ElementType.METHOD
|
||||
})
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
public @interface HandleBeforeLinkDelete {
|
||||
|
||||
Class<?>[] value() default {};
|
||||
Class<?>[] value() default {};
|
||||
|
||||
}
|
||||
|
||||
@@ -8,17 +8,14 @@ import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Denotes a component that should handle the {@literal beforeLinkSave} event.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@Target({
|
||||
ElementType.TYPE,
|
||||
ElementType.METHOD
|
||||
})
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
public @interface HandleBeforeLinkSave {
|
||||
|
||||
Class<?>[] value() default {};
|
||||
Class<?>[] value() default {};
|
||||
|
||||
}
|
||||
|
||||
@@ -8,17 +8,14 @@ import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Denotes a component that should handle the {@literal beforeSave} event.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@Target({
|
||||
ElementType.TYPE,
|
||||
ElementType.METHOD
|
||||
})
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
public @interface HandleBeforeSave {
|
||||
|
||||
Class<?>[] value() default {};
|
||||
Class<?>[] value() default {};
|
||||
|
||||
}
|
||||
|
||||
@@ -8,17 +8,17 @@ import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Advertises classes annotated with this that they are event handlers.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
public @interface RepositoryEventHandler {
|
||||
|
||||
/**
|
||||
* The list of {@link org.springframework.context.ApplicationEvent} classes this event handler cares about.
|
||||
*/
|
||||
Class<?>[] value() default {};
|
||||
/**
|
||||
* The list of {@link org.springframework.context.ApplicationEvent} classes this event handler cares about.
|
||||
*/
|
||||
Class<?>[] value() default {};
|
||||
|
||||
}
|
||||
|
||||
@@ -9,37 +9,33 @@ import java.lang.annotation.Target;
|
||||
/**
|
||||
* Annotate a {@link org.springframework.data.repository.Repository} with this to influence how it is exported and what
|
||||
* the value of the {@literal rel} attribute will be in links.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@Target({
|
||||
ElementType.FIELD,
|
||||
ElementType.METHOD,
|
||||
ElementType.TYPE
|
||||
})
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
public @interface RestResource {
|
||||
|
||||
/**
|
||||
* Flag indicating whether this resource is exported at all.
|
||||
*
|
||||
* @return {@literal true} if the resource is to be exported, {@literal false} otherwise.
|
||||
*/
|
||||
boolean exported() default true;
|
||||
/**
|
||||
* Flag indicating whether this resource is exported at all.
|
||||
*
|
||||
* @return {@literal true} if the resource is to be exported, {@literal false} otherwise.
|
||||
*/
|
||||
boolean exported() default true;
|
||||
|
||||
/**
|
||||
* The path segment under which this resource is to be exported.
|
||||
*
|
||||
* @return A valid path segment.
|
||||
*/
|
||||
String path() default "";
|
||||
/**
|
||||
* The path segment under which this resource is to be exported.
|
||||
*
|
||||
* @return A valid path segment.
|
||||
*/
|
||||
String path() default "";
|
||||
|
||||
/**
|
||||
* The rel value to use when generating links to this resource.
|
||||
*
|
||||
* @return A valid rel value.
|
||||
*/
|
||||
String rel() default "";
|
||||
/**
|
||||
* The rel value to use when generating links to this resource.
|
||||
*
|
||||
* @return A valid rel value.
|
||||
*/
|
||||
String rel() default "";
|
||||
|
||||
}
|
||||
|
||||
@@ -8,147 +8,125 @@ import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
|
||||
/**
|
||||
* Abstract class that listens for generic {@link RepositoryEvent}s and dispatches them to a specific
|
||||
* method based on the event type.
|
||||
*
|
||||
* Abstract class that listens for generic {@link RepositoryEvent}s and dispatches them to a specific method based on
|
||||
* the event type.
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
public abstract class AbstractRepositoryEventListener<T> implements ApplicationListener<RepositoryEvent>,
|
||||
ApplicationContextAware {
|
||||
ApplicationContextAware {
|
||||
|
||||
private final Class<?> INTERESTED_TYPE = resolveTypeArgument(getClass(), AbstractRepositoryEventListener.class);
|
||||
protected ApplicationContext applicationContext;
|
||||
|
||||
@Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
@Override public final void onApplicationEvent(RepositoryEvent event) {
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
@Override
|
||||
public final void onApplicationEvent(RepositoryEvent event) {
|
||||
Class<?> srcType = event.getSource().getClass();
|
||||
if(null != INTERESTED_TYPE && !INTERESTED_TYPE.isAssignableFrom(srcType)) {
|
||||
if (null != INTERESTED_TYPE && !INTERESTED_TYPE.isAssignableFrom(srcType)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(event instanceof BeforeSaveEvent) {
|
||||
onBeforeSave((T)event.getSource());
|
||||
} else if(event instanceof BeforeCreateEvent) {
|
||||
onBeforeCreate((T)event.getSource());
|
||||
} else if(event instanceof AfterCreateEvent) {
|
||||
onAfterCreate((T)event.getSource());
|
||||
} else if(event instanceof AfterSaveEvent) {
|
||||
onAfterSave((T)event.getSource());
|
||||
} else if(event instanceof BeforeLinkSaveEvent) {
|
||||
onBeforeLinkSave((T)event.getSource(), ((BeforeLinkSaveEvent)event).getLinked());
|
||||
} else if(event instanceof AfterLinkSaveEvent) {
|
||||
onAfterLinkSave((T)event.getSource(), ((AfterLinkSaveEvent)event).getLinked());
|
||||
} else if(event instanceof BeforeLinkDeleteEvent) {
|
||||
onBeforeLinkDelete((T)event.getSource(), ((BeforeLinkDeleteEvent)event).getLinked());
|
||||
} else if(event instanceof AfterLinkDeleteEvent) {
|
||||
onAfterLinkDelete((T)event.getSource(), ((AfterLinkDeleteEvent)event).getLinked());
|
||||
} else if(event instanceof BeforeDeleteEvent) {
|
||||
onBeforeDelete((T)event.getSource());
|
||||
} else if(event instanceof AfterDeleteEvent) {
|
||||
onAfterDelete((T)event.getSource());
|
||||
if (event instanceof BeforeSaveEvent) {
|
||||
onBeforeSave((T) event.getSource());
|
||||
} else if (event instanceof BeforeCreateEvent) {
|
||||
onBeforeCreate((T) event.getSource());
|
||||
} else if (event instanceof AfterCreateEvent) {
|
||||
onAfterCreate((T) event.getSource());
|
||||
} else if (event instanceof AfterSaveEvent) {
|
||||
onAfterSave((T) event.getSource());
|
||||
} else if (event instanceof BeforeLinkSaveEvent) {
|
||||
onBeforeLinkSave((T) event.getSource(), ((BeforeLinkSaveEvent) event).getLinked());
|
||||
} else if (event instanceof AfterLinkSaveEvent) {
|
||||
onAfterLinkSave((T) event.getSource(), ((AfterLinkSaveEvent) event).getLinked());
|
||||
} else if (event instanceof BeforeLinkDeleteEvent) {
|
||||
onBeforeLinkDelete((T) event.getSource(), ((BeforeLinkDeleteEvent) event).getLinked());
|
||||
} else if (event instanceof AfterLinkDeleteEvent) {
|
||||
onAfterLinkDelete((T) event.getSource(), ((AfterLinkDeleteEvent) event).getLinked());
|
||||
} else if (event instanceof BeforeDeleteEvent) {
|
||||
onBeforeDelete((T) event.getSource());
|
||||
} else if (event instanceof AfterDeleteEvent) {
|
||||
onAfterDelete((T) event.getSource());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method if you are interested in {@literal beforeCreate} events.
|
||||
*
|
||||
* @param entity
|
||||
* The entity being created.
|
||||
*
|
||||
* @param entity The entity being created.
|
||||
*/
|
||||
protected void onBeforeCreate(T entity) {
|
||||
}
|
||||
protected void onBeforeCreate(T entity) {}
|
||||
|
||||
/**
|
||||
* Override this method if you are interested in {@literal afterCreate} events.
|
||||
*
|
||||
* @param entity
|
||||
* The entity that was created.
|
||||
*
|
||||
* @param entity The entity that was created.
|
||||
*/
|
||||
protected void onAfterCreate(T entity) {
|
||||
}
|
||||
protected void onAfterCreate(T entity) {}
|
||||
|
||||
/**
|
||||
* Override this method if you are interested in {@literal beforeSave} events.
|
||||
*
|
||||
* @param entity
|
||||
* The entity being saved.
|
||||
*
|
||||
* @param entity The entity being saved.
|
||||
*/
|
||||
protected void onBeforeSave(T entity) {
|
||||
}
|
||||
protected void onBeforeSave(T entity) {}
|
||||
|
||||
/**
|
||||
* Override this method if you are interested in {@literal afterSave} events.
|
||||
*
|
||||
* @param entity
|
||||
* The entity that was just saved.
|
||||
*
|
||||
* @param entity The entity that was just saved.
|
||||
*/
|
||||
protected void onAfterSave(T entity) {
|
||||
}
|
||||
protected void onAfterSave(T entity) {}
|
||||
|
||||
/**
|
||||
* Override this method if you are interested in {@literal beforeLinkSave} events.
|
||||
*
|
||||
* @param parent
|
||||
* The parent entity to which the child object is linked.
|
||||
* @param linked
|
||||
* The linked, child entity.
|
||||
*
|
||||
* @param parent The parent entity to which the child object is linked.
|
||||
* @param linked The linked, child entity.
|
||||
*/
|
||||
protected void onBeforeLinkSave(T parent, Object linked) {
|
||||
}
|
||||
protected void onBeforeLinkSave(T parent, Object linked) {}
|
||||
|
||||
/**
|
||||
* Override this method if you are interested in {@literal afterLinkSave} events.
|
||||
*
|
||||
* @param parent
|
||||
* The parent entity to which the child object is linked.
|
||||
* @param linked
|
||||
* The linked, child entity.
|
||||
*
|
||||
* @param parent The parent entity to which the child object is linked.
|
||||
* @param linked The linked, child entity.
|
||||
*/
|
||||
protected void onAfterLinkSave(T parent, Object linked) {
|
||||
}
|
||||
protected void onAfterLinkSave(T parent, Object linked) {}
|
||||
|
||||
/**
|
||||
* Override this method if you are interested in {@literal beforeLinkDelete} events.
|
||||
*
|
||||
* @param parent
|
||||
* The parent entity to which the child object is linked.
|
||||
* @param linked
|
||||
* The linked, child entity.
|
||||
*
|
||||
* @param parent The parent entity to which the child object is linked.
|
||||
* @param linked The linked, child entity.
|
||||
*/
|
||||
protected void onBeforeLinkDelete(T parent, Object linked) {
|
||||
}
|
||||
protected void onBeforeLinkDelete(T parent, Object linked) {}
|
||||
|
||||
/**
|
||||
* Override this method if you are interested in {@literal afterLinkDelete} events.
|
||||
*
|
||||
* @param parent
|
||||
* The parent entity to which the child object is linked.
|
||||
* @param linked
|
||||
* The linked, child entity.
|
||||
*
|
||||
* @param parent The parent entity to which the child object is linked.
|
||||
* @param linked The linked, child entity.
|
||||
*/
|
||||
protected void onAfterLinkDelete(T parent, Object linked) {
|
||||
}
|
||||
protected void onAfterLinkDelete(T parent, Object linked) {}
|
||||
|
||||
/**
|
||||
* Override this method if you are interested in {@literal beforeDelete} events.
|
||||
*
|
||||
* @param entity
|
||||
* The entity that is being deleted.
|
||||
*
|
||||
* @param entity The entity that is being deleted.
|
||||
*/
|
||||
protected void onBeforeDelete(T entity) {
|
||||
}
|
||||
protected void onBeforeDelete(T entity) {}
|
||||
|
||||
/**
|
||||
* Override this method if you are interested in {@literal afterDelete} events.
|
||||
*
|
||||
* @param entity
|
||||
* The entity that was just deleted.
|
||||
*
|
||||
* @param entity The entity that was just deleted.
|
||||
*/
|
||||
protected void onAfterDelete(T entity) {
|
||||
}
|
||||
protected void onAfterDelete(T entity) {}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,11 +2,11 @@ package org.springframework.data.rest.repository.context;
|
||||
|
||||
/**
|
||||
* Event that is emitted after a new entity is saved.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
public class AfterCreateEvent extends RepositoryEvent {
|
||||
|
||||
|
||||
private static final long serialVersionUID = -7673953693485678403L;
|
||||
|
||||
public AfterCreateEvent(Object source) {
|
||||
|
||||
@@ -2,14 +2,14 @@ package org.springframework.data.rest.repository.context;
|
||||
|
||||
/**
|
||||
* Emitted after the entity is deleted from the repository.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
public class AfterDeleteEvent extends RepositoryEvent {
|
||||
|
||||
|
||||
private static final long serialVersionUID = -6090615345948638970L;
|
||||
|
||||
public AfterDeleteEvent(Object source) {
|
||||
super(source);
|
||||
}
|
||||
super(source);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package org.springframework.data.rest.repository.context;
|
||||
|
||||
/**
|
||||
* Emitted after a link to a related object is deleted from the parent.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
public class AfterLinkDeleteEvent extends LinkSaveEvent {
|
||||
@@ -10,6 +10,6 @@ public class AfterLinkDeleteEvent extends LinkSaveEvent {
|
||||
private static final long serialVersionUID = 3887575011761146290L;
|
||||
|
||||
public AfterLinkDeleteEvent(Object source, Object linked) {
|
||||
super(source, linked);
|
||||
}
|
||||
super(source, linked);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,14 +2,14 @@ package org.springframework.data.rest.repository.context;
|
||||
|
||||
/**
|
||||
* Emitted after saving a linked object to its parent in the repository.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
public class AfterLinkSaveEvent extends LinkSaveEvent {
|
||||
|
||||
|
||||
private static final long serialVersionUID = 261522353893713633L;
|
||||
|
||||
public AfterLinkSaveEvent(Object source, Object child) {
|
||||
super(source, child);
|
||||
}
|
||||
super(source, child);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,14 +2,14 @@ package org.springframework.data.rest.repository.context;
|
||||
|
||||
/**
|
||||
* Emitted after a save to the repository.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
public class AfterSaveEvent extends RepositoryEvent {
|
||||
|
||||
|
||||
private static final long serialVersionUID = 8568843338617401903L;
|
||||
|
||||
public AfterSaveEvent(Object source) {
|
||||
super(source);
|
||||
}
|
||||
super(source);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,126 +31,119 @@ import org.springframework.util.ReflectionUtils;
|
||||
/**
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
public class AnnotatedHandlerBeanPostProcessor implements ApplicationListener<RepositoryEvent>,
|
||||
BeanPostProcessor {
|
||||
public class AnnotatedHandlerBeanPostProcessor implements ApplicationListener<RepositoryEvent>, BeanPostProcessor {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(
|
||||
AnnotatedHandlerBeanPostProcessor.class);
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AnnotatedHandlerBeanPostProcessor.class);
|
||||
private final MultiValueMap<Class<? extends RepositoryEvent>, EventHandlerMethod> handlerMethods = new LinkedMultiValueMap<Class<? extends RepositoryEvent>, AnnotatedHandlerBeanPostProcessor.EventHandlerMethod>();
|
||||
|
||||
@Override public void onApplicationEvent(RepositoryEvent event) {
|
||||
@Override
|
||||
public void onApplicationEvent(RepositoryEvent event) {
|
||||
Class<? extends RepositoryEvent> eventType = event.getClass();
|
||||
if(!handlerMethods.containsKey(eventType)) {
|
||||
if (!handlerMethods.containsKey(eventType)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for(EventHandlerMethod handlerMethod : handlerMethods.get(eventType)) {
|
||||
for (EventHandlerMethod handlerMethod : handlerMethods.get(eventType)) {
|
||||
try {
|
||||
Object src = event.getSource();
|
||||
|
||||
if(!ClassUtils.isAssignable(handlerMethod.targetType, src.getClass())) {
|
||||
if (!ClassUtils.isAssignable(handlerMethod.targetType, src.getClass())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
List<Object> params = new ArrayList<Object>();
|
||||
params.add(src);
|
||||
if(event instanceof BeforeLinkSaveEvent) {
|
||||
params.add(((BeforeLinkSaveEvent)event).getLinked());
|
||||
} else if(event instanceof AfterLinkSaveEvent) {
|
||||
params.add(((AfterLinkSaveEvent)event).getLinked());
|
||||
if (event instanceof BeforeLinkSaveEvent) {
|
||||
params.add(((BeforeLinkSaveEvent) event).getLinked());
|
||||
} else if (event instanceof AfterLinkSaveEvent) {
|
||||
params.add(((AfterLinkSaveEvent) event).getLinked());
|
||||
}
|
||||
|
||||
if(LOG.isDebugEnabled()) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Invoking " + event.getClass().getSimpleName() + " handler for " + event.getSource());
|
||||
}
|
||||
handlerMethod.method.invoke(handlerMethod.handler, params.toArray());
|
||||
|
||||
} catch(Exception e) {
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException {
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException {
|
||||
final Class<?> beanType = bean.getClass();
|
||||
|
||||
RepositoryEventHandler typeAnno = AnnotationUtils.findAnnotation(beanType, RepositoryEventHandler.class);
|
||||
if(null == typeAnno) {
|
||||
if (null == typeAnno) {
|
||||
return bean;
|
||||
}
|
||||
|
||||
Class<?>[] targetTypes = typeAnno.value();
|
||||
if(targetTypes.length == 0) {
|
||||
targetTypes = new Class<?>[]{null};
|
||||
if (targetTypes.length == 0) {
|
||||
targetTypes = new Class<?>[] { null };
|
||||
}
|
||||
|
||||
for(final Class<?> targetType : targetTypes) {
|
||||
ReflectionUtils.doWithMethods(
|
||||
beanType,
|
||||
new ReflectionUtils.MethodCallback() {
|
||||
@Override public void doWith(Method method)
|
||||
throws IllegalArgumentException, IllegalAccessException {
|
||||
inspect(targetType, bean, method, HandleBeforeCreate.class, BeforeCreateEvent.class);
|
||||
inspect(targetType, bean, method, HandleAfterCreate.class, AfterCreateEvent.class);
|
||||
inspect(targetType, bean, method, HandleBeforeSave.class, BeforeSaveEvent.class);
|
||||
inspect(targetType, bean, method, HandleAfterSave.class, AfterSaveEvent.class);
|
||||
inspect(targetType, bean, method, HandleBeforeLinkSave.class, BeforeLinkSaveEvent.class);
|
||||
inspect(targetType, bean, method, HandleAfterLinkSave.class, AfterLinkSaveEvent.class);
|
||||
inspect(targetType, bean, method, HandleBeforeDelete.class, BeforeDeleteEvent.class);
|
||||
inspect(targetType, bean, method, HandleAfterDelete.class, AfterDeleteEvent.class);
|
||||
inspect(targetType, bean, method, HandleBeforeLinkDelete.class, BeforeLinkDeleteEvent.class);
|
||||
inspect(targetType, bean, method, HandleAfterLinkDelete.class, AfterLinkDeleteEvent.class);
|
||||
}
|
||||
},
|
||||
new ReflectionUtils.MethodFilter() {
|
||||
@Override public boolean matches(Method method) {
|
||||
return (!method.isSynthetic()
|
||||
&& !method.isBridge()
|
||||
&& method.getDeclaringClass() != Object.class
|
||||
&& !method.getName().contains("$"));
|
||||
}
|
||||
}
|
||||
);
|
||||
for (final Class<?> targetType : targetTypes) {
|
||||
ReflectionUtils.doWithMethods(beanType, new ReflectionUtils.MethodCallback() {
|
||||
@Override
|
||||
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
|
||||
inspect(targetType, bean, method, HandleBeforeCreate.class, BeforeCreateEvent.class);
|
||||
inspect(targetType, bean, method, HandleAfterCreate.class, AfterCreateEvent.class);
|
||||
inspect(targetType, bean, method, HandleBeforeSave.class, BeforeSaveEvent.class);
|
||||
inspect(targetType, bean, method, HandleAfterSave.class, AfterSaveEvent.class);
|
||||
inspect(targetType, bean, method, HandleBeforeLinkSave.class, BeforeLinkSaveEvent.class);
|
||||
inspect(targetType, bean, method, HandleAfterLinkSave.class, AfterLinkSaveEvent.class);
|
||||
inspect(targetType, bean, method, HandleBeforeDelete.class, BeforeDeleteEvent.class);
|
||||
inspect(targetType, bean, method, HandleAfterDelete.class, AfterDeleteEvent.class);
|
||||
inspect(targetType, bean, method, HandleBeforeLinkDelete.class, BeforeLinkDeleteEvent.class);
|
||||
inspect(targetType, bean, method, HandleAfterLinkDelete.class, AfterLinkDeleteEvent.class);
|
||||
}
|
||||
}, new ReflectionUtils.MethodFilter() {
|
||||
@Override
|
||||
public boolean matches(Method method) {
|
||||
return (!method.isSynthetic() && !method.isBridge() && method.getDeclaringClass() != Object.class && !method
|
||||
.getName().contains("$"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
private <T extends Annotation> void inspect(Class<?> targetType,
|
||||
Object handler,
|
||||
Method method,
|
||||
Class<T> annoType,
|
||||
Class<? extends RepositoryEvent> eventType) {
|
||||
private <T extends Annotation> void inspect(Class<?> targetType, Object handler, Method method, Class<T> annoType,
|
||||
Class<? extends RepositoryEvent> eventType) {
|
||||
T anno = method.getAnnotation(annoType);
|
||||
if(null != anno) {
|
||||
if (null != anno) {
|
||||
try {
|
||||
Class<?>[] targetTypes;
|
||||
if(null == targetType) {
|
||||
targetTypes = (Class<?>[])anno.getClass().getMethod("value", new Class[0]).invoke(anno);
|
||||
if (null == targetType) {
|
||||
targetTypes = (Class<?>[]) anno.getClass().getMethod("value", new Class[0]).invoke(anno);
|
||||
} else {
|
||||
targetTypes = new Class<?>[]{targetType};
|
||||
targetTypes = new Class<?>[] { targetType };
|
||||
}
|
||||
for(Class<?> type : targetTypes) {
|
||||
for (Class<?> type : targetTypes) {
|
||||
EventHandlerMethod m = new EventHandlerMethod(type, handler, method);
|
||||
if(LOG.isDebugEnabled()) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Annotated handler method found: " + m);
|
||||
}
|
||||
handlerMethods.add(eventType, m);
|
||||
}
|
||||
} catch(NoSuchMethodException e) {
|
||||
if(LOG.isDebugEnabled()) {
|
||||
} catch (NoSuchMethodException e) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug(e.getMessage(), e);
|
||||
}
|
||||
} catch(InvocationTargetException e) {
|
||||
if(LOG.isDebugEnabled()) {
|
||||
} catch (InvocationTargetException e) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug(e.getMessage(), e);
|
||||
}
|
||||
} catch(IllegalAccessException e) {
|
||||
if(LOG.isDebugEnabled()) {
|
||||
} catch (IllegalAccessException e) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
@@ -159,8 +152,8 @@ public class AnnotatedHandlerBeanPostProcessor implements ApplicationListener<Re
|
||||
|
||||
private class EventHandlerMethod {
|
||||
final Class<?> targetType;
|
||||
final Method method;
|
||||
final Object handler;
|
||||
final Method method;
|
||||
final Object handler;
|
||||
|
||||
private EventHandlerMethod(Class<?> targetType, Object handler, Method method) {
|
||||
this.targetType = targetType;
|
||||
@@ -168,12 +161,9 @@ public class AnnotatedHandlerBeanPostProcessor implements ApplicationListener<Re
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "EventHandlerMethod{" +
|
||||
"targetType=" + targetType +
|
||||
", method=" + method +
|
||||
", handler=" + handler +
|
||||
'}';
|
||||
@Override
|
||||
public String toString() {
|
||||
return "EventHandlerMethod{" + "targetType=" + targetType + ", method=" + method + ", handler=" + handler + '}';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ package org.springframework.data.rest.repository.context;
|
||||
|
||||
/**
|
||||
* Event emitted before an entity is saved for the first time.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
public class BeforeCreateEvent extends RepositoryEvent {
|
||||
|
||||
@@ -2,7 +2,7 @@ package org.springframework.data.rest.repository.context;
|
||||
|
||||
/**
|
||||
* Emitted before an entity is deleted from the repository.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||
*/
|
||||
public class BeforeDeleteEvent extends RepositoryEvent {
|
||||
@@ -10,6 +10,6 @@ public class BeforeDeleteEvent extends RepositoryEvent {
|
||||
private static final long serialVersionUID = 9150212393209433211L;
|
||||
|
||||
public BeforeDeleteEvent(Object source) {
|
||||
super(source);
|
||||
}
|
||||
super(source);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package org.springframework.data.rest.repository.context;
|
||||
|
||||
/**
|
||||
* Emitted before a link to a related object is deleted from the parent.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
public class BeforeLinkDeleteEvent extends LinkSaveEvent {
|
||||
@@ -10,6 +10,6 @@ public class BeforeLinkDeleteEvent extends LinkSaveEvent {
|
||||
private static final long serialVersionUID = -973540913790564962L;
|
||||
|
||||
public BeforeLinkDeleteEvent(Object source, Object linked) {
|
||||
super(source, linked);
|
||||
}
|
||||
super(source, linked);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package org.springframework.data.rest.repository.context;
|
||||
|
||||
/**
|
||||
* Emitted before a linked object is saved to the repository.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||
*/
|
||||
public class BeforeLinkSaveEvent extends LinkSaveEvent {
|
||||
@@ -10,6 +10,6 @@ public class BeforeLinkSaveEvent extends LinkSaveEvent {
|
||||
private static final long serialVersionUID = 4836932640633578985L;
|
||||
|
||||
public BeforeLinkSaveEvent(Object source, Object linked) {
|
||||
super(source, linked);
|
||||
}
|
||||
super(source, linked);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package org.springframework.data.rest.repository.context;
|
||||
|
||||
/**
|
||||
* An event to encapsulate an exception occurring anywhere within the REST exporter.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
public class ExceptionEvent extends RepositoryEvent {
|
||||
@@ -10,15 +10,15 @@ public class ExceptionEvent extends RepositoryEvent {
|
||||
private static final long serialVersionUID = 6614805546974091704L;
|
||||
|
||||
public ExceptionEvent(Throwable t) {
|
||||
super(t);
|
||||
}
|
||||
super(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the source of this exception event.
|
||||
*
|
||||
* @return The {@link Throwable} that is the source of this exception event.
|
||||
*/
|
||||
public Throwable getException() {
|
||||
return (Throwable)getSource();
|
||||
}
|
||||
/**
|
||||
* Get the source of this exception event.
|
||||
*
|
||||
* @return The {@link Throwable} that is the source of this exception event.
|
||||
*/
|
||||
public Throwable getException() {
|
||||
return (Throwable) getSource();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package org.springframework.data.rest.repository.context;
|
||||
|
||||
/**
|
||||
* Base class for {@link RepositoryEvent}s that deal with saving/updating or deleting a linked object.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
public abstract class LinkSaveEvent extends RepositoryEvent {
|
||||
@@ -10,18 +10,18 @@ public abstract class LinkSaveEvent extends RepositoryEvent {
|
||||
private static final long serialVersionUID = -9071648572128698903L;
|
||||
private final Object linked;
|
||||
|
||||
public LinkSaveEvent(Object source, Object linked) {
|
||||
super(source);
|
||||
this.linked = linked;
|
||||
}
|
||||
public LinkSaveEvent(Object source, Object linked) {
|
||||
super(source);
|
||||
this.linked = linked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the linked object.
|
||||
*
|
||||
* @return The entity representing the right-hand side of this relationship.
|
||||
*/
|
||||
public Object getLinked() {
|
||||
return linked;
|
||||
}
|
||||
/**
|
||||
* Get the linked object.
|
||||
*
|
||||
* @return The entity representing the right-hand side of this relationship.
|
||||
*/
|
||||
public Object getLinked() {
|
||||
return linked;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,46 +18,47 @@ import org.springframework.hateoas.ResourceProcessor;
|
||||
*/
|
||||
public class PersistentEntityResourceProcessor implements ResourceProcessor<PersistentEntityResource<?>> {
|
||||
|
||||
private final List<DomainTypeResourceProcessor> resourceProcessors = new ArrayList<DomainTypeResourceProcessor>();
|
||||
private final List<DomainTypeResourceProcessor> resourceProcessors = new ArrayList<DomainTypeResourceProcessor>();
|
||||
|
||||
@Autowired
|
||||
public PersistentEntityResourceProcessor(Repositories repositories,
|
||||
List<ResourceProcessor<Resource<?>>> resourceProcessors) {
|
||||
if(null != resourceProcessors) {
|
||||
for(ResourceProcessor<Resource<?>> rp : resourceProcessors) {
|
||||
TypeInformation<?> typeInfo = ClassTypeInformation.from(rp.getClass());
|
||||
TypeInformation<?> domainType = typeInfo.getTypeArguments().get(0);
|
||||
if(null != repositories.getPersistentEntity(domainType.getType())) {
|
||||
this.resourceProcessors.add(new DomainTypeResourceProcessor(domainType.getType(), rp));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@Autowired
|
||||
public PersistentEntityResourceProcessor(Repositories repositories,
|
||||
List<ResourceProcessor<Resource<?>>> resourceProcessors) {
|
||||
if (null != resourceProcessors) {
|
||||
for (ResourceProcessor<Resource<?>> rp : resourceProcessors) {
|
||||
TypeInformation<?> typeInfo = ClassTypeInformation.from(rp.getClass());
|
||||
TypeInformation<?> domainType = typeInfo.getTypeArguments().get(0);
|
||||
if (null != repositories.getPersistentEntity(domainType.getType())) {
|
||||
this.resourceProcessors.add(new DomainTypeResourceProcessor(domainType.getType(), rp));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override public PersistentEntityResource<?> process(PersistentEntityResource<?> resource) {
|
||||
Object content = resource.getContent();
|
||||
if(null == content) {
|
||||
return resource;
|
||||
}
|
||||
@Override
|
||||
public PersistentEntityResource<?> process(PersistentEntityResource<?> resource) {
|
||||
Object content = resource.getContent();
|
||||
if (null == content) {
|
||||
return resource;
|
||||
}
|
||||
|
||||
Class<?> domainType = content.getClass();
|
||||
for(DomainTypeResourceProcessor rp : resourceProcessors) {
|
||||
if(isAssignable(domainType, rp.domainType)) {
|
||||
rp.resourceProcessor.process(resource);
|
||||
}
|
||||
}
|
||||
Class<?> domainType = content.getClass();
|
||||
for (DomainTypeResourceProcessor rp : resourceProcessors) {
|
||||
if (isAssignable(domainType, rp.domainType)) {
|
||||
rp.resourceProcessor.process(resource);
|
||||
}
|
||||
}
|
||||
|
||||
return resource;
|
||||
}
|
||||
return resource;
|
||||
}
|
||||
|
||||
private static class DomainTypeResourceProcessor {
|
||||
final Class<?> domainType;
|
||||
final ResourceProcessor<Resource<?>> resourceProcessor;
|
||||
private static class DomainTypeResourceProcessor {
|
||||
final Class<?> domainType;
|
||||
final ResourceProcessor<Resource<?>> resourceProcessor;
|
||||
|
||||
private DomainTypeResourceProcessor(Class<?> domainType, ResourceProcessor<Resource<?>> resourceProcessor) {
|
||||
this.domainType = domainType;
|
||||
this.resourceProcessor = resourceProcessor;
|
||||
}
|
||||
}
|
||||
private DomainTypeResourceProcessor(Class<?> domainType, ResourceProcessor<Resource<?>> resourceProcessor) {
|
||||
this.domainType = domainType;
|
||||
this.resourceProcessor = resourceProcessor;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,14 +4,14 @@ import org.springframework.context.ApplicationEvent;
|
||||
|
||||
/**
|
||||
* Abstract base class for events emitted by the REST exporter.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
public abstract class RepositoryEvent extends ApplicationEvent {
|
||||
|
||||
|
||||
private static final long serialVersionUID = -966689410815418259L;
|
||||
|
||||
protected RepositoryEvent(Object source) {
|
||||
super(source);
|
||||
}
|
||||
super(source);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,53 +36,44 @@ import org.springframework.validation.Validator;
|
||||
/**
|
||||
* {@link org.springframework.context.ApplicationListener} implementation that dispatches {@link RepositoryEvent}s to a
|
||||
* specific {@link Validator}.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||
*/
|
||||
public class ValidatingRepositoryEventListener
|
||||
extends AbstractRepositoryEventListener<Object>
|
||||
implements InitializingBean {
|
||||
public class ValidatingRepositoryEventListener extends AbstractRepositoryEventListener<Object> implements
|
||||
InitializingBean {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(
|
||||
ValidatingRepositoryEventListener.class);
|
||||
@SuppressWarnings({"unchecked"})
|
||||
private static final List<Class<? extends Annotation>> ANNOTATIONS_TO_FIND = Arrays.asList(
|
||||
HandleBeforeSave.class,
|
||||
HandleAfterSave.class,
|
||||
HandleBeforeDelete.class,
|
||||
HandleAfterDelete.class,
|
||||
HandleBeforeLinkSave.class,
|
||||
HandleAfterLinkSave.class,
|
||||
HandleBeforeLinkDelete.class,
|
||||
HandleAfterLinkDelete.class
|
||||
);
|
||||
@Autowired
|
||||
private Repositories repositories;
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ValidatingRepositoryEventListener.class);
|
||||
@SuppressWarnings({ "unchecked" }) private static final List<Class<? extends Annotation>> ANNOTATIONS_TO_FIND = Arrays
|
||||
.asList(HandleBeforeSave.class, HandleAfterSave.class, HandleBeforeDelete.class, HandleAfterDelete.class,
|
||||
HandleBeforeLinkSave.class, HandleAfterLinkSave.class, HandleBeforeLinkDelete.class,
|
||||
HandleAfterLinkDelete.class);
|
||||
@Autowired private Repositories repositories;
|
||||
private MultiValueMap<String, Validator> validators = new LinkedMultiValueMap<String, Validator>();
|
||||
|
||||
@Override public void afterPropertiesSet() throws Exception {
|
||||
if(validators.size() == 0) {
|
||||
for(Map.Entry<String, Validator> entry : beansOfTypeIncludingAncestors(applicationContext,
|
||||
Validator.class).entrySet()) {
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (validators.size() == 0) {
|
||||
for (Map.Entry<String, Validator> entry : beansOfTypeIncludingAncestors(applicationContext, Validator.class)
|
||||
.entrySet()) {
|
||||
String name = null;
|
||||
Validator v = entry.getValue();
|
||||
|
||||
if(entry.getKey().contains("Save")) {
|
||||
if (entry.getKey().contains("Save")) {
|
||||
name = entry.getKey().substring(0, entry.getKey().indexOf("Save") + 4);
|
||||
} else if(entry.getKey().contains("Create")) {
|
||||
} else if (entry.getKey().contains("Create")) {
|
||||
name = entry.getKey().substring(0, entry.getKey().indexOf("Create") + 6);
|
||||
} else if(entry.getKey().contains("Delete")) {
|
||||
} else if (entry.getKey().contains("Delete")) {
|
||||
name = entry.getKey().substring(0, entry.getKey().indexOf("Delete") + 6);
|
||||
} else {
|
||||
|
||||
for(Class<? extends Annotation> annoType : ANNOTATIONS_TO_FIND) {
|
||||
if(findAnnotation(v.getClass(), annoType) != null) {
|
||||
for (Class<? extends Annotation> annoType : ANNOTATIONS_TO_FIND) {
|
||||
if (findAnnotation(v.getClass(), annoType) != null) {
|
||||
name = uncapitalize(annoType.getSimpleName().substring(6));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(null != name) {
|
||||
if (null != name) {
|
||||
this.validators.add(name, v);
|
||||
}
|
||||
}
|
||||
@@ -91,7 +82,7 @@ public class ValidatingRepositoryEventListener
|
||||
|
||||
/**
|
||||
* Get a Map of {@link Validator}s that are assigned to the various {@link RepositoryEvent}s.
|
||||
*
|
||||
*
|
||||
* @return Validators assigned to events.
|
||||
*/
|
||||
public Map<String, Collection<Validator>> getValidators() {
|
||||
@@ -100,14 +91,12 @@ public class ValidatingRepositoryEventListener
|
||||
|
||||
/**
|
||||
* Assign a Map of {@link Validator}s that are assigned to the various {@link RepositoryEvent}s.
|
||||
*
|
||||
* @param validators
|
||||
* A Map of Validators to wire.
|
||||
*
|
||||
*
|
||||
* @param validators A Map of Validators to wire.
|
||||
* @return @this
|
||||
*/
|
||||
public ValidatingRepositoryEventListener setValidators(Map<String, Collection<Validator>> validators) {
|
||||
for(Map.Entry<String, Collection<Validator>> entry : validators.entrySet()) {
|
||||
for (Map.Entry<String, Collection<Validator>> entry : validators.entrySet()) {
|
||||
this.validators.put(entry.getKey(), new ArrayList<Validator>(entry.getValue()));
|
||||
}
|
||||
return this;
|
||||
@@ -115,12 +104,9 @@ public class ValidatingRepositoryEventListener
|
||||
|
||||
/**
|
||||
* Add a {@link Validator} that will be triggered on the given event.
|
||||
*
|
||||
* @param event
|
||||
* The event to listen for.
|
||||
* @param validator
|
||||
* The Validator to execute when that event fires.
|
||||
*
|
||||
*
|
||||
* @param event The event to listen for.
|
||||
* @param validator The Validator to execute when that event fires.
|
||||
* @return @this
|
||||
*/
|
||||
public ValidatingRepositoryEventListener addValidator(String event, Validator validator) {
|
||||
@@ -128,57 +114,63 @@ public class ValidatingRepositoryEventListener
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override protected void onBeforeCreate(Object entity) {
|
||||
@Override
|
||||
protected void onBeforeCreate(Object entity) {
|
||||
validate("beforeCreate", entity);
|
||||
}
|
||||
|
||||
@Override protected void onAfterCreate(Object entity) {
|
||||
@Override
|
||||
protected void onAfterCreate(Object entity) {
|
||||
validate("afterCreate", entity);
|
||||
}
|
||||
|
||||
@Override protected void onBeforeSave(Object entity) {
|
||||
@Override
|
||||
protected void onBeforeSave(Object entity) {
|
||||
validate("beforeSave", entity);
|
||||
}
|
||||
|
||||
@Override protected void onAfterSave(Object entity) {
|
||||
@Override
|
||||
protected void onAfterSave(Object entity) {
|
||||
validate("afterSave", entity);
|
||||
}
|
||||
|
||||
@Override protected void onBeforeLinkSave(Object parent, Object linked) {
|
||||
@Override
|
||||
protected void onBeforeLinkSave(Object parent, Object linked) {
|
||||
validate("beforeLinkSave", parent);
|
||||
}
|
||||
|
||||
@Override protected void onAfterLinkSave(Object parent, Object linked) {
|
||||
@Override
|
||||
protected void onAfterLinkSave(Object parent, Object linked) {
|
||||
validate("afterLinkSave", parent);
|
||||
}
|
||||
|
||||
@Override protected void onBeforeDelete(Object entity) {
|
||||
@Override
|
||||
protected void onBeforeDelete(Object entity) {
|
||||
validate("beforeDelete", entity);
|
||||
}
|
||||
|
||||
@Override protected void onAfterDelete(Object entity) {
|
||||
@Override
|
||||
protected void onAfterDelete(Object entity) {
|
||||
validate("afterDelete", entity);
|
||||
}
|
||||
|
||||
private Errors validate(String event, Object o) {
|
||||
Errors errors = null;
|
||||
if(null != o) {
|
||||
if (null != o) {
|
||||
Class<?> domainType = o.getClass();
|
||||
errors = new ValidationErrors(domainType.getSimpleName(),
|
||||
o,
|
||||
repositories.getPersistentEntity(domainType));
|
||||
errors = new ValidationErrors(domainType.getSimpleName(), o, repositories.getPersistentEntity(domainType));
|
||||
|
||||
Collection<Validator> validators = this.validators.get(event);
|
||||
if(null != validators) {
|
||||
for(Validator v : validators) {
|
||||
if(v.supports(o.getClass())) {
|
||||
if (null != validators) {
|
||||
for (Validator v : validators) {
|
||||
if (v.supports(o.getClass())) {
|
||||
LOG.debug(event + ": " + o + " with " + v);
|
||||
ValidationUtils.invokeValidator(v, o, errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(errors.getErrorCount() > 0) {
|
||||
if (errors.getErrorCount() > 0) {
|
||||
throw new RepositoryConstraintViolationException(errors);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,78 +3,69 @@ package org.springframework.data.rest.repository.invoke;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Represents one of the CRUD methods supported by {@link org.springframework.data.repository.PagingAndSortingRepository}
|
||||
* or {@link org.springframework.data.repository.CrudRepository}.
|
||||
*
|
||||
* Represents one of the CRUD methods supported by
|
||||
* {@link org.springframework.data.repository.PagingAndSortingRepository} or
|
||||
* {@link org.springframework.data.repository.CrudRepository}.
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
public enum CrudMethod {
|
||||
|
||||
COUNT,
|
||||
DELETE_ALL,
|
||||
DELETE_ONE,
|
||||
DELETE_SOME,
|
||||
FIND_ALL,
|
||||
FIND_ONE,
|
||||
FIND_SOME,
|
||||
SAVE_ONE,
|
||||
SAVE_SOME;
|
||||
COUNT, DELETE_ALL, DELETE_ONE, DELETE_SOME, FIND_ALL, FIND_ONE, FIND_SOME, SAVE_ONE, SAVE_SOME;
|
||||
|
||||
/**
|
||||
* Get an enum from a {@link Method}. Narrow down overridden methods by looking for {@link Iterable} in the first
|
||||
* parameter, which tells us it is a '_SOME' type.
|
||||
*
|
||||
* @param m
|
||||
* The CRUD method from the repository interface.
|
||||
*
|
||||
* @return An enum representing which CRUD operation this method represents.
|
||||
*/
|
||||
public static CrudMethod fromMethod(Method m) {
|
||||
String s = m.getName();
|
||||
Class<?>[] paramTypes = m.getParameterTypes();
|
||||
boolean some = (paramTypes.length > 0 && Iterable.class.isAssignableFrom(paramTypes[0]));
|
||||
if("count".equals(s)) {
|
||||
return COUNT;
|
||||
} else if("delete".equals(s)) {
|
||||
return (some ? DELETE_SOME : DELETE_ONE);
|
||||
} else if("deleteAll".equals(s)) {
|
||||
return DELETE_ALL;
|
||||
} else if("findAll".equals(s)) {
|
||||
return (some ? FIND_SOME : FIND_ALL);
|
||||
} else if("findOne".equals(s)) {
|
||||
return FIND_ONE;
|
||||
} else if("save".equals(s)) {
|
||||
return (some ? SAVE_SOME : SAVE_ONE);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get an enum from a {@link Method}. Narrow down overridden methods by looking for {@link Iterable} in the first
|
||||
* parameter, which tells us it is a '_SOME' type.
|
||||
*
|
||||
* @param m The CRUD method from the repository interface.
|
||||
* @return An enum representing which CRUD operation this method represents.
|
||||
*/
|
||||
public static CrudMethod fromMethod(Method m) {
|
||||
String s = m.getName();
|
||||
Class<?>[] paramTypes = m.getParameterTypes();
|
||||
boolean some = (paramTypes.length > 0 && Iterable.class.isAssignableFrom(paramTypes[0]));
|
||||
if ("count".equals(s)) {
|
||||
return COUNT;
|
||||
} else if ("delete".equals(s)) {
|
||||
return (some ? DELETE_SOME : DELETE_ONE);
|
||||
} else if ("deleteAll".equals(s)) {
|
||||
return DELETE_ALL;
|
||||
} else if ("findAll".equals(s)) {
|
||||
return (some ? FIND_SOME : FIND_ALL);
|
||||
} else if ("findOne".equals(s)) {
|
||||
return FIND_ONE;
|
||||
} else if ("save".equals(s)) {
|
||||
return (some ? SAVE_SOME : SAVE_ONE);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn this enum into a method name.
|
||||
*
|
||||
* @return The method name as a string.
|
||||
*/
|
||||
public String toMethodName() {
|
||||
switch(this) {
|
||||
case COUNT:
|
||||
return "count";
|
||||
case DELETE_ALL:
|
||||
return "deleteAll";
|
||||
case DELETE_ONE:
|
||||
case DELETE_SOME:
|
||||
return "delete";
|
||||
case FIND_ALL:
|
||||
case FIND_SOME:
|
||||
return "findAll";
|
||||
case FIND_ONE:
|
||||
return "findOne";
|
||||
case SAVE_ONE:
|
||||
case SAVE_SOME:
|
||||
return "save";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Turn this enum into a method name.
|
||||
*
|
||||
* @return The method name as a string.
|
||||
*/
|
||||
public String toMethodName() {
|
||||
switch (this) {
|
||||
case COUNT:
|
||||
return "count";
|
||||
case DELETE_ALL:
|
||||
return "deleteAll";
|
||||
case DELETE_ONE:
|
||||
case DELETE_SOME:
|
||||
return "delete";
|
||||
case FIND_ALL:
|
||||
case FIND_SOME:
|
||||
return "findAll";
|
||||
case FIND_ONE:
|
||||
return "findOne";
|
||||
case SAVE_ONE:
|
||||
case SAVE_SOME:
|
||||
return "save";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,49 +9,48 @@ import org.springframework.data.rest.repository.annotation.ConvertWith;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A special conversion service that can convert {@link MethodParameter}s and their values to a target type, taking
|
||||
* into account any specific conversion instructions annotated on the parameter with {@link ConvertWith}.
|
||||
*
|
||||
* A special conversion service that can convert {@link MethodParameter}s and their values to a target type, taking into
|
||||
* account any specific conversion instructions annotated on the parameter with {@link ConvertWith}.
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
public class MethodParameterConversionService {
|
||||
|
||||
private final ConversionService delegateConversionService;
|
||||
private final ConversionService delegateConversionService;
|
||||
|
||||
public MethodParameterConversionService(ConversionService delegateConversionService) {
|
||||
Assert.notNull(delegateConversionService, "Delegate ConversionService cannot be null.");
|
||||
this.delegateConversionService = delegateConversionService;
|
||||
}
|
||||
public MethodParameterConversionService(ConversionService delegateConversionService) {
|
||||
Assert.notNull(delegateConversionService, "Delegate ConversionService cannot be null.");
|
||||
this.delegateConversionService = delegateConversionService;
|
||||
}
|
||||
|
||||
public boolean canConvert(Class<?> sourceType, MethodParameter param) {
|
||||
return canConvert(TypeDescriptor.valueOf(sourceType), param);
|
||||
}
|
||||
public boolean canConvert(Class<?> sourceType, MethodParameter param) {
|
||||
return canConvert(TypeDescriptor.valueOf(sourceType), param);
|
||||
}
|
||||
|
||||
public boolean canConvert(TypeDescriptor sourceType, MethodParameter param) {
|
||||
return (delegateConversionService.canConvert(sourceType, new TypeDescriptor(param))
|
||||
|| param.hasParameterAnnotation(ConvertWith.class));
|
||||
}
|
||||
public boolean canConvert(TypeDescriptor sourceType, MethodParameter param) {
|
||||
return (delegateConversionService.canConvert(sourceType, new TypeDescriptor(param)) || param
|
||||
.hasParameterAnnotation(ConvertWith.class));
|
||||
}
|
||||
|
||||
public <T> T convert(Object source, MethodParameter param) {
|
||||
return convert(source, TypeDescriptor.forObject(source), param);
|
||||
}
|
||||
public <T> T convert(Object source, MethodParameter param) {
|
||||
return convert(source, TypeDescriptor.forObject(source), param);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
public <T> T convert(Object source, TypeDescriptor sourceType, MethodParameter param) {
|
||||
TypeDescriptor targetType = new TypeDescriptor(param);
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
public <T> T convert(Object source, TypeDescriptor sourceType, MethodParameter param) {
|
||||
TypeDescriptor targetType = new TypeDescriptor(param);
|
||||
|
||||
try {
|
||||
if(param.hasParameterAnnotation(ConvertWith.class)) {
|
||||
Converter<Object, T> converter = (Converter<Object, T>)param.getParameterAnnotation(ConvertWith.class)
|
||||
.value()
|
||||
.newInstance();
|
||||
return converter.convert(source);
|
||||
} else {
|
||||
return (T)delegateConversionService.convert(source, sourceType, targetType);
|
||||
}
|
||||
} catch(Exception e) {
|
||||
throw new ConversionFailedException(sourceType, targetType, source, e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
if (param.hasParameterAnnotation(ConvertWith.class)) {
|
||||
Converter<Object, T> converter = (Converter<Object, T>) param.getParameterAnnotation(ConvertWith.class).value()
|
||||
.newInstance();
|
||||
return converter.convert(source);
|
||||
} else {
|
||||
return (T) delegateConversionService.convert(source, sourceType, targetType);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new ConversionFailedException(sourceType, targetType, source, e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,101 +14,101 @@ import org.springframework.data.rest.repository.support.Methods;
|
||||
|
||||
/**
|
||||
* An abstraction to encapsulate metadata about a repository method.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
public class RepositoryMethod {
|
||||
|
||||
private Method method;
|
||||
private List<MethodParameter> methodParameters = new ArrayList<MethodParameter>();
|
||||
private List<String> paramNames = new ArrayList<String>();
|
||||
private boolean pageable = false;
|
||||
private boolean sortable = false;
|
||||
private Method method;
|
||||
private List<MethodParameter> methodParameters = new ArrayList<MethodParameter>();
|
||||
private List<String> paramNames = new ArrayList<String>();
|
||||
private boolean pageable = false;
|
||||
private boolean sortable = false;
|
||||
|
||||
public RepositoryMethod(Method method) {
|
||||
this.method = method;
|
||||
public RepositoryMethod(Method method) {
|
||||
this.method = method;
|
||||
|
||||
Class<?>[] paramTypes = method.getParameterTypes();
|
||||
String[] paramNames = Methods.NAME_DISCOVERER.getParameterNames(method);
|
||||
if(null == paramNames) {
|
||||
paramNames = new String[paramTypes.length];
|
||||
}
|
||||
Class<?>[] paramTypes = method.getParameterTypes();
|
||||
String[] paramNames = Methods.NAME_DISCOVERER.getParameterNames(method);
|
||||
if (null == paramNames) {
|
||||
paramNames = new String[paramTypes.length];
|
||||
}
|
||||
|
||||
Annotation[][] paramAnnos = method.getParameterAnnotations();
|
||||
for(int i = 0; i < paramAnnos.length; i++) {
|
||||
if(paramAnnos[i].length > 0) {
|
||||
for(Annotation anno : paramAnnos[i]) {
|
||||
if(Param.class.isAssignableFrom(anno.getClass())) {
|
||||
Param p = (Param)anno;
|
||||
paramNames[i] = p.value();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(null == paramNames[i]) {
|
||||
paramNames[i] = "arg" + i;
|
||||
}
|
||||
}
|
||||
Annotation[][] paramAnnos = method.getParameterAnnotations();
|
||||
for (int i = 0; i < paramAnnos.length; i++) {
|
||||
if (paramAnnos[i].length > 0) {
|
||||
for (Annotation anno : paramAnnos[i]) {
|
||||
if (Param.class.isAssignableFrom(anno.getClass())) {
|
||||
Param p = (Param) anno;
|
||||
paramNames[i] = p.value();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (null == paramNames[i]) {
|
||||
paramNames[i] = "arg" + i;
|
||||
}
|
||||
}
|
||||
|
||||
int idx = 0;
|
||||
for(Class<?> type : paramTypes) {
|
||||
if(Pageable.class.isAssignableFrom(type)) {
|
||||
pageable = true;
|
||||
}
|
||||
if(Sort.class.isAssignableFrom(type)) {
|
||||
sortable = true;
|
||||
}
|
||||
methodParameters.add(new MethodParameter(method, idx));
|
||||
idx++;
|
||||
}
|
||||
int idx = 0;
|
||||
for (Class<?> type : paramTypes) {
|
||||
if (Pageable.class.isAssignableFrom(type)) {
|
||||
pageable = true;
|
||||
}
|
||||
if (Sort.class.isAssignableFrom(type)) {
|
||||
sortable = true;
|
||||
}
|
||||
methodParameters.add(new MethodParameter(method, idx));
|
||||
idx++;
|
||||
}
|
||||
|
||||
Collections.addAll(this.paramNames, paramNames);
|
||||
}
|
||||
Collections.addAll(this.paramNames, paramNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the method parameter types.
|
||||
*
|
||||
* @return Array of parameter types.
|
||||
*/
|
||||
public List<MethodParameter> getParameters() {
|
||||
return methodParameters;
|
||||
}
|
||||
/**
|
||||
* Get the method parameter types.
|
||||
*
|
||||
* @return Array of parameter types.
|
||||
*/
|
||||
public List<MethodParameter> getParameters() {
|
||||
return methodParameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the method parameter names.
|
||||
*
|
||||
* @return Array of parameter names.
|
||||
*/
|
||||
public List<String> getParameterNames() {
|
||||
return paramNames;
|
||||
}
|
||||
/**
|
||||
* Get the method parameter names.
|
||||
*
|
||||
* @return Array of parameter names.
|
||||
*/
|
||||
public List<String> getParameterNames() {
|
||||
return paramNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the reflected {@link Method} to invoke.
|
||||
*
|
||||
* @return The {@link Method} to invoke.
|
||||
*/
|
||||
public Method getMethod() {
|
||||
return method;
|
||||
}
|
||||
/**
|
||||
* Get the reflected {@link Method} to invoke.
|
||||
*
|
||||
* @return The {@link Method} to invoke.
|
||||
*/
|
||||
public Method getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag denoting whether this repository method returns a {@link org.springframework.data.domain.Page} result or not.
|
||||
*
|
||||
* @return {@literal true} if this method returns a {@link org.springframework.data.domain.Page}, {@literal false}
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean isPageable() {
|
||||
return pageable;
|
||||
}
|
||||
/**
|
||||
* Flag denoting whether this repository method returns a {@link org.springframework.data.domain.Page} result or not.
|
||||
*
|
||||
* @return {@literal true} if this method returns a {@link org.springframework.data.domain.Page}, {@literal false}
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean isPageable() {
|
||||
return pageable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag denoting whether this repository method accepts sorting information.
|
||||
*
|
||||
* @return {@literal true} if this method accepts a {@link Sort}, {@literal false} otherwise.
|
||||
*/
|
||||
public boolean isSortable() {
|
||||
return sortable;
|
||||
}
|
||||
/**
|
||||
* Flag denoting whether this repository method accepts sorting information.
|
||||
*
|
||||
* @return {@literal true} if this method accepts a {@link Sort}, {@literal false} otherwise.
|
||||
*/
|
||||
public boolean isSortable() {
|
||||
return sortable;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ public class RepositoryMethodInvoker implements PagingAndSortingRepository<Objec
|
||||
private final Object repository;
|
||||
private final Map<String, RepositoryMethod> queryMethods = new HashMap<String, RepositoryMethod>();
|
||||
private final ConversionService conversionService;
|
||||
|
||||
|
||||
private RepositoryMethod saveOne;
|
||||
private RepositoryMethod saveSome;
|
||||
private RepositoryMethod findOne;
|
||||
@@ -42,18 +42,17 @@ public class RepositoryMethodInvoker implements PagingAndSortingRepository<Objec
|
||||
private RepositoryMethod deleteSome;
|
||||
private RepositoryMethod deleteAll;
|
||||
|
||||
public RepositoryMethodInvoker(Object repository,
|
||||
RepositoryInformation repoInfo,
|
||||
ConversionService conversionService) {
|
||||
|
||||
public RepositoryMethodInvoker(Object repository, RepositoryInformation repoInfo, ConversionService conversionService) {
|
||||
|
||||
this.repository = repository;
|
||||
this.conversionService = conversionService;
|
||||
Class<?> repoType = repoInfo.getRepositoryInterface();
|
||||
|
||||
doWithMethods(repoType, new MethodCallback() {
|
||||
@Override public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
|
||||
@Override
|
||||
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
|
||||
boolean exported = ResourceMappingUtils.findExported(method);
|
||||
if(!exported) {
|
||||
if (!exported) {
|
||||
return;
|
||||
}
|
||||
String name = method.getName();
|
||||
@@ -65,31 +64,31 @@ public class RepositoryMethodInvoker implements PagingAndSortingRepository<Objec
|
||||
boolean pageable = (null != paramType && Pageable.class.isAssignableFrom(paramType));
|
||||
RepositoryMethod repoMethod = new RepositoryMethod(method);
|
||||
|
||||
if("save".equals(name) && someMethod) {
|
||||
if ("save".equals(name) && someMethod) {
|
||||
saveSome = repoMethod;
|
||||
} else if("save".equals(name)) {
|
||||
} else if ("save".equals(name)) {
|
||||
saveOne = repoMethod;
|
||||
} else if("findOne".equals(name)) {
|
||||
} else if ("findOne".equals(name)) {
|
||||
findOne = repoMethod;
|
||||
} else if("exists".equals(name)) {
|
||||
} else if ("exists".equals(name)) {
|
||||
exists = repoMethod;
|
||||
} else if("findAll".equals(name) && sortable) {
|
||||
} else if ("findAll".equals(name) && sortable) {
|
||||
findAllSorted = repoMethod;
|
||||
} else if("findAll".equals(name) && someMethod) {
|
||||
} else if ("findAll".equals(name) && someMethod) {
|
||||
findSome = repoMethod;
|
||||
} else if("findAll".equals(name) && pageable) {
|
||||
} else if ("findAll".equals(name) && pageable) {
|
||||
findAllPaged = repoMethod;
|
||||
} else if("findAll".equals(name)) {
|
||||
} else if ("findAll".equals(name)) {
|
||||
findAll = repoMethod;
|
||||
} else if("count".equals(name)) {
|
||||
} else if ("count".equals(name)) {
|
||||
count = repoMethod;
|
||||
} else if("delete".equals(name) && byIdMethod) {
|
||||
} else if ("delete".equals(name) && byIdMethod) {
|
||||
deleteOneById = repoMethod;
|
||||
} else if("delete".equals(name) && someMethod) {
|
||||
} else if ("delete".equals(name) && someMethod) {
|
||||
deleteSome = repoMethod;
|
||||
} else if("delete".equals(name)) {
|
||||
} else if ("delete".equals(name)) {
|
||||
deleteOne = repoMethod;
|
||||
} else if("deleteAll".equals(name)) {
|
||||
} else if ("deleteAll".equals(name)) {
|
||||
deleteAll = repoMethod;
|
||||
} else {
|
||||
queryMethods.put(name, repoMethod);
|
||||
@@ -98,25 +97,28 @@ public class RepositoryMethodInvoker implements PagingAndSortingRepository<Objec
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
@Override public <S extends Object> S save(S entity) {
|
||||
return (S)invokeMethod(saveOne.getMethod(), repository, entity);
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
@Override
|
||||
public <S extends Object> S save(S entity) {
|
||||
return (S) invokeMethod(saveOne.getMethod(), repository, entity);
|
||||
}
|
||||
|
||||
public boolean hasSaveOne() {
|
||||
return null != saveOne;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
@Override public <S extends Object> Iterable<S> save(Iterable<S> entities) {
|
||||
return (Iterable<S>)invokeMethod(saveSome.getMethod(), repository, entities);
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
@Override
|
||||
public <S extends Object> Iterable<S> save(Iterable<S> entities) {
|
||||
return (Iterable<S>) invokeMethod(saveSome.getMethod(), repository, entities);
|
||||
}
|
||||
|
||||
public boolean hasSaveSome() {
|
||||
return null != saveSome;
|
||||
}
|
||||
|
||||
@Override public Object findOne(Serializable serializable) {
|
||||
@Override
|
||||
public Object findOne(Serializable serializable) {
|
||||
return invokeMethod(findOne.getMethod(), repository, serializable);
|
||||
}
|
||||
|
||||
@@ -124,51 +126,57 @@ public class RepositoryMethodInvoker implements PagingAndSortingRepository<Objec
|
||||
return null != findOne;
|
||||
}
|
||||
|
||||
@Override public boolean exists(Serializable serializable) {
|
||||
return (Boolean)invokeMethod(exists.getMethod(), repository, serializable);
|
||||
@Override
|
||||
public boolean exists(Serializable serializable) {
|
||||
return (Boolean) invokeMethod(exists.getMethod(), repository, serializable);
|
||||
}
|
||||
|
||||
public boolean hasExists() {
|
||||
return null != exists;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
@Override public Iterable<Object> findAll() {
|
||||
return (Iterable<Object>)invokeMethod(findAll.getMethod(), repository);
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
@Override
|
||||
public Iterable<Object> findAll() {
|
||||
return (Iterable<Object>) invokeMethod(findAll.getMethod(), repository);
|
||||
}
|
||||
|
||||
public boolean hasFindAll() {
|
||||
return null != findAll;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
@Override public Iterable<Object> findAll(Iterable<Serializable> serializables) {
|
||||
return (Iterable<Object>)invokeMethod(findSome.getMethod(), repository, serializables);
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
@Override
|
||||
public Iterable<Object> findAll(Iterable<Serializable> serializables) {
|
||||
return (Iterable<Object>) invokeMethod(findSome.getMethod(), repository, serializables);
|
||||
}
|
||||
|
||||
public boolean hasFindSome() {
|
||||
return null != findSome;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
@Override public Iterable<Object> findAll(Sort sort) {
|
||||
return (Iterable<Object>)invokeMethod(findAllSorted.getMethod(), repository, sort);
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
@Override
|
||||
public Iterable<Object> findAll(Sort sort) {
|
||||
return (Iterable<Object>) invokeMethod(findAllSorted.getMethod(), repository, sort);
|
||||
}
|
||||
|
||||
public boolean hasFindAllSorted() {
|
||||
return null != findAllSorted;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
@Override public Page<Object> findAll(Pageable pageable) {
|
||||
return (Page<Object>)invokeMethod(findAllPaged.getMethod(), repository, pageable);
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
@Override
|
||||
public Page<Object> findAll(Pageable pageable) {
|
||||
return (Page<Object>) invokeMethod(findAllPaged.getMethod(), repository, pageable);
|
||||
}
|
||||
|
||||
public boolean hasFindAllPageable() {
|
||||
return null != findAllPaged;
|
||||
}
|
||||
|
||||
@Override public void delete(Serializable serializable) {
|
||||
@Override
|
||||
public void delete(Serializable serializable) {
|
||||
invokeMethod(deleteOneById.getMethod(), repository, serializable);
|
||||
}
|
||||
|
||||
@@ -176,15 +184,17 @@ public class RepositoryMethodInvoker implements PagingAndSortingRepository<Objec
|
||||
return null != deleteOneById;
|
||||
}
|
||||
|
||||
@Override public long count() {
|
||||
return (Long)invokeMethod(count.getMethod(), repository);
|
||||
@Override
|
||||
public long count() {
|
||||
return (Long) invokeMethod(count.getMethod(), repository);
|
||||
}
|
||||
|
||||
public boolean hasCount() {
|
||||
return null != count;
|
||||
}
|
||||
|
||||
@Override public void delete(Object entity) {
|
||||
@Override
|
||||
public void delete(Object entity) {
|
||||
invokeMethod(deleteOne.getMethod(), repository, entity);
|
||||
}
|
||||
|
||||
@@ -192,7 +202,8 @@ public class RepositoryMethodInvoker implements PagingAndSortingRepository<Objec
|
||||
return null != deleteOne;
|
||||
}
|
||||
|
||||
@Override public void delete(Iterable<?> entities) {
|
||||
@Override
|
||||
public void delete(Iterable<?> entities) {
|
||||
invokeMethod(deleteSome.getMethod(), repository, entities);
|
||||
}
|
||||
|
||||
@@ -200,7 +211,8 @@ public class RepositoryMethodInvoker implements PagingAndSortingRepository<Objec
|
||||
return null != deleteSome;
|
||||
}
|
||||
|
||||
@Override public void deleteAll() {
|
||||
@Override
|
||||
public void deleteAll() {
|
||||
invokeMethod(deleteAll.getMethod(), repository);
|
||||
}
|
||||
|
||||
@@ -218,7 +230,7 @@ public class RepositoryMethodInvoker implements PagingAndSortingRepository<Objec
|
||||
|
||||
public Object invokeQueryMethod(String name, Object... params) {
|
||||
RepositoryMethod repoMethod = queryMethods.get(name);
|
||||
if(null == repoMethod) {
|
||||
if (null == repoMethod) {
|
||||
throw new NoSuchMethodError(name);
|
||||
}
|
||||
return invokeMethod(repoMethod.getMethod(), repository, params);
|
||||
@@ -227,48 +239,44 @@ public class RepositoryMethodInvoker implements PagingAndSortingRepository<Objec
|
||||
public Object invokeQueryMethod(RepositoryMethod method, Object... params) {
|
||||
return invokeMethod(method.getMethod(), repository, params);
|
||||
}
|
||||
|
||||
|
||||
public Object invokeQueryMethod(RepositoryMethod method, Pageable pageable, Map<String, String[]> rawParameters) {
|
||||
return invokeQueryMethod(method, foo(method, pageable, rawParameters));
|
||||
}
|
||||
|
||||
|
||||
private Object[] foo(RepositoryMethod repoMethod, Pageable pageable, Map<String, String[]> rawParameters) {
|
||||
|
||||
|
||||
List<MethodParameter> methodParams = repoMethod.getParameters();
|
||||
|
||||
|
||||
if (methodParams.isEmpty()) {
|
||||
return new Object[0];
|
||||
}
|
||||
|
||||
|
||||
Object[] paramValues = new Object[methodParams.size()];
|
||||
|
||||
|
||||
for(int i = 0; i < paramValues.length; i++) {
|
||||
|
||||
for (int i = 0; i < paramValues.length; i++) {
|
||||
MethodParameter param = methodParams.get(i);
|
||||
Class<?> targetType = param.getParameterType();
|
||||
if(Pageable.class.isAssignableFrom(targetType)) {
|
||||
if (Pageable.class.isAssignableFrom(targetType)) {
|
||||
paramValues[i] = pageable;
|
||||
} else if(Sort.class.isAssignableFrom(targetType)) {
|
||||
} else if (Sort.class.isAssignableFrom(targetType)) {
|
||||
paramValues[i] = pageable.getSort();
|
||||
} else {
|
||||
String paramName = repoMethod.getParameterNames().get(i);
|
||||
String[] queryParamVals = rawParameters.get(paramName);
|
||||
if(null == queryParamVals) {
|
||||
if(paramName.startsWith("arg")) {
|
||||
if (null == queryParamVals) {
|
||||
if (paramName.startsWith("arg")) {
|
||||
throw new IllegalArgumentException("No @Param annotation found on query method "
|
||||
+ repoMethod.getMethod().getName()
|
||||
+ " for parameter " + param.getParameterName());
|
||||
+ repoMethod.getMethod().getName() + " for parameter " + param.getParameterName());
|
||||
} else {
|
||||
throw new IllegalArgumentException("No query parameter specified for "
|
||||
+ repoMethod.getMethod().getName() + " param '"
|
||||
+ paramName + "'");
|
||||
throw new IllegalArgumentException("No query parameter specified for " + repoMethod.getMethod().getName()
|
||||
+ " param '" + paramName + "'");
|
||||
}
|
||||
}
|
||||
paramValues[i] = conversionService.convert(queryParamVals, targetType);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return paramValues;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,96 +11,94 @@ import org.springframework.hateoas.Link;
|
||||
/**
|
||||
* JSON-serializable response for returns that have a mix of results and links. Also used in responses that have just
|
||||
* links (in that case, 'results' will be an empty array).
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
public class RepositoryMethodResponse {
|
||||
|
||||
@JsonProperty("results")
|
||||
private List<Object> results = new ArrayList<Object>();
|
||||
@JsonProperty("links")
|
||||
private List<Link> links = new ArrayList<Link>();
|
||||
private long totalCount = 0;
|
||||
private int totalPages = 1;
|
||||
private int currentPage = 1;
|
||||
@JsonProperty("results") private List<Object> results = new ArrayList<Object>();
|
||||
@JsonProperty("links") private List<Link> links = new ArrayList<Link>();
|
||||
private long totalCount = 0;
|
||||
private int totalPages = 1;
|
||||
private int currentPage = 1;
|
||||
|
||||
public RepositoryMethodResponse addLink(Link l) {
|
||||
links.add(l);
|
||||
return this;
|
||||
}
|
||||
public RepositoryMethodResponse addLink(Link l) {
|
||||
links.add(l);
|
||||
return this;
|
||||
}
|
||||
|
||||
public RepositoryMethodResponse addResult(Object obj) {
|
||||
results.add(obj);
|
||||
return this;
|
||||
}
|
||||
public RepositoryMethodResponse addResult(Object obj) {
|
||||
results.add(obj);
|
||||
return this;
|
||||
}
|
||||
|
||||
public RepositoryMethodResponse addAllResults(Iterator<?> results) {
|
||||
if(null == results) {
|
||||
return this;
|
||||
}
|
||||
public RepositoryMethodResponse addAllResults(Iterator<?> results) {
|
||||
if (null == results) {
|
||||
return this;
|
||||
}
|
||||
|
||||
while(results.hasNext()) {
|
||||
addResult(results.next());
|
||||
}
|
||||
while (results.hasNext()) {
|
||||
addResult(results.next());
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<Object> getResults() {
|
||||
return results;
|
||||
}
|
||||
public List<Object> getResults() {
|
||||
return results;
|
||||
}
|
||||
|
||||
public boolean hasResults() {
|
||||
return (results.size() > 0);
|
||||
}
|
||||
public boolean hasResults() {
|
||||
return (results.size() > 0);
|
||||
}
|
||||
|
||||
public RepositoryMethodResponse setResults(List<Object> results) {
|
||||
if(null == results) {
|
||||
this.results = Collections.emptyList();
|
||||
} else {
|
||||
this.results = results;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public RepositoryMethodResponse setResults(List<Object> results) {
|
||||
if (null == results) {
|
||||
this.results = Collections.emptyList();
|
||||
} else {
|
||||
this.results = results;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<Link> getLinks() {
|
||||
return links;
|
||||
}
|
||||
public List<Link> getLinks() {
|
||||
return links;
|
||||
}
|
||||
|
||||
public RepositoryMethodResponse setLinks(List<Link> links) {
|
||||
if(null == links) {
|
||||
this.links = Collections.emptyList();
|
||||
} else {
|
||||
this.links = links;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public RepositoryMethodResponse setLinks(List<Link> links) {
|
||||
if (null == links) {
|
||||
this.links = Collections.emptyList();
|
||||
} else {
|
||||
this.links = links;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public long getTotalCount() {
|
||||
return totalCount;
|
||||
}
|
||||
public long getTotalCount() {
|
||||
return totalCount;
|
||||
}
|
||||
|
||||
public RepositoryMethodResponse setTotalCount(long totalCount) {
|
||||
this.totalCount = totalCount;
|
||||
return this;
|
||||
}
|
||||
public RepositoryMethodResponse setTotalCount(long totalCount) {
|
||||
this.totalCount = totalCount;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getTotalPages() {
|
||||
return totalPages;
|
||||
}
|
||||
public int getTotalPages() {
|
||||
return totalPages;
|
||||
}
|
||||
|
||||
public RepositoryMethodResponse setTotalPages(int totalPages) {
|
||||
this.totalPages = totalPages;
|
||||
return this;
|
||||
}
|
||||
public RepositoryMethodResponse setTotalPages(int totalPages) {
|
||||
this.totalPages = totalPages;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getCurrentPage() {
|
||||
return currentPage;
|
||||
}
|
||||
public int getCurrentPage() {
|
||||
return currentPage;
|
||||
}
|
||||
|
||||
public RepositoryMethodResponse setCurrentPage(int currentPage) {
|
||||
this.currentPage = currentPage;
|
||||
return this;
|
||||
}
|
||||
public RepositoryMethodResponse setCurrentPage(int currentPage) {
|
||||
this.currentPage = currentPage;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,72 +10,70 @@ import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Represents a query method on a repository interface.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||
*/
|
||||
public class RepositoryQueryMethod {
|
||||
|
||||
private Method method;
|
||||
private Class<?>[] paramTypes;
|
||||
private String[] paramNames;
|
||||
private Method method;
|
||||
private Class<?>[] paramTypes;
|
||||
private String[] paramNames;
|
||||
|
||||
public RepositoryQueryMethod(Method method) {
|
||||
this.method = method;
|
||||
paramTypes = method.getParameterTypes();
|
||||
paramNames = new String[paramTypes.length];
|
||||
if(null == paramNames) {
|
||||
paramNames = new String[paramTypes.length];
|
||||
}
|
||||
Annotation[][] paramAnnos = method.getParameterAnnotations();
|
||||
for(int i = 0; i < paramAnnos.length; i++) {
|
||||
if(paramAnnos[i].length == 0) {
|
||||
continue;
|
||||
}
|
||||
public RepositoryQueryMethod(Method method) {
|
||||
this.method = method;
|
||||
paramTypes = method.getParameterTypes();
|
||||
paramNames = new String[paramTypes.length];
|
||||
if (null == paramNames) {
|
||||
paramNames = new String[paramTypes.length];
|
||||
}
|
||||
Annotation[][] paramAnnos = method.getParameterAnnotations();
|
||||
for (int i = 0; i < paramAnnos.length; i++) {
|
||||
if (paramAnnos[i].length == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for(Annotation anno : paramAnnos[i]) {
|
||||
if(Param.class.isAssignableFrom(anno.getClass())) {
|
||||
Param p = (Param)anno;
|
||||
paramNames[i] = p.value();
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (Annotation anno : paramAnnos[i]) {
|
||||
if (Param.class.isAssignableFrom(anno.getClass())) {
|
||||
Param p = (Param) anno;
|
||||
paramNames[i] = p.value();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(Pageable.class.isAssignableFrom(paramTypes[i])
|
||||
|| Sort.class.isAssignableFrom(paramTypes[i])) {
|
||||
continue;
|
||||
}
|
||||
if (Pageable.class.isAssignableFrom(paramTypes[i]) || Sort.class.isAssignableFrom(paramTypes[i])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Assert.notNull(paramNames[i],
|
||||
"No @Param('name') was provided for parameter " + (i + 1) + " of type " + paramTypes[i]
|
||||
+ " on " + (method.getDeclaringClass().getName() + "." + method.getName()));
|
||||
}
|
||||
}
|
||||
Assert.notNull(paramNames[i], "No @Param('name') was provided for parameter " + (i + 1) + " of type "
|
||||
+ paramTypes[i] + " on " + (method.getDeclaringClass().getName() + "." + method.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The method's parameter types.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Class<?>[] paramTypes() {
|
||||
return paramTypes;
|
||||
}
|
||||
/**
|
||||
* The method's parameter types.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Class<?>[] paramTypes() {
|
||||
return paramTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* The parameter names as pulled from the {@link Param} annotations.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String[] paramNames() {
|
||||
return paramNames;
|
||||
}
|
||||
/**
|
||||
* The parameter names as pulled from the {@link Param} annotations.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String[] paramNames() {
|
||||
return paramNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link Method} to invoke.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Method method() {
|
||||
return method;
|
||||
}
|
||||
/**
|
||||
* The {@link Method} to invoke.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Method method() {
|
||||
return method;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ package org.springframework.data.rest.repository.mapping;
|
||||
|
||||
/**
|
||||
* A custom resource mapping for collection resources.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface CollectionResourceMapping extends ResourceMapping {
|
||||
|
||||
@@ -17,92 +17,91 @@ package org.springframework.data.rest.repository.mapping;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
class CollectionResourceMappingBuilder implements InternalMappingBuilder {
|
||||
|
||||
|
||||
private final CollectionResourceMapping mapping;
|
||||
|
||||
|
||||
public CollectionResourceMappingBuilder(CollectionResourceMapping mapping) {
|
||||
this.mapping = mapping;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.mapping.InternalMappingBuilder#withCollectionRel(java.lang.String)
|
||||
*/
|
||||
public CollectionResourceMappingBuilder withCollectionRel(String rel) {
|
||||
|
||||
SimpleCollectionResourceMapping newMapping = new SimpleCollectionResourceMapping(rel != null ? rel : mapping.getRel(),
|
||||
mapping.getSingleResourceRel(), mapping.getPath(), mapping.isExported());
|
||||
|
||||
SimpleCollectionResourceMapping newMapping = new SimpleCollectionResourceMapping(rel != null ? rel
|
||||
: mapping.getRel(), mapping.getSingleResourceRel(), mapping.getPath(), mapping.isExported());
|
||||
|
||||
return new CollectionResourceMappingBuilder(newMapping);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.mapping.InternalMappingBuilder#withSingleRel(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public CollectionResourceMappingBuilder withSingleRel(String rel) {
|
||||
|
||||
|
||||
SimpleCollectionResourceMapping newMapping = new SimpleCollectionResourceMapping(mapping.getRel(),
|
||||
rel != null ? rel : mapping.getSingleResourceRel(), mapping.getPath(), mapping.isExported());
|
||||
|
||||
|
||||
return new CollectionResourceMappingBuilder(newMapping);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.mapping.InternalMappingBuilder#withPath(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public CollectionResourceMappingBuilder withPath(String path) {
|
||||
|
||||
|
||||
SimpleCollectionResourceMapping newMapping = new SimpleCollectionResourceMapping(mapping.getRel(),
|
||||
mapping.getSingleResourceRel(), path != null ? path : mapping.getPath(), mapping.isExported());
|
||||
|
||||
|
||||
return new CollectionResourceMappingBuilder(newMapping);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.mapping.InternalMappingBuilder#withExposed(java.lang.Boolean)
|
||||
*/
|
||||
@Override
|
||||
public CollectionResourceMappingBuilder withExposed(Boolean exported) {
|
||||
|
||||
|
||||
SimpleCollectionResourceMapping newMapping = new SimpleCollectionResourceMapping(mapping.getRel(),
|
||||
mapping.getSingleResourceRel(), mapping.getPath(), exported != null ? exported : mapping.isExported());
|
||||
|
||||
|
||||
return new CollectionResourceMappingBuilder(newMapping);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.mapping.InternalMappingBuilder#merge(org.springframework.data.rest.repository.mapping.CollectionResourceMapping)
|
||||
*/
|
||||
@Override
|
||||
public InternalMappingBuilder merge(CollectionResourceMapping mapping) {
|
||||
|
||||
|
||||
if (mapping == null) {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
return withCollectionRel(mapping.getRel()). //
|
||||
withSingleRel(mapping.getSingleResourceRel()). //
|
||||
withPath(mapping.getPath()). //
|
||||
withExposed(mapping.isExported());
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.mapping.InternalMappingBuilder#getMapping()
|
||||
*/
|
||||
@Override
|
||||
public CollectionResourceMapping getMapping() {
|
||||
|
||||
|
||||
Assert.hasText(mapping.getRel(), "Rel must not be null or empty!");
|
||||
|
||||
|
||||
return mapping;
|
||||
}
|
||||
|
||||
@@ -112,4 +111,4 @@ class CollectionResourceMappingBuilder implements InternalMappingBuilder {
|
||||
public Boolean isExported() {
|
||||
return mapping.isExported();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,6 @@ package org.springframework.data.rest.repository.mapping;
|
||||
interface InternalMappingBuilder extends MappingBuilder {
|
||||
|
||||
InternalMappingBuilder merge(CollectionResourceMapping mapping);
|
||||
|
||||
|
||||
CollectionResourceMapping getMapping();
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ package org.springframework.data.rest.repository.mapping;
|
||||
|
||||
/**
|
||||
* SPI to allow users to register
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface MappingBuilder {
|
||||
|
||||
@@ -49,7 +49,7 @@ public class RepositoryAwareResourceInformation implements ResourceMetadata {
|
||||
this.provider = provider;
|
||||
this.repositoryInterface = repositoryInterface;
|
||||
}
|
||||
|
||||
|
||||
public boolean isPrimary() {
|
||||
return AnnotationUtils.findAnnotation(repositoryInterface.getRepositoryInterface(), Primary.class) != null;
|
||||
}
|
||||
@@ -71,7 +71,7 @@ public class RepositoryAwareResourceInformation implements ResourceMetadata {
|
||||
public ResourceMapping getMappingFor(PersistentProperty<?> property) {
|
||||
return provider.getMappingFor(property);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.mapping.ResourceMetadataProvider#hasMappingFor(org.springframework.data.mapping.PersistentProperty)
|
||||
|
||||
@@ -21,19 +21,19 @@ package org.springframework.data.rest.repository.mapping;
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface ResourceMapping {
|
||||
|
||||
|
||||
public static ResourceMapping NO_MAPPING = new ResourceMapping() {
|
||||
|
||||
|
||||
@Override
|
||||
public Boolean isExported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getRel() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return null;
|
||||
|
||||
@@ -47,7 +47,7 @@ public class ResourceMappingFactory {
|
||||
if (type != typeToInspect) {
|
||||
mapping = mapping.merge(discoverConfig(type));
|
||||
}
|
||||
|
||||
|
||||
for (CollectionResourceMapping externalMapping : manualMapping) {
|
||||
mapping = mapping.merge(externalMapping);
|
||||
}
|
||||
@@ -56,7 +56,7 @@ public class ResourceMappingFactory {
|
||||
}
|
||||
|
||||
private static Class<?> getTypeToInspect(Class<?> type) {
|
||||
|
||||
|
||||
if (!RepositoriesUtils.isRepositoryInterface(type)) {
|
||||
return type;
|
||||
}
|
||||
@@ -69,8 +69,9 @@ public class ResourceMappingFactory {
|
||||
String path = StringUtils.uncapitalize(domainType.getSimpleName());
|
||||
String defaultCollectionRel = relProvider.getCollectionResourceRelFor(domainType);
|
||||
String defaultSingleRel = relProvider.getSingleResourceRelFor(domainType);
|
||||
|
||||
CollectionResourceMapping mapping = new SimpleCollectionResourceMapping(defaultCollectionRel, defaultSingleRel, path, true);
|
||||
|
||||
CollectionResourceMapping mapping = new SimpleCollectionResourceMapping(defaultCollectionRel, defaultSingleRel,
|
||||
path, true);
|
||||
|
||||
return new CollectionResourceMappingBuilder(mapping);
|
||||
}
|
||||
@@ -82,19 +83,19 @@ public class ResourceMappingFactory {
|
||||
if (resource == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
return new AnnotationResourceMapping(resource);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@link CollectionResourceMapping} based on an {@link RestResource} annotation.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
private static class AnnotationResourceMapping implements CollectionResourceMapping {
|
||||
|
||||
|
||||
private final RestResource annotation;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new {@link AnnotationResourceMapping} for the given {@link RestResource}.
|
||||
*
|
||||
@@ -129,7 +130,7 @@ public class ResourceMappingFactory {
|
||||
*/
|
||||
@Override
|
||||
public String getSingleResourceRel() {
|
||||
|
||||
|
||||
String rel = getRel();
|
||||
return rel == null ? null : String.format("%s.%s", rel, rel);
|
||||
}
|
||||
|
||||
@@ -25,8 +25,8 @@ import org.springframework.data.repository.core.RepositoryInformation;
|
||||
import org.springframework.data.repository.support.Repositories;
|
||||
import org.springframework.data.rest.config.RepositoryRestConfiguration;
|
||||
import org.springframework.data.rest.repository.support.RepositoriesUtils;
|
||||
import org.springframework.data.rest.repository.support.SimpleRelProvider;
|
||||
import org.springframework.hateoas.RelProvider;
|
||||
import org.springframework.hateoas.core.EvoInflectorRelProvider;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -53,7 +53,7 @@ public class ResourceMappings implements ResourceMetadataProvider, Iterable<Reso
|
||||
* @param repositories
|
||||
*/
|
||||
public ResourceMappings(RepositoryRestConfiguration config, Repositories repositories) {
|
||||
this(config, repositories, new SimpleRelProvider());
|
||||
this(config, repositories, new EvoInflectorRelProvider());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,10 +18,9 @@ package org.springframework.data.rest.repository.mapping;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface ResourceMetadata extends CollectionResourceMapping, ResourceMetadataProvider {
|
||||
|
||||
|
||||
boolean isManaged(PersistentProperty<?> property);
|
||||
}
|
||||
|
||||
@@ -18,12 +18,11 @@ package org.springframework.data.rest.repository.mapping;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface ResourceMetadataProvider {
|
||||
|
||||
boolean isMapped(PersistentProperty<?> property);
|
||||
|
||||
|
||||
ResourceMapping getMappingFor(PersistentProperty<?> property);
|
||||
}
|
||||
|
||||
@@ -15,9 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.rest.repository.mapping;
|
||||
|
||||
|
||||
public class SimpleCollectionResourceMapping implements CollectionResourceMapping {
|
||||
|
||||
|
||||
private final String collectionRel;
|
||||
private final String singleRel;
|
||||
private final String path;
|
||||
@@ -26,9 +25,9 @@ public class SimpleCollectionResourceMapping implements CollectionResourceMappin
|
||||
public SimpleCollectionResourceMapping(String relsAndPath) {
|
||||
this(relsAndPath, relsAndPath, relsAndPath, true);
|
||||
}
|
||||
|
||||
|
||||
public SimpleCollectionResourceMapping(String collectionRel, String singleRel, String path, Boolean exported) {
|
||||
|
||||
|
||||
this.collectionRel = collectionRel;
|
||||
this.singleRel = singleRel;
|
||||
this.path = path;
|
||||
@@ -50,7 +49,7 @@ public class SimpleCollectionResourceMapping implements CollectionResourceMappin
|
||||
public String getSingleResourceRel() {
|
||||
return singleRel;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.mapping.CollectionResourceMapping#getPath()
|
||||
@@ -66,4 +65,4 @@ public class SimpleCollectionResourceMapping implements CollectionResourceMappin
|
||||
public Boolean isExported() {
|
||||
return exported;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,43 +15,43 @@ import org.springframework.data.repository.support.Repositories;
|
||||
*/
|
||||
public class DomainObjectMerger {
|
||||
|
||||
private final Repositories repositories;
|
||||
private final ConversionService conversionService;
|
||||
private final Repositories repositories;
|
||||
private final ConversionService conversionService;
|
||||
|
||||
@Autowired
|
||||
public DomainObjectMerger(Repositories repositories,
|
||||
ConversionService conversionService) {
|
||||
this.repositories = repositories;
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
@Autowired
|
||||
public DomainObjectMerger(Repositories repositories, ConversionService conversionService) {
|
||||
this.repositories = repositories;
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public void merge(Object from, Object target) {
|
||||
if(null == from || null == target) {
|
||||
return;
|
||||
}
|
||||
final BeanWrapper<?, Object> fromWrapper = BeanWrapper.create(from, conversionService);
|
||||
final BeanWrapper<?, Object> targetWrapper = BeanWrapper.create(target, conversionService);
|
||||
|
||||
PersistentEntity<?, ?> entity = repositories.getPersistentEntity(target.getClass());
|
||||
entity.doWithProperties(new PropertyHandler() {
|
||||
@Override public void doWithPersistentProperty(PersistentProperty persistentProperty) {
|
||||
Object fromVal = fromWrapper.getProperty(persistentProperty);
|
||||
if(null != fromVal && !fromVal.equals(targetWrapper.getProperty(persistentProperty))) {
|
||||
targetWrapper.setProperty(persistentProperty, fromVal);
|
||||
}
|
||||
}
|
||||
});
|
||||
entity.doWithAssociations(new AssociationHandler() {
|
||||
@Override public void doWithAssociation(Association association) {
|
||||
PersistentProperty persistentProperty = association.getInverse();
|
||||
Object fromVal = fromWrapper.getProperty(persistentProperty);
|
||||
if(null != fromVal && !fromVal.equals(targetWrapper.getProperty(persistentProperty))) {
|
||||
targetWrapper.setProperty(persistentProperty, fromVal);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public void merge(Object from, Object target) {
|
||||
if (null == from || null == target) {
|
||||
return;
|
||||
}
|
||||
final BeanWrapper<?, Object> fromWrapper = BeanWrapper.create(from, conversionService);
|
||||
final BeanWrapper<?, Object> targetWrapper = BeanWrapper.create(target, conversionService);
|
||||
|
||||
PersistentEntity<?, ?> entity = repositories.getPersistentEntity(target.getClass());
|
||||
entity.doWithProperties(new PropertyHandler() {
|
||||
@Override
|
||||
public void doWithPersistentProperty(PersistentProperty persistentProperty) {
|
||||
Object fromVal = fromWrapper.getProperty(persistentProperty);
|
||||
if (null != fromVal && !fromVal.equals(targetWrapper.getProperty(persistentProperty))) {
|
||||
targetWrapper.setProperty(persistentProperty, fromVal);
|
||||
}
|
||||
}
|
||||
});
|
||||
entity.doWithAssociations(new AssociationHandler() {
|
||||
@Override
|
||||
public void doWithAssociation(Association association) {
|
||||
PersistentProperty persistentProperty = association.getInverse();
|
||||
Object fromVal = fromWrapper.getProperty(persistentProperty);
|
||||
if (null != fromVal && !fromVal.equals(targetWrapper.getProperty(persistentProperty))) {
|
||||
targetWrapper.setProperty(persistentProperty, fromVal);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,19 +10,15 @@ import org.springframework.util.ReflectionUtils;
|
||||
*/
|
||||
public abstract class Methods {
|
||||
|
||||
private Methods() {
|
||||
}
|
||||
private Methods() {}
|
||||
|
||||
public static final ReflectionUtils.MethodFilter USER_METHODS =
|
||||
new ReflectionUtils.MethodFilter() {
|
||||
@Override public boolean matches(Method method) {
|
||||
return (!method.isSynthetic()
|
||||
&& !method.isBridge()
|
||||
&& method.getDeclaringClass() != Object.class
|
||||
&& !method.getName().contains("$"));
|
||||
}
|
||||
};
|
||||
public static final LocalVariableTableParameterNameDiscoverer NAME_DISCOVERER =
|
||||
new LocalVariableTableParameterNameDiscoverer();
|
||||
public static final ReflectionUtils.MethodFilter USER_METHODS = new ReflectionUtils.MethodFilter() {
|
||||
@Override
|
||||
public boolean matches(Method method) {
|
||||
return (!method.isSynthetic() && !method.isBridge() && method.getDeclaringClass() != Object.class && !method
|
||||
.getName().contains("$"));
|
||||
}
|
||||
};
|
||||
public static final LocalVariableTableParameterNameDiscoverer NAME_DISCOVERER = new LocalVariableTableParameterNameDiscoverer();
|
||||
|
||||
}
|
||||
|
||||
@@ -23,20 +23,19 @@ import org.springframework.data.repository.core.support.AnnotationRepositoryMeta
|
||||
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class RepositoriesUtils {
|
||||
|
||||
public static Class<?> getDomainType(Class<?> repositoryType) {
|
||||
|
||||
|
||||
if (!isRepositoryInterface(repositoryType)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
return getMetadataFor(repositoryType).getDomainType();
|
||||
}
|
||||
|
||||
|
||||
public static boolean isRepositoryInterface(Class<?> type) {
|
||||
return Repository.class.isAssignableFrom(type)
|
||||
|| AnnotationUtils.findAnnotation(type, RepositoryDefinition.class) != null;
|
||||
|
||||
@@ -22,56 +22,57 @@ import org.springframework.util.MultiValueMap;
|
||||
@SuppressWarnings("deprecation")
|
||||
public abstract class RepositoryInformationSupport {
|
||||
|
||||
protected Repositories repositories;
|
||||
protected RepositoryRestConfiguration config;
|
||||
protected MultiValueMap<Class<?>, RepositoryMethod> repositoryMethods = new LinkedMultiValueMap<Class<?>, RepositoryMethod>();
|
||||
protected Repositories repositories;
|
||||
protected RepositoryRestConfiguration config;
|
||||
protected MultiValueMap<Class<?>, RepositoryMethod> repositoryMethods = new LinkedMultiValueMap<Class<?>, RepositoryMethod>();
|
||||
|
||||
public Repositories getRepositories() {
|
||||
return repositories;
|
||||
}
|
||||
public Repositories getRepositories() {
|
||||
return repositories;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setRepositories(Repositories repositories) {
|
||||
this.repositories = repositories;
|
||||
for(Class<?> domainType : repositories) {
|
||||
final RepositoryInformation repoInfo = repositories.getRepositoryInformationFor(domainType);
|
||||
doWithMethods(repoInfo.getRepositoryInterface(), new MethodCallback() {
|
||||
@Override public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
|
||||
repositoryMethods.add(repoInfo.getRepositoryInterface(), new RepositoryMethod(method));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@Autowired
|
||||
public void setRepositories(Repositories repositories) {
|
||||
this.repositories = repositories;
|
||||
for (Class<?> domainType : repositories) {
|
||||
final RepositoryInformation repoInfo = repositories.getRepositoryInformationFor(domainType);
|
||||
doWithMethods(repoInfo.getRepositoryInterface(), new MethodCallback() {
|
||||
@Override
|
||||
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
|
||||
repositoryMethods.add(repoInfo.getRepositoryInterface(), new RepositoryMethod(method));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public RepositoryRestConfiguration getConfig() {
|
||||
return config;
|
||||
}
|
||||
public RepositoryRestConfiguration getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setConfig(RepositoryRestConfiguration config) {
|
||||
this.config = config;
|
||||
}
|
||||
@Autowired
|
||||
public void setConfig(RepositoryRestConfiguration config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
protected RepositoryInformation findRepositoryInfoFor(String pathSegment) {
|
||||
if(!hasText(pathSegment)) {
|
||||
return null;
|
||||
}
|
||||
for(Class<?> domainType : repositories) {
|
||||
RepositoryInformation repoInfo = findRepositoryInfoFor(domainType);
|
||||
protected RepositoryInformation findRepositoryInfoFor(String pathSegment) {
|
||||
if (!hasText(pathSegment)) {
|
||||
return null;
|
||||
}
|
||||
for (Class<?> domainType : repositories) {
|
||||
RepositoryInformation repoInfo = findRepositoryInfoFor(domainType);
|
||||
ResourceMapping mapping = getResourceMapping(config, repoInfo);
|
||||
if(pathSegment.equals(mapping.getPath()) && mapping.isExported()) {
|
||||
return repoInfo;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (pathSegment.equals(mapping.getPath()) && mapping.isExported()) {
|
||||
return repoInfo;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected RepositoryInformation findRepositoryInfoFor(Class<?> domainType) {
|
||||
PersistentEntity<?, ?> entity = repositories.getPersistentEntity(domainType);
|
||||
if(null != entity) {
|
||||
return repositories.getRepositoryInformationFor(domainType);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
protected RepositoryInformation findRepositoryInfoFor(Class<?> domainType) {
|
||||
PersistentEntity<?, ?> entity = repositories.getPersistentEntity(domainType);
|
||||
if (null != entity) {
|
||||
return repositories.getRepositoryInformationFor(domainType);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,22 +19,21 @@ import org.springframework.data.rest.repository.mapping.ResourceMappings;
|
||||
import org.springframework.hateoas.RelProvider;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class RepositoryRelProvider implements RelProvider {
|
||||
|
||||
private final ResourceMappings mappings;
|
||||
|
||||
|
||||
/**
|
||||
* @param repositories
|
||||
* @param config
|
||||
*/
|
||||
public RepositoryRelProvider(ResourceMappings mappings) {
|
||||
|
||||
|
||||
this.mappings = mappings;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.hateoas.RelProvider#getCollectionResourceRelFor(java.lang.Class)
|
||||
@@ -43,7 +42,7 @@ public class RepositoryRelProvider implements RelProvider {
|
||||
public String getCollectionResourceRelFor(Class<?> type) {
|
||||
return mappings.getMappingFor(type).getRel();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.hateoas.RelProvider#getSingleResourceRelFor(java.lang.Class)
|
||||
@@ -52,7 +51,7 @@ public class RepositoryRelProvider implements RelProvider {
|
||||
public String getSingleResourceRelFor(Class<?> type) {
|
||||
return mappings.getMappingFor(type).getSingleResourceRel();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.plugin.core.Plugin#supports(java.lang.Object)
|
||||
|
||||
@@ -67,7 +67,7 @@ public abstract class ResourceMappingUtils {
|
||||
|
||||
public static String formatRel(RepositoryRestConfiguration config, RepositoryInformation repoInfo,
|
||||
PersistentProperty<?> persistentProperty) {
|
||||
|
||||
|
||||
if (persistentProperty == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -81,9 +81,9 @@ public abstract class ResourceMappingUtils {
|
||||
}
|
||||
|
||||
public static String findPath(Class<?> type) {
|
||||
|
||||
|
||||
RestResource anno = findAnnotation(type, RestResource.class);
|
||||
|
||||
|
||||
if (anno != null) {
|
||||
if (hasTextExceptSlash(anno.path())) {
|
||||
return removeLeadingSlash(anno.path());
|
||||
@@ -94,9 +94,9 @@ public abstract class ResourceMappingUtils {
|
||||
}
|
||||
|
||||
public static String findPath(Method method) {
|
||||
|
||||
|
||||
RestResource anno = findAnnotation(method, RestResource.class);
|
||||
|
||||
|
||||
if (anno != null) {
|
||||
if (hasTextExceptSlash(anno.path())) {
|
||||
return removeLeadingSlash(anno.path());
|
||||
|
||||
@@ -53,11 +53,11 @@ public class ResourceStringUtils {
|
||||
}
|
||||
|
||||
boolean hasLeadingSlash = startsWithSlash(path);
|
||||
|
||||
|
||||
if (path.length() == 1) {
|
||||
return hasLeadingSlash ? "" : path;
|
||||
}
|
||||
|
||||
|
||||
return hasLeadingSlash ? path.substring(1) : path;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ import org.springframework.hateoas.RelProvider;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class SimpleRelProvider implements RelProvider {
|
||||
|
||||
@@ -35,89 +35,84 @@ import org.springframework.data.rest.repository.support.SimpleRelProvider;
|
||||
|
||||
/**
|
||||
* Ensure the {@link ResourceMapping} components convey the correct information.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class ResourceMappingUnitTests {
|
||||
|
||||
|
||||
ResourceMappingFactory factory = new ResourceMappingFactory(new SimpleRelProvider());
|
||||
|
||||
@Test
|
||||
public void shouldDetectDefaultRelAndPath() throws Exception {
|
||||
|
||||
ResourceMapping newMapping = factory.getMappingForType(PlainPersonRepository.class);
|
||||
|
||||
assertThat(newMapping.getRel(), is("person"));
|
||||
assertThat(newMapping.getPath(), is("person"));
|
||||
assertThat(newMapping.isExported(), is(true));
|
||||
}
|
||||
@Test
|
||||
public void shouldDetectDefaultRelAndPath() throws Exception {
|
||||
|
||||
@Test
|
||||
public void shouldDetectAnnotatedRelAndPath() throws Exception {
|
||||
|
||||
ResourceMapping newMapping = factory.getMappingForType(AnnotatedPersonRepository.class);
|
||||
|
||||
assertThat(newMapping.getRel(), is("people"));
|
||||
assertThat(newMapping.getPath(), is("person"));
|
||||
assertThat(newMapping.isExported(), is(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDetectPathAndRemoveLeadingSlashIfAny() {
|
||||
ResourceMapping newMapping = factory.getMappingForType(PlainPersonRepository.class);
|
||||
|
||||
assertThat(newMapping.getRel(), is("person"));
|
||||
assertThat(newMapping.getPath(), is("person"));
|
||||
assertThat(newMapping.isExported(), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDetectAnnotatedRelAndPath() throws Exception {
|
||||
|
||||
ResourceMapping newMapping = factory.getMappingForType(AnnotatedPersonRepository.class);
|
||||
|
||||
assertThat(newMapping.getRel(), is("people"));
|
||||
assertThat(newMapping.getPath(), is("person"));
|
||||
assertThat(newMapping.isExported(), is(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDetectPathAndRemoveLeadingSlashIfAny() {
|
||||
org.springframework.data.rest.config.ResourceMapping mapping = new org.springframework.data.rest.config.ResourceMapping(
|
||||
findRel(AnnotatedWithLeadingSlashPersonRepository.class),
|
||||
findPath(AnnotatedWithLeadingSlashPersonRepository.class),
|
||||
findExported(AnnotatedWithLeadingSlashPersonRepository.class)
|
||||
);
|
||||
findRel(AnnotatedWithLeadingSlashPersonRepository.class),
|
||||
findPath(AnnotatedWithLeadingSlashPersonRepository.class),
|
||||
findExported(AnnotatedWithLeadingSlashPersonRepository.class));
|
||||
|
||||
// The rel attribute defaults to class name
|
||||
assertThat(mapping.getRel(), is("annotatedWithLeadingSlashPerson"));
|
||||
assertThat(mapping.getPath(), is("people"));
|
||||
// The exported defaults to true
|
||||
assertThat(mapping.isExported(), is(true));
|
||||
}
|
||||
// The rel attribute defaults to class name
|
||||
assertThat(mapping.getRel(), is("annotatedWithLeadingSlashPerson"));
|
||||
assertThat(mapping.getPath(), is("people"));
|
||||
// The exported defaults to true
|
||||
assertThat(mapping.isExported(), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDetectPathAndRemoveLeadingSlashIfAnyOnMethod() throws Exception {
|
||||
Method method = AnnotatedWithLeadingSlashPersonRepository.class.getMethod("findByFirstName", String.class, Pageable.class);
|
||||
org.springframework.data.rest.config.ResourceMapping mapping = new org.springframework.data.rest.config.ResourceMapping(
|
||||
findRel(method),
|
||||
findPath(method),
|
||||
findExported(method)
|
||||
);
|
||||
@Test
|
||||
public void shouldDetectPathAndRemoveLeadingSlashIfAnyOnMethod() throws Exception {
|
||||
Method method = AnnotatedWithLeadingSlashPersonRepository.class.getMethod("findByFirstName", String.class,
|
||||
Pageable.class);
|
||||
org.springframework.data.rest.config.ResourceMapping mapping = new org.springframework.data.rest.config.ResourceMapping(
|
||||
findRel(method), findPath(method), findExported(method));
|
||||
|
||||
// The rel attribute defaults to class name
|
||||
assertThat(mapping.getRel(), is("findByFirstName"));
|
||||
assertThat(mapping.getPath(), is("firstname"));
|
||||
// The exported defaults to true
|
||||
assertThat(mapping.isExported(), is(true));
|
||||
}
|
||||
// The rel attribute defaults to class name
|
||||
assertThat(mapping.getRel(), is("findByFirstName"));
|
||||
assertThat(mapping.getPath(), is("firstname"));
|
||||
// The exported defaults to true
|
||||
assertThat(mapping.isExported(), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnDefaultIfPathContainsOnlySlashTextOnMethod() throws Exception {
|
||||
Method method = AnnotatedWithLeadingSlashPersonRepository.class.getMethod("findByLastName", String.class, Pageable.class);
|
||||
org.springframework.data.rest.config.ResourceMapping mapping = new org.springframework.data.rest.config.ResourceMapping(
|
||||
findRel(method),
|
||||
findPath(method),
|
||||
findExported(method)
|
||||
);
|
||||
@Test
|
||||
public void shouldReturnDefaultIfPathContainsOnlySlashTextOnMethod() throws Exception {
|
||||
Method method = AnnotatedWithLeadingSlashPersonRepository.class.getMethod("findByLastName", String.class,
|
||||
Pageable.class);
|
||||
org.springframework.data.rest.config.ResourceMapping mapping = new org.springframework.data.rest.config.ResourceMapping(
|
||||
findRel(method), findPath(method), findExported(method));
|
||||
|
||||
// The rel defaults to method name
|
||||
assertThat(mapping.getRel(), is("findByLastName"));
|
||||
// The path contains only a leading slash therefore defaults to method name
|
||||
assertThat(mapping.getPath(), is("findByLastName"));
|
||||
// The exported defaults to true
|
||||
assertThat(mapping.isExported(), is(true));
|
||||
}
|
||||
|
||||
@RestResource(path = "/people")
|
||||
interface AnnotatedWithLeadingSlashPersonRepository {
|
||||
// The rel defaults to method name
|
||||
assertThat(mapping.getRel(), is("findByLastName"));
|
||||
// The path contains only a leading slash therefore defaults to method name
|
||||
assertThat(mapping.getPath(), is("findByLastName"));
|
||||
// The exported defaults to true
|
||||
assertThat(mapping.isExported(), is(true));
|
||||
}
|
||||
|
||||
@RestResource(path = "/firstname")
|
||||
Page<Person> findByFirstName(@Param("firstName") String firstName, Pageable pageable);
|
||||
@RestResource(path = "/people")
|
||||
interface AnnotatedWithLeadingSlashPersonRepository {
|
||||
|
||||
@RestResource(path = " / ")
|
||||
Page<Person> findByLastName(@Param("lastName") String firstName, Pageable pageable);
|
||||
}
|
||||
@RestResource(path = "/firstname")
|
||||
Page<Person> findByFirstName(@Param("firstName") String firstName, Pageable pageable);
|
||||
|
||||
@RestResource(path = " / ")
|
||||
Page<Person> findByLastName(@Param("lastName") String firstName, Pageable pageable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
* Tests to check that {@link ResourceMapping}s are handled correctly.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@@ -22,17 +22,16 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
@SuppressWarnings("deprecation")
|
||||
public class RepositoryRestConfigurationIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
RepositoryRestConfiguration config;
|
||||
@Autowired RepositoryRestConfiguration config;
|
||||
|
||||
@Test
|
||||
public void shouldProvideResourceMappingForConfiguredRepository() throws Exception {
|
||||
@Test
|
||||
public void shouldProvideResourceMappingForConfiguredRepository() throws Exception {
|
||||
ResourceMapping mapping = config.getResourceMappingForRepository(ConfiguredPersonRepository.class);
|
||||
|
||||
assertThat(mapping, notNullValue());
|
||||
assertThat(mapping.getRel(), is("people"));
|
||||
assertThat(mapping.getPath(), is("people"));
|
||||
assertThat(mapping.isExported(), is(false));
|
||||
}
|
||||
assertThat(mapping, notNullValue());
|
||||
assertThat(mapping.getRel(), is("people"));
|
||||
assertThat(mapping.getPath(), is("people"));
|
||||
assertThat(mapping.isExported(), is(false));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,47 +18,44 @@ import org.springframework.format.support.DefaultFormattingConversionService;
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@Configuration
|
||||
@Import({JpaRepositoryConfig.class})
|
||||
@Import({ JpaRepositoryConfig.class })
|
||||
public class RepositoryTestsConfig {
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext appCtx;
|
||||
@Autowired private ApplicationContext appCtx;
|
||||
|
||||
@Bean public Repositories repositories() {
|
||||
return new Repositories(appCtx);
|
||||
}
|
||||
@Bean
|
||||
public Repositories repositories() {
|
||||
return new Repositories(appCtx);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Bean public RepositoryRestConfiguration config() {
|
||||
RepositoryRestConfiguration config = new RepositoryRestConfiguration();
|
||||
@SuppressWarnings("deprecation")
|
||||
@Bean
|
||||
public RepositoryRestConfiguration config() {
|
||||
RepositoryRestConfiguration config = new RepositoryRestConfiguration();
|
||||
|
||||
config.setResourceMappingForDomainType(Person.class)
|
||||
.setRel("person");
|
||||
config.setResourceMappingForDomainType(Person.class).setRel("person");
|
||||
|
||||
config.setResourceMappingForRepository(ConfiguredPersonRepository.class)
|
||||
.setRel("people")
|
||||
.setPath("people")
|
||||
.setExported(false);
|
||||
config.setResourceMappingForRepository(ConfiguredPersonRepository.class).setRel("people").setPath("people")
|
||||
.setExported(false);
|
||||
|
||||
config.setResourceMappingForRepository(PersonRepository.class)
|
||||
.setRel("people")
|
||||
.setPath("people")
|
||||
.addResourceMappingFor("findByFirstName")
|
||||
.setRel("firstname")
|
||||
.setPath("firstname");
|
||||
config.setResourceMappingForRepository(PersonRepository.class).setRel("people").setPath("people")
|
||||
.addResourceMappingFor("findByFirstName").setRel("firstname").setPath("firstname");
|
||||
|
||||
return config;
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
@Bean public DefaultFormattingConversionService defaultConversionService() {
|
||||
return new DefaultFormattingConversionService();
|
||||
}
|
||||
@Bean
|
||||
public DefaultFormattingConversionService defaultConversionService() {
|
||||
return new DefaultFormattingConversionService();
|
||||
}
|
||||
|
||||
@Bean public DomainClassConverter<?> domainClassConverter() {
|
||||
return new DomainClassConverter<DefaultFormattingConversionService>(defaultConversionService());
|
||||
}
|
||||
@Bean
|
||||
public DomainClassConverter<?> domainClassConverter() {
|
||||
return new DomainClassConverter<DefaultFormattingConversionService>(defaultConversionService());
|
||||
}
|
||||
|
||||
@Bean public UriDomainClassConverter uriDomainClassConverter() {
|
||||
return new UriDomainClassConverter();
|
||||
}
|
||||
@Bean
|
||||
public UriDomainClassConverter uriDomainClassConverter() {
|
||||
return new UriDomainClassConverter();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,17 +12,15 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
* Tests around the {@link org.springframework.context.ApplicationEvent} handling abstractions.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = RepositoryEventTestsConfig.class)
|
||||
public class RepositoryEventIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
ApplicationContext appCtx;
|
||||
@Autowired
|
||||
PersonRepository people;
|
||||
@Autowired ApplicationContext appCtx;
|
||||
@Autowired PersonRepository people;
|
||||
Person person;
|
||||
|
||||
@Before
|
||||
|
||||
@@ -11,19 +11,22 @@ import org.springframework.data.rest.repository.domain.jpa.PersonBeforeSaveHandl
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@Configuration
|
||||
@Import({RepositoryTestsConfig.class})
|
||||
@Import({ RepositoryTestsConfig.class })
|
||||
public class RepositoryEventTestsConfig {
|
||||
|
||||
@Bean public PersonBeforeSaveHandler personBeforeSaveHandler() {
|
||||
return new PersonBeforeSaveHandler();
|
||||
}
|
||||
@Bean
|
||||
public PersonBeforeSaveHandler personBeforeSaveHandler() {
|
||||
return new PersonBeforeSaveHandler();
|
||||
}
|
||||
|
||||
@Bean public AnnotatedPersonEventHandler beforeSaveHandler() {
|
||||
return new AnnotatedPersonEventHandler();
|
||||
}
|
||||
@Bean
|
||||
public AnnotatedPersonEventHandler beforeSaveHandler() {
|
||||
return new AnnotatedPersonEventHandler();
|
||||
}
|
||||
|
||||
@Bean public AnnotatedHandlerBeanPostProcessor annotatedHandlerBeanPostProcessor() {
|
||||
return new AnnotatedHandlerBeanPostProcessor();
|
||||
}
|
||||
@Bean
|
||||
public AnnotatedHandlerBeanPostProcessor annotatedHandlerBeanPostProcessor() {
|
||||
return new AnnotatedHandlerBeanPostProcessor();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,19 +11,18 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
* Tests to check the {@link org.springframework.validation.Validator} integration.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = ValidatorTestsConfig.class)
|
||||
public class ValidatorIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
ApplicationContext appCtx;
|
||||
@Autowired ApplicationContext appCtx;
|
||||
|
||||
@Test(expected = RepositoryConstraintViolationException.class)
|
||||
public void shouldValidateLastName() throws Exception {
|
||||
appCtx.publishEvent(new BeforeSaveEvent(new Person()));
|
||||
}
|
||||
@Test(expected = RepositoryConstraintViolationException.class)
|
||||
public void shouldValidateLastName() throws Exception {
|
||||
appCtx.publishEvent(new BeforeSaveEvent(new Person()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,11 +9,12 @@ import org.springframework.data.rest.repository.RepositoryTestsConfig;
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@Configuration
|
||||
@Import({RepositoryTestsConfig.class})
|
||||
@Import({ RepositoryTestsConfig.class })
|
||||
public class ValidatorTestsConfig {
|
||||
|
||||
@Bean public ValidatingRepositoryEventListener validatingListener() {
|
||||
return new ValidatingRepositoryEventListener();
|
||||
}
|
||||
@Bean
|
||||
public ValidatingRepositoryEventListener validatingListener() {
|
||||
return new ValidatingRepositoryEventListener();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,10 +6,9 @@ import org.springframework.data.rest.repository.annotation.RestResource;
|
||||
|
||||
/**
|
||||
* A repository to manage {@link org.springframework.data.rest.repository.domain.jpa.Person}s.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@RestResource(rel = "people", exported = false)
|
||||
@NoRepositoryBean
|
||||
public interface AnnotatedPersonRepository extends CrudRepository<Person, Long> {
|
||||
}
|
||||
public interface AnnotatedPersonRepository extends CrudRepository<Person, Long> {}
|
||||
|
||||
@@ -5,9 +5,8 @@ import org.springframework.data.repository.NoRepositoryBean;
|
||||
|
||||
/**
|
||||
* A repository to manage {@link Person}s.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@NoRepositoryBean
|
||||
public interface ConfiguredPersonRepository extends CrudRepository<Person, Long> {
|
||||
}
|
||||
public interface ConfiguredPersonRepository extends CrudRepository<Person, Long> {}
|
||||
|
||||
@@ -45,39 +45,44 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
@EnableTransactionManagement
|
||||
public class JpaRepositoryConfig {
|
||||
|
||||
@Bean public MessageSource messageSource() {
|
||||
ResourceBundleMessageSource ms = new ResourceBundleMessageSource();
|
||||
ms.setBasename("org.springframework.data.rest.repository.ValidationErrors");
|
||||
return ms;
|
||||
}
|
||||
@Bean
|
||||
public MessageSource messageSource() {
|
||||
ResourceBundleMessageSource ms = new ResourceBundleMessageSource();
|
||||
ms.setBasename("org.springframework.data.rest.repository.ValidationErrors");
|
||||
return ms;
|
||||
}
|
||||
|
||||
@Bean public DataSource dataSource() {
|
||||
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
|
||||
return builder.setType(EmbeddedDatabaseType.HSQL).build();
|
||||
}
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
|
||||
return builder.setType(EmbeddedDatabaseType.HSQL).build();
|
||||
}
|
||||
|
||||
@Bean public EntityManagerFactory entityManagerFactory() {
|
||||
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
|
||||
vendorAdapter.setDatabase(Database.HSQL);
|
||||
vendorAdapter.setGenerateDdl(true);
|
||||
@Bean
|
||||
public EntityManagerFactory entityManagerFactory() {
|
||||
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
|
||||
vendorAdapter.setDatabase(Database.HSQL);
|
||||
vendorAdapter.setGenerateDdl(true);
|
||||
|
||||
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
|
||||
factory.setJpaVendorAdapter(vendorAdapter);
|
||||
factory.setPackagesToScan(getClass().getPackage().getName());
|
||||
factory.setDataSource(dataSource());
|
||||
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
|
||||
factory.setJpaVendorAdapter(vendorAdapter);
|
||||
factory.setPackagesToScan(getClass().getPackage().getName());
|
||||
factory.setDataSource(dataSource());
|
||||
|
||||
factory.afterPropertiesSet();
|
||||
factory.afterPropertiesSet();
|
||||
|
||||
return factory.getObject();
|
||||
}
|
||||
return factory.getObject();
|
||||
}
|
||||
|
||||
@Bean public JpaDialect jpaDialect() {
|
||||
return new HibernateJpaDialect();
|
||||
}
|
||||
@Bean
|
||||
public JpaDialect jpaDialect() {
|
||||
return new HibernateJpaDialect();
|
||||
}
|
||||
|
||||
@Bean public PlatformTransactionManager transactionManager() {
|
||||
JpaTransactionManager txManager = new JpaTransactionManager();
|
||||
txManager.setEntityManagerFactory(entityManagerFactory());
|
||||
return txManager;
|
||||
}
|
||||
@Bean
|
||||
public PlatformTransactionManager transactionManager() {
|
||||
JpaTransactionManager txManager = new JpaTransactionManager();
|
||||
txManager.setEntityManagerFactory(entityManagerFactory());
|
||||
return txManager;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,70 +13,68 @@ import javax.persistence.PrePersist;
|
||||
|
||||
/**
|
||||
* An entity that represents a person.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@Entity
|
||||
public class Person {
|
||||
|
||||
@Id @GeneratedValue private Long id;
|
||||
private String firstName;
|
||||
private String lastName;
|
||||
@OneToMany
|
||||
private List<Person> siblings = Collections.emptyList();
|
||||
private Date created;
|
||||
@Id @GeneratedValue private Long id;
|
||||
private String firstName;
|
||||
private String lastName;
|
||||
@OneToMany private List<Person> siblings = Collections.emptyList();
|
||||
private Date created;
|
||||
|
||||
public Person() {
|
||||
}
|
||||
public Person() {}
|
||||
|
||||
public Person(String firstName, String lastName) {
|
||||
this.firstName = firstName;
|
||||
this.lastName = lastName;
|
||||
}
|
||||
public Person(String firstName, String lastName) {
|
||||
this.firstName = firstName;
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public Person addSibling(Person p) {
|
||||
if(siblings == Collections.EMPTY_LIST) {
|
||||
siblings = new ArrayList<Person>();
|
||||
}
|
||||
siblings.add(p);
|
||||
return this;
|
||||
}
|
||||
public Person addSibling(Person p) {
|
||||
if (siblings == Collections.EMPTY_LIST) {
|
||||
siblings = new ArrayList<Person>();
|
||||
}
|
||||
siblings.add(p);
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<Person> getSiblings() {
|
||||
return siblings;
|
||||
}
|
||||
public List<Person> getSiblings() {
|
||||
return siblings;
|
||||
}
|
||||
|
||||
public void setSiblings(List<Person> siblings) {
|
||||
this.siblings = siblings;
|
||||
}
|
||||
public void setSiblings(List<Person> siblings) {
|
||||
this.siblings = siblings;
|
||||
}
|
||||
|
||||
public Date getCreated() {
|
||||
return created;
|
||||
}
|
||||
public Date getCreated() {
|
||||
return created;
|
||||
}
|
||||
|
||||
@PrePersist
|
||||
private void prePersist() {
|
||||
this.created = Calendar.getInstance().getTime();
|
||||
}
|
||||
@PrePersist
|
||||
private void prePersist() {
|
||||
this.created = Calendar.getInstance().getTime();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,7 +6,8 @@ import org.springframework.data.rest.repository.context.AbstractRepositoryEventL
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
public class PersonBeforeSaveHandler extends AbstractRepositoryEventListener<Person> {
|
||||
@Override protected void onBeforeSave(Person person) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
@Override
|
||||
protected void onBeforeSave(Person person) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,10 +10,10 @@ import org.springframework.stereotype.Component;
|
||||
@Component
|
||||
public class PersonLoader implements InitializingBean {
|
||||
|
||||
@Autowired
|
||||
PersonRepository people;
|
||||
@Autowired PersonRepository people;
|
||||
|
||||
@Override public void afterPropertiesSet() throws Exception {
|
||||
people.save(new Person("John", "Doe"));
|
||||
}
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
people.save(new Person("John", "Doe"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,22 +10,24 @@ import org.springframework.validation.Validator;
|
||||
|
||||
/**
|
||||
* A test {@link Validator} that checks for non-blank names.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@Component
|
||||
@HandleBeforeSave
|
||||
public class PersonNameValidator implements Validator {
|
||||
|
||||
@Override public boolean supports(Class<?> clazz) {
|
||||
return isAssignable(clazz, Person.class);
|
||||
}
|
||||
@Override
|
||||
public boolean supports(Class<?> clazz) {
|
||||
return isAssignable(clazz, Person.class);
|
||||
}
|
||||
|
||||
@Override public void validate(Object target, Errors errors) {
|
||||
Person p = (Person)target;
|
||||
if(!hasText(p.getLastName())) {
|
||||
errors.rejectValue("lastName", "blank", "Last name cannot be blank");
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void validate(Object target, Errors errors) {
|
||||
Person p = (Person) target;
|
||||
if (!hasText(p.getLastName())) {
|
||||
errors.rejectValue("lastName", "blank", "Last name cannot be blank");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,22 +13,19 @@ import org.springframework.data.rest.repository.annotation.RestResource;
|
||||
|
||||
/**
|
||||
* A repository to manage {@link Person}s.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@RestResource(rel = "people", path = "people")
|
||||
public interface PersonRepository extends PagingAndSortingRepository<Person, Long> {
|
||||
|
||||
@RestResource(rel = "firstname", path = "firstname")
|
||||
public Page<Person> findByFirstName(@Param("firstName") String firstName, Pageable pageable);
|
||||
@RestResource(rel = "firstname", path = "firstname")
|
||||
public Page<Person> findByFirstName(@Param("firstName") String firstName, Pageable pageable);
|
||||
|
||||
public Page<Person> findByCreatedGreaterThan(@Param("date") Date date, Pageable pageable);
|
||||
public Page<Person> findByCreatedGreaterThan(@Param("date") Date date, Pageable pageable);
|
||||
|
||||
@Query("select p from Person p where p.created > :date")
|
||||
public Page<Person> findByCreatedUsingISO8601Date(@Param("date")
|
||||
@ConvertWith(
|
||||
ISO8601DateConverter.class)
|
||||
Date date,
|
||||
Pageable pageable);
|
||||
@Query("select p from Person p where p.created > :date")
|
||||
public Page<Person> findByCreatedUsingISO8601Date(@Param("date") @ConvertWith(ISO8601DateConverter.class) Date date,
|
||||
Pageable pageable);
|
||||
|
||||
}
|
||||
|
||||
@@ -5,9 +5,8 @@ import org.springframework.data.repository.NoRepositoryBean;
|
||||
|
||||
/**
|
||||
* A repository to manage {@link Person}s.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@NoRepositoryBean
|
||||
public interface PlainPersonRepository extends CrudRepository<Person, Long> {
|
||||
}
|
||||
public interface PlainPersonRepository extends CrudRepository<Person, Long> {}
|
||||
|
||||
@@ -15,16 +15,18 @@ import org.springframework.data.mongodb.repository.config.EnableMongoRepositorie
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@Configuration
|
||||
@ComponentScan(basePackageClasses = {MongoDbRepositoryConfig.class})
|
||||
@ComponentScan(basePackageClasses = { MongoDbRepositoryConfig.class })
|
||||
@EnableMongoRepositories
|
||||
public class MongoDbRepositoryConfig {
|
||||
|
||||
@Bean public MongoDbFactory mongoDbFactory() throws UnknownHostException {
|
||||
return new SimpleMongoDbFactory(new Mongo("localhost"), "spring-data-rest");
|
||||
}
|
||||
@Bean
|
||||
public MongoDbFactory mongoDbFactory() throws UnknownHostException {
|
||||
return new SimpleMongoDbFactory(new Mongo("localhost"), "spring-data-rest");
|
||||
}
|
||||
|
||||
@Bean public MongoTemplate mongoTemplate() throws UnknownHostException {
|
||||
return new MongoTemplate(mongoDbFactory());
|
||||
}
|
||||
@Bean
|
||||
public MongoTemplate mongoTemplate() throws UnknownHostException {
|
||||
return new MongoTemplate(mongoDbFactory());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,39 +9,38 @@ import org.springframework.data.mongodb.core.mapping.Document;
|
||||
@Document
|
||||
public class Profile {
|
||||
|
||||
@Id private String id;
|
||||
private String name;
|
||||
private String type;
|
||||
@Id private String id;
|
||||
private String name;
|
||||
private String type;
|
||||
|
||||
public Profile() {
|
||||
}
|
||||
public Profile() {}
|
||||
|
||||
public Profile(String id, String name, String type) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
public Profile(String id, String name, String type) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Profile setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
public Profile setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public Profile setType(String type) {
|
||||
this.type = type;
|
||||
return this;
|
||||
}
|
||||
public Profile setType(String type) {
|
||||
this.type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,11 +10,11 @@ import org.springframework.stereotype.Component;
|
||||
@Component
|
||||
public class ProfileLoader implements InitializingBean {
|
||||
|
||||
@Autowired
|
||||
private ProfileRepository profiles;
|
||||
@Autowired private ProfileRepository profiles;
|
||||
|
||||
@Override public void afterPropertiesSet() throws Exception {
|
||||
profiles.save(new Profile("jdoe", "jdoe", "account"));
|
||||
}
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
profiles.save(new Profile("jdoe", "jdoe", "account"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,8 +5,7 @@ import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
/**
|
||||
* Repository for managing {@link Profile}s in MongoDB.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
public interface ProfileRepository extends CrudRepository<Profile, ObjectId> {
|
||||
}
|
||||
public interface ProfileRepository extends CrudRepository<Profile, ObjectId> {}
|
||||
|
||||
@@ -21,50 +21,48 @@ import org.springframework.format.support.DefaultFormattingConversionService;
|
||||
*/
|
||||
public class MethodParameterConversionServiceUnitTests {
|
||||
|
||||
static final SimpleDateFormat ISO8601_FMT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
|
||||
static final String[] DATE_S = new String[]{"2010-01-01T12:00:00-0600"};
|
||||
static final Date DATE_D;
|
||||
static final SimpleDateFormat ISO8601_FMT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
|
||||
static final String[] DATE_S = new String[] { "2010-01-01T12:00:00-0600" };
|
||||
static final Date DATE_D;
|
||||
|
||||
static {
|
||||
try {
|
||||
DATE_D = ISO8601_FMT.parse(DATE_S[0]);
|
||||
} catch(ParseException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
static {
|
||||
try {
|
||||
DATE_D = ISO8601_FMT.parse(DATE_S[0]);
|
||||
} catch (ParseException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
MethodParameter findByCreatedGreaterThan;
|
||||
MethodParameter findByCreatedUsingISO8601Date;
|
||||
MethodParameter findByCreatedGreaterThan;
|
||||
MethodParameter findByCreatedUsingISO8601Date;
|
||||
|
||||
@Before
|
||||
public void setup() throws NoSuchMethodException {
|
||||
findByCreatedGreaterThan = new MethodParameter(PersonRepository.class.getMethod("findByCreatedGreaterThan",
|
||||
Date.class,
|
||||
Pageable.class), 0);
|
||||
findByCreatedUsingISO8601Date = new MethodParameter(PersonRepository.class.getMethod("findByCreatedUsingISO8601Date",
|
||||
Date.class,
|
||||
Pageable.class), 0);
|
||||
}
|
||||
@Before
|
||||
public void setup() throws NoSuchMethodException {
|
||||
findByCreatedGreaterThan = new MethodParameter(PersonRepository.class.getMethod("findByCreatedGreaterThan",
|
||||
Date.class, Pageable.class), 0);
|
||||
findByCreatedUsingISO8601Date = new MethodParameter(PersonRepository.class.getMethod(
|
||||
"findByCreatedUsingISO8601Date", Date.class, Pageable.class), 0);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"deprecation"})
|
||||
@Test
|
||||
public void shouldConvertDateParameterUsingDefaultConverter() throws Exception {
|
||||
ConfigurableConversionService cs = new DefaultFormattingConversionService();
|
||||
MethodParameterConversionService conversionService = new MethodParameterConversionService(cs);
|
||||
@SuppressWarnings({ "deprecation" })
|
||||
@Test
|
||||
public void shouldConvertDateParameterUsingDefaultConverter() throws Exception {
|
||||
ConfigurableConversionService cs = new DefaultFormattingConversionService();
|
||||
MethodParameterConversionService conversionService = new MethodParameterConversionService(cs);
|
||||
|
||||
String dateStr = "01/01/2010";
|
||||
assertThat(conversionService.canConvert(String.class, findByCreatedGreaterThan), is(true));
|
||||
assertThat((Date)conversionService.convert(dateStr, findByCreatedGreaterThan), is(new Date(dateStr)));
|
||||
}
|
||||
String dateStr = "01/01/2010";
|
||||
assertThat(conversionService.canConvert(String.class, findByCreatedGreaterThan), is(true));
|
||||
assertThat((Date) conversionService.convert(dateStr, findByCreatedGreaterThan), is(new Date(dateStr)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldConvertDateParameterUsingSpecificConverter() throws Exception {
|
||||
ConfigurableConversionService cs = new DefaultFormattingConversionService();
|
||||
cs.addConverter(ISO8601DateConverter.INSTANCE);
|
||||
MethodParameterConversionService conversionService = new MethodParameterConversionService(cs);
|
||||
@Test
|
||||
public void shouldConvertDateParameterUsingSpecificConverter() throws Exception {
|
||||
ConfigurableConversionService cs = new DefaultFormattingConversionService();
|
||||
cs.addConverter(ISO8601DateConverter.INSTANCE);
|
||||
MethodParameterConversionService conversionService = new MethodParameterConversionService(cs);
|
||||
|
||||
assertThat(conversionService.canConvert(String.class, findByCreatedUsingISO8601Date), is(true));
|
||||
assertThat((Date)conversionService.convert(DATE_S, findByCreatedUsingISO8601Date), is(DATE_D));
|
||||
}
|
||||
assertThat(conversionService.canConvert(String.class, findByCreatedUsingISO8601Date), is(true));
|
||||
assertThat((Date) conversionService.convert(DATE_S, findByCreatedUsingISO8601Date), is(DATE_D));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,57 +17,55 @@ import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Tests to verify the integrity of the {@link RepositoryMethod} abstraction.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
public class RepositoryMethodUnitTests {
|
||||
|
||||
Map<String, RepositoryMethod> methods = new HashMap<String, RepositoryMethod>();
|
||||
RepositoryMethod method;
|
||||
Map<String, RepositoryMethod> methods = new HashMap<String, RepositoryMethod>();
|
||||
RepositoryMethod method;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
doWithMethods(PersonRepository.class,
|
||||
new ReflectionUtils.MethodCallback() {
|
||||
@Override public void doWith(Method method) throws IllegalArgumentException,
|
||||
IllegalAccessException {
|
||||
String name = method.getName();
|
||||
RepositoryMethod repoMethod = new RepositoryMethod(method);
|
||||
methods.put(name, repoMethod);
|
||||
}
|
||||
},
|
||||
Methods.USER_METHODS);
|
||||
method = methods.get("findByFirstName");
|
||||
}
|
||||
@Before
|
||||
public void setup() {
|
||||
doWithMethods(PersonRepository.class, new ReflectionUtils.MethodCallback() {
|
||||
@Override
|
||||
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
|
||||
String name = method.getName();
|
||||
RepositoryMethod repoMethod = new RepositoryMethod(method);
|
||||
methods.put(name, repoMethod);
|
||||
}
|
||||
}, Methods.USER_METHODS);
|
||||
method = methods.get("findByFirstName");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFindSimpleQueryMethods() throws Exception {
|
||||
assertThat(method, notNullValue());
|
||||
}
|
||||
@Test
|
||||
public void shouldFindSimpleQueryMethods() throws Exception {
|
||||
assertThat(method, notNullValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFindPageableInformationOnMethod() throws Exception {
|
||||
assertThat(method, notNullValue());
|
||||
assertThat(method.isPageable(), is(true));
|
||||
}
|
||||
@Test
|
||||
public void shouldFindPageableInformationOnMethod() throws Exception {
|
||||
assertThat(method, notNullValue());
|
||||
assertThat(method.isPageable(), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotFindSortInformationOnMethod() throws Exception {
|
||||
assertThat(method, notNullValue());
|
||||
assertThat(method.isSortable(), is(false));
|
||||
}
|
||||
@Test
|
||||
public void shouldNotFindSortInformationOnMethod() throws Exception {
|
||||
assertThat(method, notNullValue());
|
||||
assertThat(method.isSortable(), is(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldProvideParameterClassTypes() throws Exception {
|
||||
assertThat(method, notNullValue());
|
||||
assertThat(method.getParameters().get(0).getParameterType(), is(typeCompatibleWith(String.class)));
|
||||
assertThat(method.getParameters().get(1).getParameterType(), is(typeCompatibleWith(Pageable.class)));
|
||||
}
|
||||
@Test
|
||||
public void shouldProvideParameterClassTypes() throws Exception {
|
||||
assertThat(method, notNullValue());
|
||||
assertThat(method.getParameters().get(0).getParameterType(), is(typeCompatibleWith(String.class)));
|
||||
assertThat(method.getParameters().get(1).getParameterType(), is(typeCompatibleWith(Pageable.class)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldProvideParameterNames() throws Exception {
|
||||
assertThat(method, notNullValue());
|
||||
assertThat(method.getParameterNames(), contains("firstName", "arg1"));
|
||||
}
|
||||
@Test
|
||||
public void shouldProvideParameterNames() throws Exception {
|
||||
assertThat(method, notNullValue());
|
||||
assertThat(method.getParameterNames(), contains("firstName", "arg1"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,38 +23,37 @@ import org.springframework.data.rest.repository.annotation.RestResource;
|
||||
import org.springframework.data.rest.repository.support.SimpleRelProvider;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class RepositoryAwareResourceMappingFactoryUnitTests {
|
||||
|
||||
ResourceMappingFactory factory = new ResourceMappingFactory(new SimpleRelProvider());
|
||||
|
||||
|
||||
@Test
|
||||
public void foo() {
|
||||
|
||||
|
||||
CollectionResourceMapping mapping = factory.getMappingForType(Person.class);
|
||||
assertThat(mapping.getPath(), is("person"));
|
||||
assertThat(mapping.getRel(), is("person"));
|
||||
assertThat(mapping.getSingleResourceRel(), is("person.person"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void honorsAnnotatedMapping() {
|
||||
|
||||
|
||||
CollectionResourceMapping mapping = factory.getMappingForType(AnnotatedPerson.class);
|
||||
assertThat(mapping.getPath(), is("bar"));
|
||||
assertThat(mapping.getRel(), is("foo"));
|
||||
assertThat(mapping.getSingleResourceRel(), is("foo.foo"));
|
||||
assertThat(mapping.isExported(), is(false));
|
||||
}
|
||||
|
||||
|
||||
static class Person {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@RestResource(path = "bar", rel = "foo", exported = false)
|
||||
static class AnnotatedPerson {
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,67 +24,66 @@ import org.springframework.data.rest.repository.annotation.RestResource;
|
||||
import org.springframework.data.rest.repository.support.SimpleRelProvider;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class ResourceMappingFactoryUnitTests {
|
||||
|
||||
ResourceMappingFactory factory = new ResourceMappingFactory(new SimpleRelProvider());
|
||||
|
||||
|
||||
@Test
|
||||
public void foo() {
|
||||
|
||||
|
||||
CollectionResourceMapping mapping = factory.getMappingForType(Person.class);
|
||||
assertThat(mapping.getPath(), is("person"));
|
||||
assertThat(mapping.getRel(), is("person"));
|
||||
assertThat(mapping.getSingleResourceRel(), is("person.person"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void honorsAnnotatedMapping() {
|
||||
|
||||
|
||||
CollectionResourceMapping mapping = factory.getMappingForType(AnnotatedPerson.class);
|
||||
assertThat(mapping.getPath(), is("bar"));
|
||||
assertThat(mapping.getRel(), is("foo"));
|
||||
assertThat(mapping.getSingleResourceRel(), is("foo.foo"));
|
||||
assertThat(mapping.isExported(), is(false));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void honorsAnnotatedsMapping() {
|
||||
|
||||
|
||||
CollectionResourceMapping mapping = factory.getMappingForType(PersonRepository.class);
|
||||
assertThat(mapping.getPath(), is("bar"));
|
||||
assertThat(mapping.getRel(), is("foo"));
|
||||
assertThat(mapping.getSingleResourceRel(), is("foo.foo"));
|
||||
assertThat(mapping.isExported(), is(false));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void repositoryAnnotationTrumpsDomainTypeMapping() {
|
||||
|
||||
|
||||
CollectionResourceMapping mapping = factory.getMappingForType(AnnotatedAnnotatedPersonRepository.class);
|
||||
assertThat(mapping.getPath(), is("trumpsAll"));
|
||||
assertThat(mapping.getRel(), is("foo"));
|
||||
assertThat(mapping.getSingleResourceRel(), is("foo.foo"));
|
||||
assertThat(mapping.isExported(), is(true));
|
||||
}
|
||||
|
||||
|
||||
static class Person {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@RestResource(path = "bar", rel = "foo", exported = false)
|
||||
static class AnnotatedPerson {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
interface PersonRepository extends Repository<AnnotatedPerson, Long> {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@RestResource(path = "trumpsAll")
|
||||
interface AnnotatedAnnotatedPersonRepository extends Repository<AnnotatedPerson, Long> {
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,14 +46,14 @@ public class ResourceMappingsIntegrationTest {
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
|
||||
Repositories repositories = new Repositories(factory);
|
||||
this.mappings = new ResourceMappings(new RepositoryRestConfiguration(), repositories);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void foo() {
|
||||
|
||||
|
||||
assertThat(mappings, is(Matchers.<ResourceMetadata> iterableWithSize(2)));
|
||||
assertThat(mappings.getMappingFor(Person.class).isExported(), is(true));
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ public class ResourceStringUtilsTest {
|
||||
final boolean hasText;
|
||||
|
||||
public ResourceStringUtilsTest(String testDescription, String actual, String expected, boolean hasText) {
|
||||
|
||||
|
||||
this.actual = actual;
|
||||
this.expected = expected;
|
||||
this.hasText = hasText;
|
||||
|
||||
@@ -58,7 +58,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "deprecation" })
|
||||
class AbstractRepositoryRestController implements MessageSourceAware, InitializingBean {
|
||||
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AbstractRepositoryRestController.class);
|
||||
|
||||
private final PersistentEntityResourceAssembler<Object> perAssembler;
|
||||
@@ -69,8 +69,9 @@ class AbstractRepositoryRestController implements MessageSourceAware, Initializi
|
||||
private MessageSource messageSource;
|
||||
private PagedResourcesAssembler<Object> assembler;
|
||||
|
||||
public AbstractRepositoryRestController(PagedResourcesAssembler<Object> assembler, PersistentEntityResourceAssembler<Object> entityResourceAssembler) {
|
||||
|
||||
public AbstractRepositoryRestController(PagedResourcesAssembler<Object> assembler,
|
||||
PersistentEntityResourceAssembler<Object> entityResourceAssembler) {
|
||||
|
||||
this.assembler = assembler;
|
||||
this.perAssembler = entityResourceAssembler;
|
||||
}
|
||||
@@ -86,13 +87,13 @@ class AbstractRepositoryRestController implements MessageSourceAware, Initializi
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
|
||||
// FIXME:
|
||||
|
||||
// if (null != txMgr) {
|
||||
// txTmpl = new TransactionTemplate(txMgr);
|
||||
// txTmpl.afterPropertiesSet();
|
||||
// }
|
||||
|
||||
// FIXME:
|
||||
|
||||
// if (null != txMgr) {
|
||||
// txTmpl = new TransactionTemplate(txMgr);
|
||||
// txTmpl.afterPropertiesSet();
|
||||
// }
|
||||
}
|
||||
|
||||
@ExceptionHandler({ NullPointerException.class })
|
||||
@@ -139,7 +140,7 @@ class AbstractRepositoryRestController implements MessageSourceAware, Initializi
|
||||
@ResponseBody
|
||||
public ResponseEntity handleRepositoryConstraintViolationException(Locale locale,
|
||||
RepositoryConstraintViolationException rcve) {
|
||||
|
||||
|
||||
return response(null, new RepositoryConstraintViolationExceptionMessage(rcve, messageSource, locale),
|
||||
HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
@@ -205,7 +206,7 @@ class AbstractRepositoryRestController implements MessageSourceAware, Initializi
|
||||
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
protected Resources resultToResources(Object result, Link baseLink) {
|
||||
|
||||
|
||||
if (result instanceof Page) {
|
||||
Page<Object> page = (Page<Object>) result;
|
||||
return entitiesToResources(page, baseLink, assembler);
|
||||
@@ -225,7 +226,6 @@ class AbstractRepositoryRestController implements MessageSourceAware, Initializi
|
||||
return assembler.toResource(page, perAssembler, baseLink);
|
||||
}
|
||||
|
||||
|
||||
protected Resources<Resource<Object>> entitiesToResources(Iterable<Object> entities) {
|
||||
|
||||
List<Resource<Object>> resources = new ArrayList<Resource<Object>>();
|
||||
|
||||
@@ -33,30 +33,28 @@ import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
|
||||
*/
|
||||
public class BaseUriMethodArgumentResolver implements HandlerMethodArgumentResolver {
|
||||
|
||||
private final RepositoryRestConfiguration config;
|
||||
private final RepositoryRestConfiguration config;
|
||||
|
||||
public BaseUriMethodArgumentResolver(RepositoryRestConfiguration config) {
|
||||
this.config = config;
|
||||
}
|
||||
public BaseUriMethodArgumentResolver(RepositoryRestConfiguration config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@Override public boolean supportsParameter(MethodParameter parameter) {
|
||||
return (null != parameter.getParameterAnnotation(BaseURI.class)
|
||||
&& parameter.getParameterType() == URI.class);
|
||||
}
|
||||
@Override
|
||||
public boolean supportsParameter(MethodParameter parameter) {
|
||||
return (null != parameter.getParameterAnnotation(BaseURI.class) && parameter.getParameterType() == URI.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI resolveArgument(MethodParameter parameter,
|
||||
ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest,
|
||||
WebDataBinderFactory binderFactory) throws Exception {
|
||||
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
|
||||
@Override
|
||||
public URI resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
|
||||
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
|
||||
|
||||
// Use configured URI if there is one or set the current one as the default if not.
|
||||
if(null == config.getBaseUri()) {
|
||||
URI baseUri = ServletUriComponentsBuilder.fromServletMapping(servletRequest).build().toUri();
|
||||
config.setBaseUri(baseUri);
|
||||
}
|
||||
// Use configured URI if there is one or set the current one as the default if not.
|
||||
if (null == config.getBaseUri()) {
|
||||
URI baseUri = ServletUriComponentsBuilder.fromServletMapping(servletRequest).build().toUri();
|
||||
config.setBaseUri(baseUri);
|
||||
}
|
||||
|
||||
return config.getBaseUri();
|
||||
}
|
||||
return config.getBaseUri();
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user