DATAREST-93 - Fixed formatting in Spring Data REST.

Added formatter to be used within Eclipse going forward.
This commit is contained in:
Oliver Gierke
2013-06-18 16:16:48 +02:00
parent eec52471d7
commit 5c61632ec2
162 changed files with 3775 additions and 3991 deletions

291
formatter.xml Normal file
View 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>

View File

@@ -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,6 +20,7 @@ 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
@@ -12,82 +28,83 @@ import org.springframework.core.convert.TypeDescriptor;
* {@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>();
public DelegatingConversionService() {
}
private final Stack<ConversionService> conversionServices;
public DelegatingConversionService(ConversionService... svcs) {
addConversionServices(svcs);
}
/**
* 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) {
this.conversionServices = new Stack<ConversionService>();
for (ConversionService svc : svcs) {
Assert.notNull(svc);
conversionServices.add(svc);
}
return this;
}
/**
* 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
/*
* (non-Javadoc)
* @see org.springframework.core.convert.ConversionService#canConvert(java.lang.Class, java.lang.Class)
*/
public DelegatingConversionService addConversionService(int atIndex, ConversionService svc) {
conversionServices.add(atIndex, svc);
return this;
}
@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)) {
for (ConversionService svc : conversionServices) {
if (svc.canConvert(from, to)) {
return true;
}
}
return false;
}
@Override public boolean canConvert(TypeDescriptor from, TypeDescriptor to) {
for(ConversionService svc : conversionServices) {
if(svc.canConvert(from, to)) {
/*
* (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) {
for (ConversionService svc : conversionServices) {
if (svc.canConvert(from, to)) {
return true;
}
}
return false;
}
@Override public <T> T convert(Object o, Class<T> type) {
for(ConversionService svc : conversionServices) {
if(svc.canConvert(o.getClass(), type)) {
/*
* (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));
}
@Override public Object convert(Object o, TypeDescriptor from, TypeDescriptor to) {
for(ConversionService svc : conversionServices) {
if(svc.canConvert(from, to)) {
/*
* (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);
}
}

View File

@@ -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,8 +30,7 @@ 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();
@@ -27,50 +41,70 @@ public class ISO8601DateConverter implements ConditionalGenericConverter,
CONVERTIBLE_PAIRS.add(new ConvertiblePair(Date.class, String.class));
}
@Override public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
if(String.class.isAssignableFrom(sourceType.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 Date.class.isAssignableFrom(targetType.getType());
}
return Date.class.isAssignableFrom(sourceType.getType())
&& String.class.isAssignableFrom(targetType.getType());
return Date.class.isAssignableFrom(sourceType.getType()) && String.class.isAssignableFrom(targetType.getType());
}
@Override public Set<ConvertiblePair> getConvertibleTypes() {
/*
* (non-Javadoc)
* @see org.springframework.core.convert.converter.GenericConverter#getConvertibleTypes()
*/
@Override
public Set<ConvertiblePair> getConvertibleTypes() {
return CONVERTIBLE_PAIRS;
}
@Override public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
/*
* (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) {
DateFormat dateFmt = iso8601DateFormat();
if(String.class.isAssignableFrom(sourceType.getType())) {
if (String.class.isAssignableFrom(sourceType.getType())) {
return dateFmt.format(source);
} else {
}
try {
return dateFmt.parse(source.toString());
} catch(ParseException e) {
} 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;
}
@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")
);
} 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;
}
private DateFormat iso8601DateFormat() {
return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
}
}

View File

@@ -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;
@@ -22,25 +37,38 @@ public class UUIDConverter implements ConditionalGenericConverter {
CONVERTIBLE_PAIRS.add(new ConvertiblePair(UUID.class, String.class));
}
@Override public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
if(String.class.isAssignableFrom(sourceType.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() {
/*
* (non-Javadoc)
* @see org.springframework.core.convert.converter.GenericConverter#getConvertibleTypes()
*/
@Override
public Set<ConvertiblePair> getConvertibleTypes() {
return CONVERTIBLE_PAIRS;
}
@Override public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if(String.class.isAssignableFrom(sourceType.getType())) {
/*
* (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();
}
}
}

View File

@@ -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;

View File

@@ -2,3 +2,4 @@
* Core components used across Spring Data REST.
*/
package org.springframework.data.rest.core;

View File

@@ -1,206 +1,21 @@
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.
*
* @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) {

View File

@@ -2,3 +2,4 @@
* Spring Data REST
*/
package org.springframework.data.rest;

View File

@@ -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,8 +32,8 @@ 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
@@ -43,20 +59,25 @@ public class DelegatingConversionServiceUnitTests {
}
@Test
public void shouldDelegateToProperConversionService() throws Exception {
public void shouldDelegateToProperConversionService() {
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() throws Exception {
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));
}

View File

@@ -1,12 +1,24 @@
/*
* 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;
@@ -23,70 +35,10 @@ public class UriUtilsUnitTests {
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");
URI uri = UriUtils.buildUri(BASE_URI, "person", "1");
assertThat(uri, is(PERSON_2LVL_URI));
}
}

View File

@@ -55,8 +55,7 @@ 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.");
@@ -76,9 +75,7 @@ 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) {
@@ -99,9 +96,7 @@ 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) {
@@ -122,9 +117,7 @@ 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) {
@@ -146,9 +139,8 @@ 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) {
@@ -169,9 +161,7 @@ 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) {
@@ -192,9 +182,7 @@ 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) {
@@ -214,9 +202,7 @@ 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) {
@@ -237,7 +223,6 @@ public class RepositoryRestConfiguration {
* Sets whether to return a response body after updating an entity.
*
* @param returnBodyOnUpdate
*
* @return
*/
public RepositoryRestConfiguration setReturnBodyOnUpdate(boolean returnBodyOnUpdate) {
@@ -248,9 +233,7 @@ 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) {
@@ -260,9 +243,7 @@ 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) {
@@ -272,9 +253,7 @@ 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) {
@@ -293,9 +272,7 @@ 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) {
@@ -305,9 +282,7 @@ 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) {
@@ -318,7 +293,6 @@ 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);
@@ -336,9 +310,7 @@ 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) {
@@ -348,9 +320,7 @@ 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) {

View File

@@ -31,8 +31,7 @@ public class ResourceMapping {
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);
@@ -79,7 +78,7 @@ public class ResourceMapping {
}
public ResourceMapping addResourceMappings(Map<String, ResourceMapping> mappings) {
if(null == mappings) {
if (null == mappings) {
return this;
}
@@ -106,21 +105,18 @@ public class ResourceMapping {
}
public String getNameForPath(String path) {
for(Map.Entry<String, ResourceMapping> mapping : resourceMappings.entrySet()) {
if(mapping.getValue().getPath().equals(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 + '}';
}
}

View File

@@ -31,7 +31,7 @@ public class ResourceMappingConfiguration {
public ResourceMapping setResourceMappingFor(Class<?> type) {
ResourceMapping rm = resourceMappings.get(type);
if(null == rm) {
if (null == rm) {
rm = new ResourceMapping(type);
resourceMappings.put(type, rm);
}
@@ -47,11 +47,11 @@ public class ResourceMappingConfiguration {
}
public Class<?> findTypeForPath(String path) {
if(null == path) {
if (null == path) {
return null;
}
for(Map.Entry<Class<?>, ResourceMapping> entry : resourceMappings.entrySet()) {
if(path.equals(entry.getValue().getPath())) {
for (Map.Entry<Class<?>, ResourceMapping> entry : resourceMappings.entrySet()) {
if (path.equals(entry.getValue().getPath())) {
return entry.getKey();
}
}

View File

@@ -18,52 +18,45 @@ import org.springframework.data.rest.repository.support.RepositoryInformationSup
*
* @author Jon Brisbin
*/
public class UriDomainClassConverter
extends RepositoryInformationSupport
implements ConditionalGenericConverter,
public class UriDomainClassConverter extends RepositoryInformationSupport implements ConditionalGenericConverter,
InitializingBean {
private static TypeDescriptor STRING_TYPE = TypeDescriptor.valueOf(String.class);
@Autowired
private DomainClassConverter<?> domainClassConverter;
@Autowired private DomainClassConverter<?> domainClassConverter;
private Set<ConvertiblePair> convertiblePairs = new HashSet<ConvertiblePair>();
@Override public void afterPropertiesSet() throws Exception {
for(Class<?> domainType : repositories) {
@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) {
@Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
return URI.class.isAssignableFrom(sourceType.getType())
&& (null != repositories.getPersistentEntity(targetType.getType()));
}
@Override public Set<ConvertiblePair> getConvertibleTypes() {
@Override
public Set<ConvertiblePair> getConvertibleTypes() {
return convertiblePairs;
}
@Override public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
@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())
);
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;
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.")
);
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);

View File

@@ -35,48 +35,50 @@ public class ValidationErrors extends AbstractErrors {
this.persistentEntity = persistentEntity;
}
@Override public String getObjectName() {
@Override
public String getObjectName() {
return name;
}
@Override public void reject(String errorCode, Object[] errorArgs, String defaultMessage) {
globalErrors.add(new ObjectError(name, 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 rejectValue(String field, String errorCode, Object[] errorArgs, String defaultMessage) {
fieldErrors.add(new FieldError(name,
field,
getFieldValue(field),
true,
new String[]{errorCode},
errorArgs,
@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 addAllErrors(Errors errors) {
@Override
public void addAllErrors(Errors errors) {
globalErrors.addAll(errors.getAllErrors());
}
@Override public List<ObjectError> getGlobalErrors() {
@Override
public List<ObjectError> getGlobalErrors() {
return globalErrors;
}
@Override public List<FieldError> getFieldErrors() {
@Override
public List<FieldError> getFieldErrors() {
return fieldErrors;
}
@Override public Object getFieldValue(String field) {
@Override
public Object getFieldValue(String field) {
PersistentProperty<?> prop = persistentEntity != null ? persistentEntity.getPersistentProperty(field) : null;
if(null == prop) {
if (null == prop) {
return null;
}
Method getter = prop.getGetter();
if(null != getter) {
if (null != getter) {
return invokeMethod(getter, entity);
}
Field fld = prop.getField();
if(null != fld) {
if (null != fld) {
return getField(fld, entity);
}

View File

@@ -11,7 +11,7 @@ import org.springframework.core.convert.converter.Converter;
/**
* @author Jon Brisbin
*/
@Target({ElementType.PARAMETER})
@Target({ ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface ConvertWith {

View File

@@ -8,11 +8,7 @@ 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();

View File

@@ -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 {

View File

@@ -11,10 +11,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 HandleAfterDelete {

View File

@@ -11,10 +11,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 HandleAfterLinkDelete {

View File

@@ -11,10 +11,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 HandleAfterLinkSave {

View File

@@ -11,10 +11,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 HandleAfterSave {

View File

@@ -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 {

View File

@@ -11,10 +11,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 HandleBeforeDelete {

View File

@@ -11,10 +11,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 HandleBeforeLinkDelete {

View File

@@ -11,10 +11,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 HandleBeforeLinkSave {

View File

@@ -11,10 +11,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 HandleBeforeSave {

View File

@@ -11,7 +11,7 @@ import java.lang.annotation.Target;
*
* @author Jon Brisbin <jbrisbin@vmware.com>
*/
@Target({ElementType.TYPE})
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface RepositoryEventHandler {

View File

@@ -12,11 +12,7 @@ import java.lang.annotation.Target;
*
* @author Jon Brisbin
*/
@Target({
ElementType.FIELD,
ElementType.METHOD,
ElementType.TYPE
})
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface RestResource {

View File

@@ -8,8 +8,8 @@ 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
*/
@@ -19,136 +19,114 @@ public abstract class AbstractRepositoryEventListener<T> implements ApplicationL
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) {}
}

View File

@@ -31,69 +31,68 @@ 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 {
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);
@@ -105,52 +104,46 @@ public class AnnotatedHandlerBeanPostProcessor implements ApplicationListener<Re
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("$"));
}, 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,
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);
}
}
@@ -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 + '}';
}
}

View File

@@ -19,6 +19,6 @@ public class ExceptionEvent extends RepositoryEvent {
* @return The {@link Throwable} that is the source of this exception event.
*/
public Throwable getException() {
return (Throwable)getSource();
return (Throwable) getSource();
}
}

View File

@@ -23,26 +23,27 @@ public class PersistentEntityResourceProcessor implements ResourceProcessor<Pers
@Autowired
public PersistentEntityResourceProcessor(Repositories repositories,
List<ResourceProcessor<Resource<?>>> resourceProcessors) {
if(null != resourceProcessors) {
for(ResourceProcessor<Resource<?>> rp : 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())) {
if (null != repositories.getPersistentEntity(domainType.getType())) {
this.resourceProcessors.add(new DomainTypeResourceProcessor(domainType.getType(), rp));
}
}
}
}
@Override public PersistentEntityResource<?> process(PersistentEntityResource<?> resource) {
@Override
public PersistentEntityResource<?> process(PersistentEntityResource<?> resource) {
Object content = resource.getContent();
if(null == content) {
if (null == content) {
return resource;
}
Class<?> domainType = content.getClass();
for(DomainTypeResourceProcessor rp : resourceProcessors) {
if(isAssignable(domainType, rp.domainType)) {
for (DomainTypeResourceProcessor rp : resourceProcessors) {
if (isAssignable(domainType, rp.domainType)) {
rp.resourceProcessor.process(resource);
}
}

View File

@@ -39,50 +39,41 @@ import org.springframework.validation.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);
}
}
@@ -101,13 +92,11 @@ 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;
@@ -116,11 +105,8 @@ 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);
}
}

View File

@@ -3,47 +3,38 @@ 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.
*
* @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)) {
if ("count".equals(s)) {
return COUNT;
} else if("delete".equals(s)) {
} else if ("delete".equals(s)) {
return (some ? DELETE_SOME : DELETE_ONE);
} else if("deleteAll".equals(s)) {
} else if ("deleteAll".equals(s)) {
return DELETE_ALL;
} else if("findAll".equals(s)) {
} else if ("findAll".equals(s)) {
return (some ? FIND_SOME : FIND_ALL);
} else if("findOne".equals(s)) {
} else if ("findOne".equals(s)) {
return FIND_ONE;
} else if("save".equals(s)) {
} else if ("save".equals(s)) {
return (some ? SAVE_SOME : SAVE_ONE);
} else {
return null;
@@ -56,7 +47,7 @@ public enum CrudMethod {
* @return The method name as a string.
*/
public String toMethodName() {
switch(this) {
switch (this) {
case COUNT:
return "count";
case DELETE_ALL:

View File

@@ -9,8 +9,8 @@ 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
*/
@@ -28,28 +28,27 @@ public class MethodParameterConversionService {
}
public boolean canConvert(TypeDescriptor sourceType, MethodParameter param) {
return (delegateConversionService.canConvert(sourceType, new TypeDescriptor(param))
|| param.hasParameterAnnotation(ConvertWith.class));
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);
}
@SuppressWarnings({"unchecked"})
@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()
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);
return (T) delegateConversionService.convert(source, sourceType, targetType);
}
} catch(Exception e) {
} catch (Exception e) {
throw new ConversionFailedException(sourceType, targetType, source, e);
}
}

View File

@@ -30,32 +30,32 @@ public class RepositoryMethod {
Class<?>[] paramTypes = method.getParameterTypes();
String[] paramNames = Methods.NAME_DISCOVERER.getParameterNames(method);
if(null == paramNames) {
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;
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]) {
if (null == paramNames[i]) {
paramNames[i] = "arg" + i;
}
}
int idx = 0;
for(Class<?> type : paramTypes) {
if(Pageable.class.isAssignableFrom(type)) {
for (Class<?> type : paramTypes) {
if (Pageable.class.isAssignableFrom(type)) {
pageable = true;
}
if(Sort.class.isAssignableFrom(type)) {
if (Sort.class.isAssignableFrom(type)) {
sortable = true;
}
methodParameters.add(new MethodParameter(method, idx));

View File

@@ -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);
@@ -242,33 +254,29 @@ public class RepositoryMethodInvoker implements PagingAndSortingRepository<Objec
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;
}

View File

@@ -16,10 +16,8 @@ import org.springframework.hateoas.Link;
*/
public class RepositoryMethodResponse {
@JsonProperty("results")
private List<Object> results = new ArrayList<Object>();
@JsonProperty("links")
private List<Link> links = new ArrayList<Link>();
@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;
@@ -35,11 +33,11 @@ public class RepositoryMethodResponse {
}
public RepositoryMethodResponse addAllResults(Iterator<?> results) {
if(null == results) {
if (null == results) {
return this;
}
while(results.hasNext()) {
while (results.hasNext()) {
addResult(results.next());
}
@@ -55,7 +53,7 @@ public class RepositoryMethodResponse {
}
public RepositoryMethodResponse setResults(List<Object> results) {
if(null == results) {
if (null == results) {
this.results = Collections.emptyList();
} else {
this.results = results;
@@ -68,7 +66,7 @@ public class RepositoryMethodResponse {
}
public RepositoryMethodResponse setLinks(List<Link> links) {
if(null == links) {
if (null == links) {
this.links = Collections.emptyList();
} else {
this.links = links;

View File

@@ -23,31 +23,29 @@ public class RepositoryQueryMethod {
this.method = method;
paramTypes = method.getParameterTypes();
paramNames = new String[paramTypes.length];
if(null == paramNames) {
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 (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;
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])) {
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()));
}
}

View File

@@ -17,7 +17,6 @@ package org.springframework.data.rest.repository.mapping;
import org.springframework.util.Assert;
class CollectionResourceMappingBuilder implements InternalMappingBuilder {
private final CollectionResourceMapping mapping;
@@ -32,8 +31,8 @@ class CollectionResourceMappingBuilder implements InternalMappingBuilder {
*/
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);
}

View File

@@ -70,7 +70,8 @@ public class ResourceMappingFactory {
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);
}

View File

@@ -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());
}
/**

View File

@@ -18,7 +18,6 @@ package org.springframework.data.rest.repository.mapping;
import org.springframework.data.mapping.PersistentProperty;
/**
*
* @author Oliver Gierke
*/
public interface ResourceMetadata extends CollectionResourceMapping, ResourceMetadataProvider {

View File

@@ -18,7 +18,6 @@ package org.springframework.data.rest.repository.mapping;
import org.springframework.data.mapping.PersistentProperty;
/**
*
* @author Oliver Gierke
*/
public interface ResourceMetadataProvider {

View File

@@ -15,7 +15,6 @@
*/
package org.springframework.data.rest.repository.mapping;
public class SimpleCollectionResourceMapping implements CollectionResourceMapping {
private final String collectionRel;

View File

@@ -19,15 +19,14 @@ public class DomainObjectMerger {
private final ConversionService conversionService;
@Autowired
public DomainObjectMerger(Repositories repositories,
ConversionService conversionService) {
public DomainObjectMerger(Repositories repositories, ConversionService conversionService) {
this.repositories = repositories;
this.conversionService = conversionService;
}
@SuppressWarnings({"unchecked", "rawtypes"})
@SuppressWarnings({ "unchecked", "rawtypes" })
public void merge(Object from, Object target) {
if(null == from || null == target) {
if (null == from || null == target) {
return;
}
final BeanWrapper<?, Object> fromWrapper = BeanWrapper.create(from, conversionService);
@@ -35,23 +34,24 @@ public class DomainObjectMerger {
PersistentEntity<?, ?> entity = repositories.getPersistentEntity(target.getClass());
entity.doWithProperties(new PropertyHandler() {
@Override public void doWithPersistentProperty(PersistentProperty persistentProperty) {
@Override
public void doWithPersistentProperty(PersistentProperty persistentProperty) {
Object fromVal = fromWrapper.getProperty(persistentProperty);
if(null != fromVal && !fromVal.equals(targetWrapper.getProperty(persistentProperty))) {
if (null != fromVal && !fromVal.equals(targetWrapper.getProperty(persistentProperty))) {
targetWrapper.setProperty(persistentProperty, fromVal);
}
}
});
entity.doWithAssociations(new AssociationHandler() {
@Override public void doWithAssociation(Association association) {
@Override
public void doWithAssociation(Association association) {
PersistentProperty persistentProperty = association.getInverse();
Object fromVal = fromWrapper.getProperty(persistentProperty);
if(null != fromVal && !fromVal.equals(targetWrapper.getProperty(persistentProperty))) {
if (null != fromVal && !fromVal.equals(targetWrapper.getProperty(persistentProperty))) {
targetWrapper.setProperty(persistentProperty, fromVal);
}
}
});
}
}

View File

@@ -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 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 LocalVariableTableParameterNameDiscoverer NAME_DISCOVERER = new LocalVariableTableParameterNameDiscoverer();
}

View File

@@ -23,7 +23,6 @@ import org.springframework.data.repository.core.support.AnnotationRepositoryMeta
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
/**
*
* @author Oliver Gierke
*/
public class RepositoriesUtils {

View File

@@ -33,10 +33,11 @@ public abstract class RepositoryInformationSupport {
@Autowired
public void setRepositories(Repositories repositories) {
this.repositories = repositories;
for(Class<?> domainType : 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 {
@Override
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
repositoryMethods.add(repoInfo.getRepositoryInterface(), new RepositoryMethod(method));
}
});
@@ -53,13 +54,13 @@ public abstract class RepositoryInformationSupport {
}
protected RepositoryInformation findRepositoryInfoFor(String pathSegment) {
if(!hasText(pathSegment)) {
if (!hasText(pathSegment)) {
return null;
}
for(Class<?> domainType : repositories) {
for (Class<?> domainType : repositories) {
RepositoryInformation repoInfo = findRepositoryInfoFor(domainType);
ResourceMapping mapping = getResourceMapping(config, repoInfo);
if(pathSegment.equals(mapping.getPath()) && mapping.isExported()) {
if (pathSegment.equals(mapping.getPath()) && mapping.isExported()) {
return repoInfo;
}
}
@@ -68,7 +69,7 @@ public abstract class RepositoryInformationSupport {
protected RepositoryInformation findRepositoryInfoFor(Class<?> domainType) {
PersistentEntity<?, ?> entity = repositories.getPersistentEntity(domainType);
if(null != entity) {
if (null != entity) {
return repositories.getRepositoryInformationFor(domainType);
}
return null;

View File

@@ -19,7 +19,6 @@ import org.springframework.data.rest.repository.mapping.ResourceMappings;
import org.springframework.hateoas.RelProvider;
/**
*
* @author Oliver Gierke
*/
public class RepositoryRelProvider implements RelProvider {

View File

@@ -19,7 +19,6 @@ import org.springframework.hateoas.RelProvider;
import org.springframework.util.StringUtils;
/**
*
* @author Oliver Gierke
*/
public class SimpleRelProvider implements RelProvider {

View File

@@ -68,8 +68,7 @@ public class ResourceMappingUnitTests {
org.springframework.data.rest.config.ResourceMapping mapping = new org.springframework.data.rest.config.ResourceMapping(
findRel(AnnotatedWithLeadingSlashPersonRepository.class),
findPath(AnnotatedWithLeadingSlashPersonRepository.class),
findExported(AnnotatedWithLeadingSlashPersonRepository.class)
);
findExported(AnnotatedWithLeadingSlashPersonRepository.class));
// The rel attribute defaults to class name
assertThat(mapping.getRel(), is("annotatedWithLeadingSlashPerson"));
@@ -80,12 +79,10 @@ public class ResourceMappingUnitTests {
@Test
public void shouldDetectPathAndRemoveLeadingSlashIfAnyOnMethod() throws Exception {
Method method = AnnotatedWithLeadingSlashPersonRepository.class.getMethod("findByFirstName", String.class, Pageable.class);
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)
);
findRel(method), findPath(method), findExported(method));
// The rel attribute defaults to class name
assertThat(mapping.getRel(), is("findByFirstName"));
@@ -96,12 +93,10 @@ public class ResourceMappingUnitTests {
@Test
public void shouldReturnDefaultIfPathContainsOnlySlashTextOnMethod() throws Exception {
Method method = AnnotatedWithLeadingSlashPersonRepository.class.getMethod("findByLastName", String.class, Pageable.class);
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)
);
findRel(method), findPath(method), findExported(method));
// The rel defaults to method name
assertThat(mapping.getRel(), is("findByLastName"));

View File

@@ -22,8 +22,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@SuppressWarnings("deprecation")
public class RepositoryRestConfigurationIntegrationTests {
@Autowired
RepositoryRestConfiguration config;
@Autowired RepositoryRestConfiguration config;
@Test
public void shouldProvideResourceMappingForConfiguredRepository() throws Exception {

View File

@@ -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() {
@Bean
public Repositories repositories() {
return new Repositories(appCtx);
}
@SuppressWarnings("deprecation")
@Bean public RepositoryRestConfiguration config() {
@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")
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;
}
@Bean public DefaultFormattingConversionService defaultConversionService() {
@Bean
public DefaultFormattingConversionService defaultConversionService() {
return new DefaultFormattingConversionService();
}
@Bean public DomainClassConverter<?> domainClassConverter() {
@Bean
public DomainClassConverter<?> domainClassConverter() {
return new DomainClassConverter<DefaultFormattingConversionService>(defaultConversionService());
}
@Bean public UriDomainClassConverter uriDomainClassConverter() {
@Bean
public UriDomainClassConverter uriDomainClassConverter() {
return new UriDomainClassConverter();
}
}

View File

@@ -19,10 +19,8 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@ContextConfiguration(classes = RepositoryEventTestsConfig.class)
public class RepositoryEventIntegrationTests {
@Autowired
ApplicationContext appCtx;
@Autowired
PersonRepository people;
@Autowired ApplicationContext appCtx;
@Autowired PersonRepository people;
Person person;
@Before

View File

@@ -11,18 +11,21 @@ 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() {
@Bean
public PersonBeforeSaveHandler personBeforeSaveHandler() {
return new PersonBeforeSaveHandler();
}
@Bean public AnnotatedPersonEventHandler beforeSaveHandler() {
@Bean
public AnnotatedPersonEventHandler beforeSaveHandler() {
return new AnnotatedPersonEventHandler();
}
@Bean public AnnotatedHandlerBeanPostProcessor annotatedHandlerBeanPostProcessor() {
@Bean
public AnnotatedHandlerBeanPostProcessor annotatedHandlerBeanPostProcessor() {
return new AnnotatedHandlerBeanPostProcessor();
}

View File

@@ -18,8 +18,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@ContextConfiguration(classes = ValidatorTestsConfig.class)
public class ValidatorIntegrationTests {
@Autowired
ApplicationContext appCtx;
@Autowired ApplicationContext appCtx;
@Test(expected = RepositoryConstraintViolationException.class)
public void shouldValidateLastName() throws Exception {

View File

@@ -9,10 +9,11 @@ import org.springframework.data.rest.repository.RepositoryTestsConfig;
* @author Jon Brisbin
*/
@Configuration
@Import({RepositoryTestsConfig.class})
@Import({ RepositoryTestsConfig.class })
public class ValidatorTestsConfig {
@Bean public ValidatingRepositoryEventListener validatingListener() {
@Bean
public ValidatingRepositoryEventListener validatingListener() {
return new ValidatingRepositoryEventListener();
}

View File

@@ -11,5 +11,4 @@ import org.springframework.data.rest.repository.annotation.RestResource;
*/
@RestResource(rel = "people", exported = false)
@NoRepositoryBean
public interface AnnotatedPersonRepository extends CrudRepository<Person, Long> {
}
public interface AnnotatedPersonRepository extends CrudRepository<Person, Long> {}

View File

@@ -9,5 +9,4 @@ import org.springframework.data.repository.NoRepositoryBean;
* @author Jon Brisbin
*/
@NoRepositoryBean
public interface ConfiguredPersonRepository extends CrudRepository<Person, Long> {
}
public interface ConfiguredPersonRepository extends CrudRepository<Person, Long> {}

View File

@@ -45,18 +45,21 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
@EnableTransactionManagement
public class JpaRepositoryConfig {
@Bean public MessageSource messageSource() {
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource ms = new ResourceBundleMessageSource();
ms.setBasename("org.springframework.data.rest.repository.ValidationErrors");
return ms;
}
@Bean public DataSource dataSource() {
@Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
return builder.setType(EmbeddedDatabaseType.HSQL).build();
}
@Bean public EntityManagerFactory entityManagerFactory() {
@Bean
public EntityManagerFactory entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setDatabase(Database.HSQL);
vendorAdapter.setGenerateDdl(true);
@@ -71,11 +74,13 @@ public class JpaRepositoryConfig {
return factory.getObject();
}
@Bean public JpaDialect jpaDialect() {
@Bean
public JpaDialect jpaDialect() {
return new HibernateJpaDialect();
}
@Bean public PlatformTransactionManager transactionManager() {
@Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory());
return txManager;

View File

@@ -22,12 +22,10 @@ public class Person {
@Id @GeneratedValue private Long id;
private String firstName;
private String lastName;
@OneToMany
private List<Person> siblings = Collections.emptyList();
@OneToMany private List<Person> siblings = Collections.emptyList();
private Date created;
public Person() {
}
public Person() {}
public Person(String firstName, String lastName) {
this.firstName = firstName;
@@ -55,7 +53,7 @@ public class Person {
}
public Person addSibling(Person p) {
if(siblings == Collections.EMPTY_LIST) {
if (siblings == Collections.EMPTY_LIST) {
siblings = new ArrayList<Person>();
}
siblings.add(p);

View File

@@ -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) {
@Override
protected void onBeforeSave(Person person) {
throw new RuntimeException();
}
}

View File

@@ -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 {
@Override
public void afterPropertiesSet() throws Exception {
people.save(new Person("John", "Doe"));
}
}

View File

@@ -17,13 +17,15 @@ import org.springframework.validation.Validator;
@HandleBeforeSave
public class PersonNameValidator implements Validator {
@Override public boolean supports(Class<?> clazz) {
@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())) {
@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");
}
}

View File

@@ -25,10 +25,7 @@ public interface PersonRepository extends PagingAndSortingRepository<Person, Lon
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,
public Page<Person> findByCreatedUsingISO8601Date(@Param("date") @ConvertWith(ISO8601DateConverter.class) Date date,
Pageable pageable);
}

View File

@@ -9,5 +9,4 @@ import org.springframework.data.repository.NoRepositoryBean;
* @author Jon Brisbin
*/
@NoRepositoryBean
public interface PlainPersonRepository extends CrudRepository<Person, Long> {
}
public interface PlainPersonRepository extends CrudRepository<Person, Long> {}

View File

@@ -15,15 +15,17 @@ 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 {
@Bean
public MongoDbFactory mongoDbFactory() throws UnknownHostException {
return new SimpleMongoDbFactory(new Mongo("localhost"), "spring-data-rest");
}
@Bean public MongoTemplate mongoTemplate() throws UnknownHostException {
@Bean
public MongoTemplate mongoTemplate() throws UnknownHostException {
return new MongoTemplate(mongoDbFactory());
}

View File

@@ -13,8 +13,7 @@ public class Profile {
private String name;
private String type;
public Profile() {
}
public Profile() {}
public Profile(String id, String name, String type) {
this.id = id;

View File

@@ -10,10 +10,10 @@ 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 {
@Override
public void afterPropertiesSet() throws Exception {
profiles.save(new Profile("jdoe", "jdoe", "account"));
}

View File

@@ -8,5 +8,4 @@ import org.springframework.data.repository.CrudRepository;
*
* @author Jon Brisbin
*/
public interface ProfileRepository extends CrudRepository<Profile, ObjectId> {
}
public interface ProfileRepository extends CrudRepository<Profile, ObjectId> {}

View File

@@ -22,13 +22,13 @@ 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 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) {
} catch (ParseException e) {
throw new IllegalStateException(e);
}
}
@@ -39,14 +39,12 @@ public class MethodParameterConversionServiceUnitTests {
@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);
Date.class, Pageable.class), 0);
findByCreatedUsingISO8601Date = new MethodParameter(PersonRepository.class.getMethod(
"findByCreatedUsingISO8601Date", Date.class, Pageable.class), 0);
}
@SuppressWarnings({"deprecation"})
@SuppressWarnings({ "deprecation" })
@Test
public void shouldConvertDateParameterUsingDefaultConverter() throws Exception {
ConfigurableConversionService cs = new DefaultFormattingConversionService();
@@ -54,7 +52,7 @@ public class MethodParameterConversionServiceUnitTests {
String dateStr = "01/01/2010";
assertThat(conversionService.canConvert(String.class, findByCreatedGreaterThan), is(true));
assertThat((Date)conversionService.convert(dateStr, findByCreatedGreaterThan), is(new Date(dateStr)));
assertThat((Date) conversionService.convert(dateStr, findByCreatedGreaterThan), is(new Date(dateStr)));
}
@Test
@@ -64,7 +62,7 @@ public class MethodParameterConversionServiceUnitTests {
MethodParameterConversionService conversionService = new MethodParameterConversionService(cs);
assertThat(conversionService.canConvert(String.class, findByCreatedUsingISO8601Date), is(true));
assertThat((Date)conversionService.convert(DATE_S, findByCreatedUsingISO8601Date), is(DATE_D));
assertThat((Date) conversionService.convert(DATE_S, findByCreatedUsingISO8601Date), is(DATE_D));
}
}

View File

@@ -27,16 +27,14 @@ public class RepositoryMethodUnitTests {
@Before
public void setup() {
doWithMethods(PersonRepository.class,
new ReflectionUtils.MethodCallback() {
@Override public void doWith(Method method) throws IllegalArgumentException,
IllegalAccessException {
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);
}, Methods.USER_METHODS);
method = methods.get("findByFirstName");
}

View File

@@ -23,7 +23,6 @@ import org.springframework.data.rest.repository.annotation.RestResource;
import org.springframework.data.rest.repository.support.SimpleRelProvider;
/**
*
* @author Oliver Gierke
*/
public class RepositoryAwareResourceMappingFactoryUnitTests {

View File

@@ -24,7 +24,6 @@ import org.springframework.data.rest.repository.annotation.RestResource;
import org.springframework.data.rest.repository.support.SimpleRelProvider;
/**
*
* @author Oliver Gierke
*/
public class ResourceMappingFactoryUnitTests {

View File

@@ -69,7 +69,8 @@ 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;
@@ -89,10 +90,10 @@ class AbstractRepositoryRestController implements MessageSourceAware, Initializi
// FIXME:
// if (null != txMgr) {
// txTmpl = new TransactionTemplate(txMgr);
// txTmpl.afterPropertiesSet();
// }
// if (null != txMgr) {
// txTmpl = new TransactionTemplate(txMgr);
// txTmpl.afterPropertiesSet();
// }
}
@ExceptionHandler({ NullPointerException.class })
@@ -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>>();

View File

@@ -39,20 +39,18 @@ public class BaseUriMethodArgumentResolver implements HandlerMethodArgumentResol
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 {
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()) {
if (null == config.getBaseUri()) {
URI baseUri = ServletUriComponentsBuilder.fromServletMapping(servletRequest).build().toUri();
config.setBaseUri(baseUri);
}

View File

@@ -25,7 +25,6 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
/**
*
* @author Oliver Gierke
*/
public class ControllerUtils {

View File

@@ -25,7 +25,6 @@ import org.springframework.hateoas.ResourceAssembler;
import org.springframework.util.Assert;
/**
*
* @author Oliver Gierke
*/
public class PersistentEntityResourceAssembler<T> implements ResourceAssembler<T, PersistentEntityResource<T>> {

View File

@@ -18,33 +18,30 @@ import org.springframework.web.method.support.ModelAndViewContainer;
*/
public class PersistentEntityResourceHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Autowired
private RepositoryRestRequestHandlerMethodArgumentResolver repoRequestResolver;
@Autowired private RepositoryRestRequestHandlerMethodArgumentResolver repoRequestResolver;
private final List<HttpMessageConverter<?>> messageConverters;
public PersistentEntityResourceHandlerMethodArgumentResolver(List<HttpMessageConverter<?>> messageConverters) {
this.messageConverters = messageConverters;
}
@Override public boolean supportsParameter(MethodParameter parameter) {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return PersistentEntityResource.class.isAssignableFrom(parameter.getParameterType());
}
@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public Object resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
RepositoryRestRequest repoRequest = (RepositoryRestRequest)repoRequestResolver.resolveArgument(parameter,
mavContainer,
webRequest,
binderFactory);
@SuppressWarnings({ "unchecked", "rawtypes" })
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
RepositoryRestRequest repoRequest = (RepositoryRestRequest) repoRequestResolver.resolveArgument(parameter,
mavContainer, webRequest, binderFactory);
final ServletServerHttpRequest request = new ServletServerHttpRequest(webRequest.getNativeRequest(HttpServletRequest.class));
for(HttpMessageConverter converter : messageConverters) {
final ServletServerHttpRequest request = new ServletServerHttpRequest(
webRequest.getNativeRequest(HttpServletRequest.class));
for (HttpMessageConverter converter : messageConverters) {
Class<?> domainType = repoRequest.getPersistentEntity().getType();
if(!converter.canRead(domainType, request.getHeaders().getContentType())) {
if (!converter.canRead(domainType, request.getHeaders().getContentType())) {
continue;
}

View File

@@ -71,8 +71,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
*/
@RestController
@SuppressWarnings("deprecation")
class RepositoryEntityController extends AbstractRepositoryRestController implements
ApplicationEventPublisherAware {
class RepositoryEntityController extends AbstractRepositoryRestController implements ApplicationEventPublisherAware {
private static final String BASE_MAPPING = "/{repository}";
@@ -203,7 +202,7 @@ class RepositoryEntityController extends AbstractRepositoryRestController implem
}
/**
* {@code GET /{repository}/{id}}
* {@code GET / repository}/{id}}
*
* @param repoRequest
* @param id
@@ -231,7 +230,7 @@ class RepositoryEntityController extends AbstractRepositoryRestController implem
}
/**
* {@code PUT /{repository}/{id}} - Updates an existing entity or creates one at exactly that place.
* {@code PUT / repository}/{id}} - Updates an existing entity or creates one at exactly that place.
*
* @param repoRequest
* @param incoming

View File

@@ -41,21 +41,19 @@ public class RepositoryInformationHandlerMethodArgumentResolver extends Reposito
}
@Override
public RepositoryInformation resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
public RepositoryInformation resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
String requestUri = new UrlPathHelper().getLookupPathForRequest(request);
if(requestUri.startsWith("/")) {
if (requestUri.startsWith("/")) {
requestUri = requestUri.substring(1);
}
String[] parts = requestUri.split("/");
if(parts.length == 0) {
if (parts.length == 0) {
// Root request
return null;
}

View File

@@ -62,8 +62,9 @@ import org.springframework.web.bind.annotation.ResponseBody;
* @author Oliver Gierke
*/
@RestController
@SuppressWarnings({"unchecked", "deprecation"})
public class RepositoryPropertyReferenceController extends AbstractRepositoryRestController implements ApplicationEventPublisherAware {
@SuppressWarnings({ "unchecked", "deprecation" })
public class RepositoryPropertyReferenceController extends AbstractRepositoryRestController implements
ApplicationEventPublisherAware {
private static final String BASE_MAPPING = "/{repository}/{id}/{property}";
@@ -96,42 +97,35 @@ public class RepositoryPropertyReferenceController extends AbstractRepositoryRes
this.publisher = applicationEventPublisher;
}
@RequestMapping(
value = BASE_MAPPING,
method = RequestMethod.GET,
produces = {
"application/json",
"application/x-spring-data-verbose+json"
}
)
@RequestMapping(value = BASE_MAPPING, method = RequestMethod.GET, produces = { "application/json",
"application/x-spring-data-verbose+json" })
@ResponseBody
public ResponseEntity<Resource<?>> followPropertyReference(final RepositoryRestRequest repoRequest,
@PathVariable String id,
@PathVariable String property)
throws ResourceNotFoundException, NoSuchMethodException {
@PathVariable String id, @PathVariable String property) throws ResourceNotFoundException, NoSuchMethodException {
final HttpHeaders headers = new HttpHeaders();
Function<ReferencedProperty, Resource<?>> handler = new Function<ReferencedProperty, Resource<?>>() {
@Override public Resource<?> apply(ReferencedProperty prop) {
@Override
public Resource<?> apply(ReferencedProperty prop) {
if(null == prop.propertyValue) {
if (null == prop.propertyValue) {
throw new ResourceNotFoundException();
}
if(prop.property.isCollectionLike()) {
if (prop.property.isCollectionLike()) {
List<Resource<?>> resources = new ArrayList<Resource<?>>();
for(Object obj : ((Iterable<Object>) prop.propertyValue)) {
for (Object obj : ((Iterable<Object>) prop.propertyValue)) {
resources.add(perAssembler.toResource(obj));
}
return new Resource<Object>(resources);
} else if(prop.property.isMap()) {
} else if (prop.property.isMap()) {
Map<Object, Resource<?>> resources = new HashMap<Object, Resource<?>>();
for(Map.Entry<Object, Object> entry : ((Map<Object, Object>) prop.propertyValue).entrySet()) {
for (Map.Entry<Object, Object> entry : ((Map<Object, Object>) prop.propertyValue).entrySet()) {
resources.put(entry.getKey(), perAssembler.toResource(entry.getValue()));
}
@@ -145,35 +139,29 @@ public class RepositoryPropertyReferenceController extends AbstractRepositoryRes
}
}
};
Resource<?> responseResource = doWithReferencedProperty(repoRequest,
id,
property,
handler);
Resource<?> responseResource = doWithReferencedProperty(repoRequest, id, property, handler);
return ControllerUtils.toResponseEntity(headers, responseResource, HttpStatus.OK);
}
@RequestMapping(
value = BASE_MAPPING,
method = RequestMethod.DELETE
)
@RequestMapping(value = BASE_MAPPING, method = RequestMethod.DELETE)
@ResponseBody
public ResponseEntity<Resource<?>> deletePropertyReference(final RepositoryRestRequest repoRequest,
@PathVariable String id,
@PathVariable String property)
throws ResourceNotFoundException, NoSuchMethodException, HttpRequestMethodNotSupportedException {
@PathVariable String id, @PathVariable String property) throws ResourceNotFoundException, NoSuchMethodException,
HttpRequestMethodNotSupportedException {
final RepositoryMethodInvoker repoMethodInvoker = repoRequest.getRepositoryMethodInvoker();
if(!repoMethodInvoker.hasDeleteOne()) {
if (!repoMethodInvoker.hasDeleteOne()) {
throw new NoSuchMethodException();
}
Function<ReferencedProperty, Resource<?>> handler = new Function<ReferencedProperty, Resource<?>>() {
@Override public Resource<?> apply(ReferencedProperty prop) {
if(null == prop.propertyValue) {
@Override
public Resource<?> apply(ReferencedProperty prop) {
if (null == prop.propertyValue) {
return null;
}
if(prop.property.isCollectionLike()) {
if (prop.property.isCollectionLike()) {
throw new IllegalArgumentException(new HttpRequestMethodNotSupportedException("DELETE"));
} else if(prop.property.isMap()) {
} else if (prop.property.isMap()) {
throw new IllegalArgumentException(new HttpRequestMethodNotSupportedException("DELETE"));
} else {
prop.wrapper.setProperty(prop.property, null);
@@ -186,61 +174,49 @@ public class RepositoryPropertyReferenceController extends AbstractRepositoryRes
}
};
try {
doWithReferencedProperty(repoRequest,
id,
property,
handler);
} catch(IllegalArgumentException iae) {
if(iae.getCause() instanceof HttpRequestMethodNotSupportedException) {
throw (HttpRequestMethodNotSupportedException)iae.getCause();
doWithReferencedProperty(repoRequest, id, property, handler);
} catch (IllegalArgumentException iae) {
if (iae.getCause() instanceof HttpRequestMethodNotSupportedException) {
throw (HttpRequestMethodNotSupportedException) iae.getCause();
}
}
return ControllerUtils.toResponseEntity(null, EMPTY_RESOURCE, HttpStatus.NO_CONTENT);
}
@RequestMapping(
value = BASE_MAPPING + "/{propertyId}",
method = RequestMethod.GET,
produces = {
"application/json",
"application/x-spring-data-verbose+json",
"application/x-spring-data-compact+json",
"text/uri-list"
}
)
@RequestMapping(value = BASE_MAPPING + "/{propertyId}", method = RequestMethod.GET, produces = { "application/json",
"application/x-spring-data-verbose+json", "application/x-spring-data-compact+json", "text/uri-list" })
@ResponseBody
public ResponseEntity<Resource<?>> followPropertyReference(final RepositoryRestRequest repoRequest,
@PathVariable String id,
@PathVariable String property,
final @PathVariable String propertyId)
@PathVariable String id, @PathVariable String property, final @PathVariable String propertyId)
throws ResourceNotFoundException, NoSuchMethodException {
final HttpHeaders headers = new HttpHeaders();
Function<ReferencedProperty, Resource<?>> handler = new Function<ReferencedProperty, Resource<?>>() {
@Override public Resource<?> apply(ReferencedProperty prop) {
if(null == prop.propertyValue) {
@Override
public Resource<?> apply(ReferencedProperty prop) {
if (null == prop.propertyValue) {
throw new ResourceNotFoundException();
}
if(prop.property.isCollectionLike()) {
for(Object obj : ((Iterable<?>)prop.propertyValue)) {
if (prop.property.isCollectionLike()) {
for (Object obj : ((Iterable<?>) prop.propertyValue)) {
BeanWrapper<?, Object> propValWrapper = BeanWrapper.create(obj, null);
String sId = propValWrapper.getProperty(prop.entity.getIdProperty()).toString();
if(propertyId.equals(sId)) {
if (propertyId.equals(sId)) {
PersistentEntityResource<Object> resource = perAssembler.toResource(obj);
headers.set("Content-Location", resource.getId().getHref());
return resource;
}
}
} else if(prop.property.isMap()) {
for(Map.Entry<Object, Object> entry : ((Map<Object, Object>)prop.propertyValue).entrySet()) {
} else if (prop.property.isMap()) {
for (Map.Entry<Object, Object> entry : ((Map<Object, Object>) prop.propertyValue).entrySet()) {
BeanWrapper<?, Object> propValWrapper = BeanWrapper.create(entry.getValue(), null);
String sId = propValWrapper.getProperty(prop.entity.getIdProperty()).toString();
if(propertyId.equals(sId)) {
if (propertyId.equals(sId)) {
PersistentEntityResource<Object> resource = perAssembler.toResource(entry.getValue());
headers.set("Content-Location", resource.getId().getHref());
@@ -258,21 +234,13 @@ public class RepositoryPropertyReferenceController extends AbstractRepositoryRes
return ControllerUtils.toResponseEntity(headers, responseResource, HttpStatus.OK);
}
@RequestMapping(
value = BASE_MAPPING,
method = RequestMethod.GET,
produces = {
"application/x-spring-data-compact+json",
"text/uri-list"
}
)
@RequestMapping(value = BASE_MAPPING, method = RequestMethod.GET, produces = {
"application/x-spring-data-compact+json", "text/uri-list" })
@ResponseBody
public ResponseEntity<Resource<?>> followPropertyReferenceCompact(RepositoryRestRequest repoRequest,
@PathVariable String id,
@PathVariable String property)
throws ResourceNotFoundException, NoSuchMethodException {
@PathVariable String id, @PathVariable String property) throws ResourceNotFoundException, NoSuchMethodException {
ResponseEntity<Resource<?>> response = followPropertyReference(repoRequest, id, property);
if(response.getStatusCode() != HttpStatus.OK) {
if (response.getStatusCode() != HttpStatus.OK) {
return response;
}
@@ -281,32 +249,25 @@ public class RepositoryPropertyReferenceController extends AbstractRepositoryRes
String propName = entityMapping.getNameForPath(property);
ResourceMapping propMapping = entityMapping.getResourceMappingFor(entityMapping.getNameForPath(property));
PersistentProperty<?> persistentProp = repoRequest.getPersistentEntity().getPersistentProperty(propName);
Class<?> propType = (persistentProp.isCollectionLike() || persistentProp.isMap()
? persistentProp.getComponentType()
: persistentProp.getType());
Class<?> propType = (persistentProp.isCollectionLike() || persistentProp.isMap() ? persistentProp
.getComponentType() : persistentProp.getType());
ResourceMapping propRepoMapping = getResourceMapping(config, repositories.getRepositoryInformationFor(propType));
String propRel = String.format("%s.%s.%s.%s",
repoMapping.getRel(),
entityMapping.getRel(),
(null != propMapping ? propMapping.getRel() : property),
propRepoMapping.getRel());
String propRel = String.format("%s.%s.%s.%s", repoMapping.getRel(), entityMapping.getRel(),
(null != propMapping ? propMapping.getRel() : property), propRepoMapping.getRel());
Resource<?> resource = response.getBody();
List<Link> links = new ArrayList<Link>();
URI entityBaseUri = buildUri(repoRequest.getBaseUri(),
repoMapping.getPath(),
id,
property);
URI entityBaseUri = buildUri(repoRequest.getBaseUri(), repoMapping.getPath(), id, property);
if(resource.getContent() instanceof Iterable) {
for(Resource<?> res : (Iterable<Resource<?>>)resource.getContent()) {
if (resource.getContent() instanceof Iterable) {
for (Resource<?> res : (Iterable<Resource<?>>) resource.getContent()) {
Link propLink = propertyReferenceLink(res, entityBaseUri, propRel);
links.add(propLink);
}
} else if(resource.getContent() instanceof Map) {
for(Map.Entry<Object, Resource<?>> entry : ((Map<Object, Resource<?>>)resource.getContent()).entrySet()) {
} else if (resource.getContent() instanceof Map) {
for (Map.Entry<Object, Resource<?>> entry : ((Map<Object, Resource<?>>) resource.getContent()).entrySet()) {
Link l = new Link(entry.getValue().getLink("self").getHref(), entry.getKey().toString());
links.add(l);
}
@@ -317,56 +278,45 @@ public class RepositoryPropertyReferenceController extends AbstractRepositoryRes
return ControllerUtils.toResponseEntity(null, new Resource<Object>(EMPTY_RESOURCE_LIST, links), HttpStatus.OK);
}
@RequestMapping(
value = BASE_MAPPING,
method = {
RequestMethod.POST,
RequestMethod.PUT
},
consumes = {
"application/json",
"application/x-spring-data-compact+json",
"text/uri-list"
}
)
@RequestMapping(value = BASE_MAPPING, method = { RequestMethod.POST, RequestMethod.PUT }, consumes = {
"application/json", "application/x-spring-data-compact+json", "text/uri-list" })
@ResponseBody
public ResponseEntity<Resource<?>> createPropertyReference(final RepositoryRestRequest repoRequest,
final @RequestBody Resource<Object> incoming,
@PathVariable String id,
@PathVariable String property)
final @RequestBody Resource<Object> incoming, @PathVariable String id, @PathVariable String property)
throws ResourceNotFoundException, NoSuchMethodException {
final RepositoryMethodInvoker repoMethodInvoker = repoRequest.getRepositoryMethodInvoker();
if(!repoMethodInvoker.hasSaveOne()) {
if (!repoMethodInvoker.hasSaveOne()) {
throw new NoSuchMethodException();
}
Function<ReferencedProperty, Resource<?>> handler = new Function<ReferencedProperty, Resource<?>>() {
@Override public Resource<?> apply(ReferencedProperty prop) {
if(prop.property.isCollectionLike()) {
@Override
public Resource<?> apply(ReferencedProperty prop) {
if (prop.property.isCollectionLike()) {
Collection<Object> coll = new ArrayList<Object>();
if("POST".equals(repoRequest.getRequest().getMethod())) {
coll.addAll((Collection<Object>)prop.propertyValue);
if ("POST".equals(repoRequest.getRequest().getMethod())) {
coll.addAll((Collection<Object>) prop.propertyValue);
}
for(Link l : incoming.getLinks()) {
for (Link l : incoming.getLinks()) {
Object propVal = loadPropertyValue(prop.propertyType, l.getHref());
coll.add(propVal);
}
prop.wrapper.setProperty(prop.property, coll);
} else if(prop.property.isMap()) {
} else if (prop.property.isMap()) {
Map<String, Object> m = new HashMap<String, Object>();
if("POST".equals(repoRequest.getRequest().getMethod())) {
m.putAll((Map<String, Object>)prop.propertyValue);
if ("POST".equals(repoRequest.getRequest().getMethod())) {
m.putAll((Map<String, Object>) prop.propertyValue);
}
for(Link l : incoming.getLinks()) {
for (Link l : incoming.getLinks()) {
Object propVal = loadPropertyValue(prop.propertyType, l.getHref());
m.put(l.getRel(), propVal);
}
prop.wrapper.setProperty(prop.property, m);
} else {
if("POST".equals(repoRequest.getRequest().getMethod())) {
if ("POST".equals(repoRequest.getRequest().getMethod())) {
throw new IllegalStateException(
"Cannot POST a reference to this singular property since the property type is not a List or a Map.");
}
if(incoming.getLinks().size() != 1) {
if (incoming.getLinks().size() != 1) {
throw new IllegalArgumentException(
"Must send only 1 link to update a property reference that isn't a List or a Map.");
}
@@ -380,49 +330,42 @@ public class RepositoryPropertyReferenceController extends AbstractRepositoryRes
return null;
}
};
doWithReferencedProperty(repoRequest,
id,
property,
handler);
doWithReferencedProperty(repoRequest, id, property, handler);
return ControllerUtils.toResponseEntity(null, EMPTY_RESOURCE, HttpStatus.CREATED);
}
@RequestMapping(
value = BASE_MAPPING + "/{propertyId}",
method = RequestMethod.DELETE
)
@RequestMapping(value = BASE_MAPPING + "/{propertyId}", method = RequestMethod.DELETE)
@ResponseBody
public ResponseEntity<Resource<?>> deletePropertyReferenceId(final RepositoryRestRequest repoRequest,
@PathVariable String id,
@PathVariable String property,
final @PathVariable String propertyId)
@PathVariable String id, @PathVariable String property, final @PathVariable String propertyId)
throws ResourceNotFoundException, NoSuchMethodException {
final RepositoryMethodInvoker repoMethodInvoker = repoRequest.getRepositoryMethodInvoker();
if(!repoMethodInvoker.hasDeleteOne()) {
if (!repoMethodInvoker.hasDeleteOne()) {
throw new NoSuchMethodException();
}
Function<ReferencedProperty, Resource<?>> handler = new Function<ReferencedProperty, Resource<?>>() {
@Override public Resource<?> apply(ReferencedProperty prop) {
if(null == prop.propertyValue) {
@Override
public Resource<?> apply(ReferencedProperty prop) {
if (null == prop.propertyValue) {
return null;
}
if(prop.property.isCollectionLike()) {
if (prop.property.isCollectionLike()) {
Collection<Object> coll = new ArrayList<Object>();
for(Object obj : (Collection<Object>) prop.propertyValue) {
for (Object obj : (Collection<Object>) prop.propertyValue) {
BeanWrapper<?, Object> propValWrapper = BeanWrapper.create(obj, null);
String s = propValWrapper.getProperty(prop.entity.getIdProperty()).toString();
if(!propertyId.equals(s)) {
if (!propertyId.equals(s)) {
coll.add(obj);
}
}
prop.wrapper.setProperty(prop.property, coll);
} else if(prop.property.isMap()) {
} else if (prop.property.isMap()) {
Map<Object, Object> m = new HashMap<Object, Object>();
for(Map.Entry<Object, Object> entry : ((Map<Object, Object>)prop.propertyValue).entrySet()) {
for (Map.Entry<Object, Object> entry : ((Map<Object, Object>) prop.propertyValue).entrySet()) {
BeanWrapper<?, Object> propValWrapper = BeanWrapper.create(entry.getValue(), null);
String s = propValWrapper.getProperty(prop.entity.getIdProperty()).toString();
if(!propertyId.equals(s)) {
if (!propertyId.equals(s)) {
m.put(entry.getKey(), entry.getValue());
}
}
@@ -437,17 +380,12 @@ public class RepositoryPropertyReferenceController extends AbstractRepositoryRes
return null;
}
};
doWithReferencedProperty(repoRequest,
id,
property,
handler);
doWithReferencedProperty(repoRequest, id, property, handler);
return ControllerUtils.toResponseEntity(null, EMPTY_RESOURCE, HttpStatus.NO_CONTENT);
}
private Link propertyReferenceLink(Resource<?> resource,
URI baseUri,
String rel) {
private Link propertyReferenceLink(Resource<?> resource, URI baseUri, String rel) {
Link selfLink = resource.getLink("self");
String objId = selfLink.getHref().substring(selfLink.getHref().lastIndexOf('/') + 1);
return new Link(buildUri(baseUri, objId).toString(), rel);
@@ -455,40 +393,33 @@ public class RepositoryPropertyReferenceController extends AbstractRepositoryRes
private Object loadPropertyValue(Class<?> type, String href) {
String id = href.substring(href.lastIndexOf('/') + 1);
return converter.convert(id,
STRING_TYPE,
TypeDescriptor.valueOf(type));
return converter.convert(id, STRING_TYPE, TypeDescriptor.valueOf(type));
}
private Resource<?> doWithReferencedProperty(RepositoryRestRequest repoRequest,
String id,
String propertyPath,
Function<ReferencedProperty, Resource<?>> handler)
throws ResourceNotFoundException, NoSuchMethodException {
private Resource<?> doWithReferencedProperty(RepositoryRestRequest repoRequest, String id, String propertyPath,
Function<ReferencedProperty, Resource<?>> handler) throws ResourceNotFoundException, NoSuchMethodException {
RepositoryMethodInvoker repoMethodInvoker = repoRequest.getRepositoryMethodInvoker();
if(!repoMethodInvoker.hasFindOne()) {
if (!repoMethodInvoker.hasFindOne()) {
throw new NoSuchMethodException();
}
Object domainObj = converter.convert(id, STRING_TYPE,
TypeDescriptor.valueOf(repoRequest.getPersistentEntity().getType()));
if(null == domainObj) {
if (null == domainObj) {
throw new ResourceNotFoundException();
}
String propertyName = repoRequest.getPersistentEntityResourceMapping().getNameForPath(propertyPath);
PersistentProperty<?> prop = repoRequest.getPersistentEntity().getPersistentProperty(propertyName);
if(null == prop) {
if (null == prop) {
throw new ResourceNotFoundException();
}
BeanWrapper<?, Object> wrapper = BeanWrapper.create(domainObj, null);
Object propVal = wrapper.getProperty(prop);
return handler.apply(new ReferencedProperty(prop,
propVal,
wrapper));
return handler.apply(new ReferencedProperty(prop, propVal, wrapper));
}
private class ReferencedProperty {
@@ -497,18 +428,16 @@ public class RepositoryPropertyReferenceController extends AbstractRepositoryRes
final PersistentProperty<?> property;
final Class<?> propertyType;
final Object propertyValue;
final BeanWrapper<?, ?>wrapper;
final BeanWrapper<?, ?> wrapper;
private ReferencedProperty(PersistentProperty<?> property,
Object propertyValue,
BeanWrapper<?, ?> wrapper) {
private ReferencedProperty(PersistentProperty<?> property, Object propertyValue, BeanWrapper<?, ?> wrapper) {
this.property = property;
this.propertyValue = propertyValue;
this.wrapper = wrapper;
if(property.isCollectionLike()) {
if (property.isCollectionLike()) {
this.propertyType = property.getComponentType();
} else if(property.isMap()) {
} else if (property.isMap()) {
this.propertyType = property.getMapValueType();
} else {
this.propertyType = property.getType();

View File

@@ -12,7 +12,6 @@ import org.springframework.web.servlet.DispatcherServlet;
*/
public class RepositoryRestDispatcherServlet extends DispatcherServlet {
private static final long serialVersionUID = 5761346441984290240L;
public RepositoryRestDispatcherServlet() {

View File

@@ -10,32 +10,34 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl
/**
* {@link RequestMappingHandlerAdapter} implementation that adds a couple argument resolvers for controller method
* parameters used in the REST exporter controller. Also only looks for handler methods in the Spring Data REST
* provided controller classes to help isolate this handler adapter from other handler adapters the user might have
* configured in their Spring MVC context.
* parameters used in the REST exporter controller. Also only looks for handler methods in the Spring Data REST provided
* controller classes to help isolate this handler adapter from other handler adapters the user might have configured in
* their Spring MVC context.
*
* @author Jon Brisbin
*/
public class RepositoryRestHandlerAdapter extends ResourceProcessorInvokingHandlerAdapter {
@Autowired
private List<HandlerMethodArgumentResolver> argumentResolvers;
@Autowired private List<HandlerMethodArgumentResolver> argumentResolvers;
@Override public void afterPropertiesSet() {
@Override
public void afterPropertiesSet() {
setCustomArgumentResolvers(argumentResolvers);
super.afterPropertiesSet();
}
@Override public int getOrder() {
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
@Override protected boolean supportsInternal(HandlerMethod handlerMethod) {
@Override
protected boolean supportsInternal(HandlerMethod handlerMethod) {
Class<?> controllerType = handlerMethod.getBeanType();
return (RepositoryController.class.isAssignableFrom(controllerType)
|| RepositoryEntityController.class.isAssignableFrom(controllerType)
|| RepositoryPropertyReferenceController.class.isAssignableFrom(controllerType)
|| RepositorySearchController.class.isAssignableFrom(controllerType));
|| RepositoryPropertyReferenceController.class.isAssignableFrom(controllerType) || RepositorySearchController.class
.isAssignableFrom(controllerType));
}
}

View File

@@ -21,21 +21,18 @@ import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
/**
* {@link RequestMappingHandlerMapping} implementation that will only find a handler method if a {@link
* org.springframework.data.repository.Repository} is exported under that URL path segment. Also ensures the {@link
* OpenEntityManagerInViewInterceptor} is registered in the application context. The OEMIVI is required for the REST
* exporter to function properly.
* {@link RequestMappingHandlerMapping} implementation that will only find a handler method if a
* {@link org.springframework.data.repository.Repository} is exported under that URL path segment. Also ensures the
* {@link OpenEntityManagerInViewInterceptor} is registered in the application context. The OEMIVI is required for the
* REST exporter to function properly.
*
* @author Jon Brisbin
*/
public class RepositoryRestHandlerMapping extends RequestMappingHandlerMapping {
@Autowired
private Repositories repositories;
@Autowired
private RepositoryRestConfiguration config;
@Autowired(required = false)
private JpaHelper jpaHelper;
@Autowired private Repositories repositories;
@Autowired private RepositoryRestConfiguration config;
@Autowired(required = false) private JpaHelper jpaHelper;
private final ResourceMappings mappings;
@@ -45,26 +42,25 @@ public class RepositoryRestHandlerMapping extends RequestMappingHandlerMapping {
}
@Override
protected HandlerMethod lookupHandlerMethod(String lookupPath,
HttpServletRequest origRequest) throws Exception {
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest origRequest) throws Exception {
String acceptType = origRequest.getHeader("Accept");
if(null == acceptType) {
if (null == acceptType) {
acceptType = config.getDefaultMediaType().toString();
}
List<MediaType> acceptHeaderTypes = MediaType.parseMediaTypes(acceptType);
List<MediaType> acceptableTypes = new ArrayList<MediaType>();
for(MediaType mt : acceptHeaderTypes) {
if(("*".equals(mt.getType()) && ("*".equals(mt.getSubtype()))
|| ("application".equals(mt.getType()) && "*".equals(mt.getSubtype())))) {
for (MediaType mt : acceptHeaderTypes) {
if (("*".equals(mt.getType()) && ("*".equals(mt.getSubtype())) || ("application".equals(mt.getType()) && "*"
.equals(mt.getSubtype())))) {
mt = config.getDefaultMediaType();
}
if(!acceptableTypes.contains(mt)) {
if (!acceptableTypes.contains(mt)) {
acceptableTypes.add(mt);
}
}
if(acceptableTypes.size() > 1) {
if (acceptableTypes.size() > 1) {
acceptType = collectionToDelimitedString(acceptableTypes, ",");
} else if(acceptableTypes.size() == 1) {
} else if (acceptableTypes.size() == 1) {
acceptType = acceptableTypes.get(0).toString();
} else {
acceptType = config.getDefaultMediaType().toString();
@@ -73,19 +69,19 @@ public class RepositoryRestHandlerMapping extends RequestMappingHandlerMapping {
HttpServletRequest request = new DefaultAcceptTypeHttpServletRequest(origRequest, acceptType);
String requestUri = lookupPath;
if(requestUri.startsWith("/")) {
if (requestUri.startsWith("/")) {
requestUri = requestUri.substring(1);
}
if(!hasText(requestUri)) {
if (!hasText(requestUri)) {
return super.lookupHandlerMethod(lookupPath, request);
}
String[] parts = requestUri.split("/");
if(parts.length == 0) {
if (parts.length == 0) {
// Root request
return super.lookupHandlerMethod(lookupPath, request);
}
for(Class<?> domainType : repositories) {
for (Class<?> domainType : repositories) {
if (mappings.exportsMappingFor(domainType)) {
return super.lookupHandlerMethod(lookupPath, request);
}
@@ -94,13 +90,15 @@ public class RepositoryRestHandlerMapping extends RequestMappingHandlerMapping {
return null;
}
@Override protected boolean isHandler(Class<?> beanType) {
@Override
protected boolean isHandler(Class<?> beanType) {
return AnnotationUtils.findAnnotation(beanType, RestController.class) != null;
}
@Override protected void extendInterceptors(List<Object> interceptors) {
if(null != jpaHelper) {
for(Object o : jpaHelper.getInterceptors()) {
@Override
protected void extendInterceptors(List<Object> interceptors) {
if (null != jpaHelper) {
for (Object o : jpaHelper.getInterceptors()) {
interceptors.add(o);
}
}
@@ -109,14 +107,14 @@ public class RepositoryRestHandlerMapping extends RequestMappingHandlerMapping {
private static class DefaultAcceptTypeHttpServletRequest extends HttpServletRequestWrapper {
private final String defaultAcceptType;
private DefaultAcceptTypeHttpServletRequest(HttpServletRequest request,
String defaultAcceptType) {
private DefaultAcceptTypeHttpServletRequest(HttpServletRequest request, String defaultAcceptType) {
super(request);
this.defaultAcceptType = defaultAcceptType;
}
@Override public String getHeader(String name) {
if("accept".equals(name.toLowerCase())) {
@Override
public String getHeader(String name) {
if ("accept".equals(name.toLowerCase())) {
return defaultAcceptType;
} else {
return super.getHeader(name);

View File

@@ -46,16 +46,12 @@ class RepositoryRestRequest {
private final PersistentEntity<?, ?> persistentEntity;
private final ResourceMapping entityMapping;
public RepositoryRestRequest(RepositoryRestConfiguration config,
Repositories repositories,
HttpServletRequest request,
URI baseUri,
RepositoryInformation repoInfo,
ConversionService conversionService) {
public RepositoryRestRequest(RepositoryRestConfiguration config, Repositories repositories,
HttpServletRequest request, URI baseUri, RepositoryInformation repoInfo, ConversionService conversionService) {
this.request = request;
this.baseUri = baseUri;
this.repoMapping = getResourceMapping(config, repoInfo);
if(null == repoMapping || !repoMapping.isExported()) {
if (null == repoMapping || !repoMapping.isExported()) {
this.repoLink = null;
this.repository = null;
this.repoMethodInvoker = null;

View File

@@ -37,14 +37,10 @@ public class RepositoryRestRequestHandlerMethodArgumentResolver implements Handl
private final ConversionService conversionService;
@Autowired
private RepositoryRestConfiguration config;
@Autowired
private Repositories repositories;
@Autowired
private RepositoryInformationHandlerMethodArgumentResolver repoInfoResolver;
@Autowired
private BaseUriMethodArgumentResolver baseUriResolver;
@Autowired private RepositoryRestConfiguration config;
@Autowired private Repositories repositories;
@Autowired private RepositoryInformationHandlerMethodArgumentResolver repoInfoResolver;
@Autowired private BaseUriMethodArgumentResolver baseUriResolver;
public RepositoryRestRequestHandlerMethodArgumentResolver(ConversionService conversionService) {
this.conversionService = conversionService;
@@ -56,15 +52,14 @@ public class RepositoryRestRequestHandlerMethodArgumentResolver implements Handl
}
@Override
public Object resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
URI baseUri = (URI) baseUriResolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
RepositoryInformation repoInfo = repoInfoResolver.resolveArgument(parameter, mavContainer, webRequest,
binderFactory);
return new RepositoryRestRequest(config, repositories, webRequest.getNativeRequest(HttpServletRequest.class), baseUri, repoInfo, conversionService);
return new RepositoryRestRequest(config, repositories, webRequest.getNativeRequest(HttpServletRequest.class),
baseUri, repoInfo, conversionService);
}
}

View File

@@ -62,10 +62,8 @@ class RepositorySearchController extends AbstractRepositoryRestController {
private final RepositoryRestConfiguration config;
@Autowired
public RepositorySearchController(Repositories repositories,
RepositoryRestConfiguration config,
PagedResourcesAssembler<Object> assembler,
PersistentEntityResourceAssembler<Object> perAssembler) {
public RepositorySearchController(Repositories repositories, RepositoryRestConfiguration config,
PagedResourcesAssembler<Object> assembler, PersistentEntityResourceAssembler<Object> perAssembler) {
super(assembler, perAssembler);
@@ -73,20 +71,13 @@ class RepositorySearchController extends AbstractRepositoryRestController {
this.config = config;
}
@RequestMapping(
value = BASE_MAPPING,
method = RequestMethod.GET,
produces = {
"application/json",
"application/x-spring-data-compact+json"
}
)
@RequestMapping(value = BASE_MAPPING, method = RequestMethod.GET, produces = { "application/json",
"application/x-spring-data-compact+json" })
@ResponseBody
public Resource<?> list(RepositoryRestRequest repoRequest) throws ResourceNotFoundException {
List<Link> links = new ArrayList<Link>();
links.addAll(queryMethodLinks(repoRequest.getBaseUri(),
repoRequest.getPersistentEntity().getType()));
if(links.isEmpty()) {
links.addAll(queryMethodLinks(repoRequest.getBaseUri(), repoRequest.getPersistentEntity().getType()));
if (links.isEmpty()) {
throw new ResourceNotFoundException();
}
return new Resource<Object>(Collections.emptyList(), links);
@@ -110,41 +101,32 @@ class RepositorySearchController extends AbstractRepositoryRestController {
return links;
}
@RequestMapping(
value = BASE_MAPPING + "/{method}",
method = RequestMethod.GET,
produces = {
"application/json",
"application/x-spring-data-verbose+json"
}
)
@RequestMapping(value = BASE_MAPPING + "/{method}", method = RequestMethod.GET, produces = { "application/json",
"application/x-spring-data-verbose+json" })
@ResponseBody
public ResourceSupport query(final RepositoryRestRequest repoRequest,
@PathVariable String repository,
@PathVariable String method, Pageable pageable)
throws ResourceNotFoundException {
public ResourceSupport query(final RepositoryRestRequest repoRequest, @PathVariable String repository,
@PathVariable String method, Pageable pageable) throws ResourceNotFoundException {
RepositoryMethodInvoker repoMethodInvoker = repoRequest.getRepositoryMethodInvoker();
if(repoMethodInvoker.getQueryMethods().isEmpty()) {
if (repoMethodInvoker.getQueryMethods().isEmpty()) {
throw new ResourceNotFoundException();
}
ResourceMapping repoMapping = repoRequest.getRepositoryResourceMapping();
String methodName = repoMapping.getNameForPath(method);
RepositoryMethod repoMethod = repoMethodInvoker.getQueryMethods().get(methodName);
if(null == repoMethod) {
for(RepositoryMethod queryMethod : repoMethodInvoker.getQueryMethods().values()) {
if (null == repoMethod) {
for (RepositoryMethod queryMethod : repoMethodInvoker.getQueryMethods().values()) {
String path = findPath(queryMethod.getMethod());
if(path.equals(method)) {
if (path.equals(method)) {
repoMethod = queryMethod;
break;
}
}
if(null == repoMethod) {
if (null == repoMethod) {
throw new ResourceNotFoundException();
}
}
Map<String, String[]> rawParameters = repoRequest.getRequest().getParameterMap();
Object result = repoMethodInvoker.invokeQueryMethod(repoMethod, pageable, rawParameters);
@@ -154,37 +136,28 @@ class RepositorySearchController extends AbstractRepositoryRestController {
return resultToResources(result, baseLink);
}
@RequestMapping(
value = BASE_MAPPING +"/{method}",
method = RequestMethod.GET,
produces = {
"application/x-spring-data-compact+json"
}
)
@RequestMapping(value = BASE_MAPPING + "/{method}", method = RequestMethod.GET,
produces = { "application/x-spring-data-compact+json" })
@ResponseBody
public ResourceSupport queryCompact(RepositoryRestRequest repoRequest,
@PathVariable String repository,
@PathVariable String method,
Pageable pageable)
throws ResourceNotFoundException {
public ResourceSupport queryCompact(RepositoryRestRequest repoRequest, @PathVariable String repository,
@PathVariable String method, Pageable pageable) throws ResourceNotFoundException {
List<Link> links = new ArrayList<Link>();
ResourceSupport resource = query(repoRequest, repository, method, pageable);
links.addAll(resource.getLinks());
if(resource instanceof Resources && ((Resources<?>) resource).getContent() != null) {
for(Object obj : ((Resources<?>) resource).getContent()) {
if(null != obj && obj instanceof Resource) {
Resource<?> res = (Resource<?>)obj;
if (resource instanceof Resources && ((Resources<?>) resource).getContent() != null) {
for (Object obj : ((Resources<?>) resource).getContent()) {
if (null != obj && obj instanceof Resource) {
Resource<?> res = (Resource<?>) obj;
links.add(resourceLink(repoRequest, res));
}
}
} else if(resource instanceof Resource) {
} else if (resource instanceof Resource) {
Resource<?> res = (Resource<?>) resource;
links.add(resourceLink(repoRequest, res));
}
return new Resource<Object>(EMPTY_RESOURCE_LIST, links);
}

View File

@@ -67,8 +67,8 @@ public class ResourceProcessorHandlerMethodReturnValueHandler implements Handler
* Will consider the given {@link ResourceProcessor} to post-process the controller methods return value to before
* invoking the delegate.
*
* @param delegate the {@link HandlerMethodReturnValueHandler} to evenually delegate calls to, must not be {@literal
* null}.
* @param delegate the {@link HandlerMethodReturnValueHandler} to evenually delegate calls to, must not be
* {@literal null}.
* @param processors the {@link ResourceProcessor}s to be considered, must not be {@literal null}.
*/
public ResourceProcessorHandlerMethodReturnValueHandler(HandlerMethodReturnValueHandler delegate,
@@ -194,8 +194,9 @@ public class ResourceProcessorHandlerMethodReturnValueHandler implements Handler
}
/**
* Re-wraps the result of the post-processing work into an {@link HttpEntity} or {@link ResponseEntity} if the original
* value was one of those two types. Copies headers and status code from the original value but uses the new body.
* Re-wraps the result of the post-processing work into an {@link HttpEntity} or {@link ResponseEntity} if the
* original value was one of those two types. Copies headers and status code from the original value but uses the new
* body.
*
* @param newBody the post-processed value.
* @param originalValue the original input value.
@@ -236,8 +237,8 @@ public class ResourceProcessorHandlerMethodReturnValueHandler implements Handler
}
/**
* Interface to unify interaction with {@link ResourceProcessor}s. The {@link Ordered} rank should be determined by the
* underlying processor.
* Interface to unify interaction with {@link ResourceProcessor}s. The {@link Ordered} rank should be determined by
* the underlying processor.
*
* @author Oliver Gierke
*/
@@ -254,8 +255,8 @@ public class ResourceProcessorHandlerMethodReturnValueHandler implements Handler
boolean supports(TypeInformation<?> typeInformation, Object value);
/**
* Performs the actual invocation of the processor. Implementations can be sure {@link #supports(TypeInformation,
* Object)} has been called before and returned {@literal true}.
* Performs the actual invocation of the processor. Implementations can be sure
* {@link #supports(TypeInformation, Object)} has been called before and returned {@literal true}.
*
* @param object
*/
@@ -355,8 +356,8 @@ public class ResourceProcessorHandlerMethodReturnValueHandler implements Handler
}
/**
* Returns whether the given {@link Resource} matches the given target {@link TypeInformation}. We inspect the {@link
* Resource}'s value to determine the match.
* Returns whether the given {@link Resource} matches the given target {@link TypeInformation}. We inspect the
* {@link Resource}'s value to determine the match.
*
* @param resource
* @param target must not be {@literal null}.
@@ -411,8 +412,8 @@ public class ResourceProcessorHandlerMethodReturnValueHandler implements Handler
}
/**
* Returns whether the given {@link Resources} instance matches the given {@link TypeInformation}. We predict this by
* inspecting the first element of the content of the {@link Resources}.
* Returns whether the given {@link Resources} instance matches the given {@link TypeInformation}. We predict this
* by inspecting the first element of the content of the {@link Resources}.
*
* @param resources the {@link Resources} to inspect.
* @param target that target {@link TypeInformation}.

View File

@@ -30,21 +30,18 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl
/**
* Special {@link RequestMappingHandlerAdapter} that tweaks the {@link HandlerMethodReturnValueHandlerComposite} to be
* proxied by a {@link ResourceProcessorHandlerMethodReturnValueHandler} which will invoke the {@link
* ResourceProcessor}s
* found in the application context and eventually delegate to the originally configured
* proxied by a {@link ResourceProcessorHandlerMethodReturnValueHandler} which will invoke the {@link ResourceProcessor}
* s found in the application context and eventually delegate to the originally configured
* {@link HandlerMethodReturnValueHandler}.
* <p/>
* This is a separate component as it might make sense to deploy it in a standalone SpringMVC application to enable
* post
* This is a separate component as it might make sense to deploy it in a standalone SpringMVC application to enable post
* processing. It would actually make most sense in Spring HATEOAS project.
*
* @author Oliver Gierke
*/
public class ResourceProcessorInvokingHandlerAdapter extends RequestMappingHandlerAdapter {
@Autowired(required = false)
private List<ResourceProcessor<?>> resourcesProcessors = new ArrayList<ResourceProcessor<?>>();
@Autowired(required = false) private List<ResourceProcessor<?>> resourcesProcessors = new ArrayList<ResourceProcessor<?>>();
/**
* Empty constructor to setup a {@link ResourceProcessorInvokingHandlerAdapter}.
@@ -57,8 +54,7 @@ public class ResourceProcessorInvokingHandlerAdapter extends RequestMappingHandl
* Copy constructor to copy configuration of {@link HttpMessageConverter}s, {@link WebBindingInitializer}, custom
* {@link HandlerMethodArgumentResolver}s and custom {@link HandlerMethodReturnValueHandler}s.
*
* @param original
* must not be {@literal null}.
* @param original must not be {@literal null}.
*/
public ResourceProcessorInvokingHandlerAdapter(RequestMappingHandlerAdapter original) {

View File

@@ -15,16 +15,15 @@ import org.springframework.web.method.support.ModelAndViewContainer;
*/
public class ServerHttpRequestMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override public boolean supportsParameter(MethodParameter parameter) {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return ClassUtils.isAssignable(parameter.getParameterType(), ServletServerHttpRequest.class);
}
@Override
public Object resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
return new ServletServerHttpRequest((HttpServletRequest)webRequest.getNativeRequest());
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
return new ServletServerHttpRequest((HttpServletRequest) webRequest.getNativeRequest());
}
}

View File

@@ -10,7 +10,7 @@ import java.lang.annotation.Target;
*
* @author Jon Brisbin
*/
@Target({ElementType.PARAMETER})
@Target({ ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
public @interface BaseURI {
}

View File

@@ -84,7 +84,8 @@ import com.fasterxml.jackson.databind.SerializationFeature;
* @author Oliver Gierke
*/
@Configuration
@ComponentScan(basePackageClasses = RestController.class, includeFilters = @Filter(RestController.class), useDefaultFilters = false)
@ComponentScan(basePackageClasses = RestController.class, includeFilters = @Filter(RestController.class),
useDefaultFilters = false)
@ImportResource("classpath*:META-INF/spring-data-rest/**/*.xml")
public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebConfiguration {

View File

@@ -29,41 +29,41 @@ public class UriListHttpMessageConverter implements HttpMessageConverter<Resourc
MEDIA_TYPES.add(MediaType.parseMediaType("text/uri-list"));
}
@Override public boolean canRead(Class<?> clazz, MediaType mediaType) {
if(null == mediaType) {
@Override
public boolean canRead(Class<?> clazz, MediaType mediaType) {
if (null == mediaType) {
return false;
}
return Resource.class.isAssignableFrom(clazz) && mediaType.getSubtype().contains("uri-list");
}
@Override public boolean canWrite(Class<?> clazz, MediaType mediaType) {
@Override
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
return canRead(clazz, mediaType);
}
@Override public List<MediaType> getSupportedMediaTypes() {
@Override
public List<MediaType> getSupportedMediaTypes() {
return MEDIA_TYPES;
}
@Override public Resource<?> read(Class<? extends Resource<?>> clazz,
HttpInputMessage inputMessage)
throws IOException,
@Override
public Resource<?> read(Class<? extends Resource<?>> clazz, HttpInputMessage inputMessage) throws IOException,
HttpMessageNotReadableException {
List<Link> links = new ArrayList<Link>();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputMessage.getBody()));
String line;
while(null != (line = reader.readLine())) {
while (null != (line = reader.readLine())) {
links.add(new Link(line));
}
return new Resource<Object>(Collections.emptyList(), links);
}
@Override public void write(Resource<?> resource,
MediaType contentType,
HttpOutputMessage outputMessage)
throws IOException,
@Override
public void write(Resource<?> resource, MediaType contentType, HttpOutputMessage outputMessage) throws IOException,
HttpMessageNotWritableException {
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputMessage.getBody()));
for(Link link : resource.getLinks()) {
for (Link link : resource.getLinks()) {
writer.write(link.getHref());
writer.newLine();
}

View File

@@ -15,33 +15,28 @@ public class Jackson2DatatypeHelper {
private static final Logger LOG = LoggerFactory.getLogger(Jackson2DatatypeHelper.class);
private static final boolean IS_HIBERNATE4_MODULE_AVAILABLE = ClassUtils.isPresent(
"com.fasterxml.jackson.datatype.hibernate4.Hibernate4Module",
Jackson2DatatypeHelper.class.getClassLoader()
);
"com.fasterxml.jackson.datatype.hibernate4.Hibernate4Module", Jackson2DatatypeHelper.class.getClassLoader());
private static final boolean IS_JODA_MODULE_AVAILABLE = ClassUtils.isPresent(
"com.fasterxml.jackson.datatype.joda.JodaModule",
Jackson2DatatypeHelper.class.getClassLoader()
);
"com.fasterxml.jackson.datatype.joda.JodaModule", Jackson2DatatypeHelper.class.getClassLoader());
public static void configureObjectMapper(ObjectMapper mapper) {
// Hibernate types
if(IS_HIBERNATE4_MODULE_AVAILABLE) {
if (IS_HIBERNATE4_MODULE_AVAILABLE) {
try {
mapper.registerModule((Module)Class.forName("com.fasterxml.jackson.datatype.hibernate4.Hibernate4Module")
mapper.registerModule((Module) Class.forName("com.fasterxml.jackson.datatype.hibernate4.Hibernate4Module")
.newInstance());
} catch(Throwable t) {
if(LOG.isDebugEnabled()) {
} catch (Throwable t) {
if (LOG.isDebugEnabled()) {
LOG.debug(t.getMessage(), t);
}
}
}
// JODA time
if(IS_JODA_MODULE_AVAILABLE) {
if (IS_JODA_MODULE_AVAILABLE) {
try {
mapper.registerModule((Module)Class.forName("com.fasterxml.jackson.datatype.joda.JodaModule")
.newInstance());
} catch(Throwable t) {
if(LOG.isDebugEnabled()) {
mapper.registerModule((Module) Class.forName("com.fasterxml.jackson.datatype.joda.JodaModule").newInstance());
} catch (Throwable t) {
if (LOG.isDebugEnabled()) {
LOG.debug(t.getMessage(), t);
}
}

View File

@@ -14,8 +14,7 @@ import org.springframework.hateoas.Resource;
public class JsonSchema extends Resource<Map<String, JsonSchema.Property>> {
private final String name;
@SuppressWarnings("unused")
private final String description;
@SuppressWarnings("unused") private final String description;
public JsonSchema(String name, String description) {
super(new HashMap<String, Property>());
@@ -28,7 +27,8 @@ public class JsonSchema extends Resource<Map<String, JsonSchema.Property>> {
}
@JsonProperty("properties")
@Override public Map<String, JsonSchema.Property> getContent() {
@Override
public Map<String, JsonSchema.Property> getContent() {
return super.getContent();
}
@@ -42,7 +42,7 @@ public class JsonSchema extends Resource<Map<String, JsonSchema.Property>> {
}
public ArrayProperty getArrayProperty(String name) {
return (ArrayProperty)getContent().get(name);
return (ArrayProperty) getContent().get(name);
}
public static class Property {
@@ -72,9 +72,7 @@ public class JsonSchema extends Resource<Map<String, JsonSchema.Property>> {
public static class ArrayProperty extends Property {
private List<Property> items = new ArrayList<Property>();
public ArrayProperty(String type,
String description,
boolean required) {
public ArrayProperty(String type, String description, boolean required) {
super(type, description, required);
}

View File

@@ -55,12 +55,9 @@ public class PersistentEntityJackson2Module extends SimpleModule implements Init
private static final long serialVersionUID = -7289265674870906323L;
private static final Logger LOG = LoggerFactory.getLogger(PersistentEntityJackson2Module.class);
private static final TypeDescriptor URI_TYPE = TypeDescriptor.valueOf(URI.class);
@Autowired
private Repositories repositories;
@Autowired
private RepositoryRestConfiguration config;
@Autowired
private UriDomainClassConverter uriDomainClassConverter;
@Autowired private Repositories repositories;
@Autowired private RepositoryRestConfiguration config;
@Autowired private UriDomainClassConverter uriDomainClassConverter;
private final ResourceMappings mappings;
public PersistentEntityJackson2Module(ResourceMappings resourceMappings) {
@@ -71,10 +68,8 @@ public class PersistentEntityJackson2Module extends SimpleModule implements Init
addSerializer(new ResourceSerializer());
}
public static boolean maybeAddAssociationLink(RepositoryLinkBuilder builder,
ResourceMappings mappings,
PersistentProperty<?> persistentProperty,
List<Link> links) {
public static boolean maybeAddAssociationLink(RepositoryLinkBuilder builder, ResourceMappings mappings,
PersistentProperty<?> persistentProperty, List<Link> links) {
Assert.isTrue(persistentProperty.isAssociation(), "PersistentProperty must be an association!");
ResourceMetadata metadata = mappings.getMappingFor(persistentProperty.getOwner().getType());
@@ -85,7 +80,7 @@ public class PersistentEntityJackson2Module extends SimpleModule implements Init
metadata = mappings.getMappingFor(persistentProperty.getActualType());
if(metadata.isExported()) {
if (metadata.isExported()) {
String propertyRel = String.format("%s.%s", metadata.getSingleResourceRel(), persistentProperty.getName());
links.add(builder.slash(persistentProperty.getName()).withRel(propertyRel));
@@ -98,12 +93,13 @@ public class PersistentEntityJackson2Module extends SimpleModule implements Init
return false;
}
@SuppressWarnings({"unchecked", "rawtypes"})
@Override public void afterPropertiesSet() throws Exception {
for(Class<?> domainType : repositories) {
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public void afterPropertiesSet() throws Exception {
for (Class<?> domainType : repositories) {
PersistentEntity<?, ?> pe = repositories.getPersistentEntity(domainType);
if(null == pe) {
if(LOG.isWarnEnabled()) {
if (null == pe) {
if (LOG.isWarnEnabled()) {
LOG.warn("The domain class {} does not have PersistentEntity metadata.", domainType.getName());
}
} else {
@@ -122,47 +118,46 @@ public class PersistentEntityJackson2Module extends SimpleModule implements Init
this.persistentEntity = persistentEntity;
}
@SuppressWarnings({"unchecked", "incomplete-switch", "null", "unused"})
@Override public T deserialize(JsonParser jp,
DeserializationContext ctxt) throws IOException,
JsonProcessingException {
@SuppressWarnings({ "unchecked", "incomplete-switch", "null", "unused" })
@Override
public T deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
Object entity = instantiateClass(getValueClass());
BeanWrapper<?, Object> wrapper = BeanWrapper.create(entity, null);
ResourceMetadata metadata = mappings.getMappingFor(getValueClass());
for(JsonToken tok = jp.nextToken(); tok != JsonToken.END_OBJECT; tok = jp.nextToken()) {
for (JsonToken tok = jp.nextToken(); tok != JsonToken.END_OBJECT; tok = jp.nextToken()) {
String name = jp.getCurrentName();
switch(tok) {
switch (tok) {
case FIELD_NAME: {
if("href".equals(name)) {
if ("href".equals(name)) {
URI uri = URI.create(jp.nextTextValue());
TypeDescriptor entityType = TypeDescriptor.forObject(entity);
if(uriDomainClassConverter.matches(URI_TYPE, entityType)) {
if (uriDomainClassConverter.matches(URI_TYPE, entityType)) {
entity = uriDomainClassConverter.convert(uri, URI_TYPE, entityType);
}
continue;
}
if("rel".equals(name)) {
if ("rel".equals(name)) {
// rel is currently ignored
continue;
}
PersistentProperty<?> persistentProperty = persistentEntity.getPersistentProperty(name);
if(null == persistentProperty) {
if (null == persistentProperty) {
continue;
}
Object val = null;
if("links".equals(name)) {
if((tok = jp.nextToken()) == JsonToken.START_ARRAY) {
while((tok = jp.nextToken()) != JsonToken.END_ARRAY) {
if ("links".equals(name)) {
if ((tok = jp.nextToken()) == JsonToken.START_ARRAY) {
while ((tok = jp.nextToken()) != JsonToken.END_ARRAY) {
// Advance past the links
}
} else if(tok == JsonToken.VALUE_NULL) {
} else if (tok == JsonToken.VALUE_NULL) {
// skip null value
} else {
throw new HttpMessageNotReadableException(
@@ -171,44 +166,44 @@ public class PersistentEntityJackson2Module extends SimpleModule implements Init
continue;
}
if(null == persistentProperty) {
if (null == persistentProperty) {
// do nothing
continue;
}
// Try and read the value of this attribute.
// The method of doing that varies based on the type of the property.
if(persistentProperty.isCollectionLike()) {
if (persistentProperty.isCollectionLike()) {
Class<? extends Collection<?>> ctype = (Class<? extends Collection<?>>) persistentProperty.getType();
Collection<Object> c = (Collection<Object>) wrapper.getProperty(persistentProperty);
if(null == c || c == Collections.EMPTY_LIST || c == Collections.EMPTY_SET) {
if(Collection.class.isAssignableFrom(ctype)) {
if (null == c || c == Collections.EMPTY_LIST || c == Collections.EMPTY_SET) {
if (Collection.class.isAssignableFrom(ctype)) {
c = new ArrayList<Object>();
} else if(Set.class.isAssignableFrom(ctype)) {
} else if (Set.class.isAssignableFrom(ctype)) {
c = new HashSet<Object>();
}
}
if((tok = jp.nextToken()) == JsonToken.START_ARRAY) {
while((tok = jp.nextToken()) != JsonToken.END_ARRAY) {
if ((tok = jp.nextToken()) == JsonToken.START_ARRAY) {
while ((tok = jp.nextToken()) != JsonToken.END_ARRAY) {
Object cval = jp.readValueAs(persistentProperty.getComponentType());
c.add(cval);
}
val = c;
} else if(tok == JsonToken.VALUE_NULL) {
} else if (tok == JsonToken.VALUE_NULL) {
val = null;
} else {
throw new HttpMessageNotReadableException("Cannot read a JSON " + tok + " as a Collection.");
}
} else if(persistentProperty.isMap()) {
Class<? extends Map<?, ?>> mtype = (Class<? extends Map<?, ?>>)persistentProperty.getType();
} else if (persistentProperty.isMap()) {
Class<? extends Map<?, ?>> mtype = (Class<? extends Map<?, ?>>) persistentProperty.getType();
Map<Object, Object> m = (Map<Object, Object>) wrapper.getProperty(persistentProperty);
if(null == m || m == Collections.EMPTY_MAP) {
if (null == m || m == Collections.EMPTY_MAP) {
m = new HashMap<Object, Object>();
}
if((tok = jp.nextToken()) == JsonToken.START_OBJECT) {
if ((tok = jp.nextToken()) == JsonToken.START_OBJECT) {
do {
name = jp.getCurrentName();
// TODO resolve domain object from URI
@@ -216,16 +211,16 @@ public class PersistentEntityJackson2Module extends SimpleModule implements Init
Object mval = jp.readValueAs(persistentProperty.getMapValueType());
m.put(name, mval);
} while((tok = jp.nextToken()) != JsonToken.END_OBJECT);
} while ((tok = jp.nextToken()) != JsonToken.END_OBJECT);
val = m;
} else if(tok == JsonToken.VALUE_NULL) {
} else if (tok == JsonToken.VALUE_NULL) {
val = null;
} else {
throw new HttpMessageNotReadableException("Cannot read a JSON " + tok + " as a Map.");
}
} else {
if((tok = jp.nextToken()) != JsonToken.VALUE_NULL) {
if ((tok = jp.nextToken()) != JsonToken.VALUE_NULL) {
val = jp.readValueAs(persistentProperty.getType());
}
}
@@ -237,7 +232,7 @@ public class PersistentEntityJackson2Module extends SimpleModule implements Init
}
}
return (T)entity;
return (T) entity;
}
}
@@ -248,12 +243,11 @@ public class PersistentEntityJackson2Module extends SimpleModule implements Init
super(PersistentEntityResource.class);
}
@SuppressWarnings({"unchecked"})
@Override public void serialize(final PersistentEntityResource resource,
final JsonGenerator jgen,
final SerializerProvider provider) throws IOException,
JsonGenerationException {
if(LOG.isDebugEnabled()) {
@SuppressWarnings({ "unchecked" })
@Override
public void serialize(final PersistentEntityResource resource, final JsonGenerator jgen,
final SerializerProvider provider) throws IOException, JsonGenerationException {
if (LOG.isDebugEnabled()) {
LOG.debug("Serializing PersistentEntity " + resource.getPersistentEntity());
}
@@ -274,11 +268,13 @@ public class PersistentEntityJackson2Module extends SimpleModule implements Init
jgen.writeStartObject();
try {
entity.doWithProperties(new PropertyHandler() {
@Override public void doWithPersistentProperty(PersistentProperty property) {
@Override
public void doWithPersistentProperty(PersistentProperty property) {
boolean idAvailableAndShallNotBeExposed = property.isIdProperty() && !config.isIdExposedFor(entity.getType());
boolean idAvailableAndShallNotBeExposed = property.isIdProperty()
&& !config.isIdExposedFor(entity.getType());
if(idAvailableAndShallNotBeExposed) {
if (idAvailableAndShallNotBeExposed) {
return;
}
@@ -290,7 +286,7 @@ public class PersistentEntityJackson2Module extends SimpleModule implements Init
Object propertyValue = wrapper.getProperty(property);
try {
jgen.writeObjectField(property.getName(), propertyValue);
} catch(IOException e) {
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
@@ -298,11 +294,12 @@ public class PersistentEntityJackson2Module extends SimpleModule implements Init
// Add associations as links
entity.doWithAssociations(new AssociationHandler() {
@Override public void doWithAssociation(Association association) {
@Override
public void doWithAssociation(Association association) {
PersistentProperty property = association.getInverse();
if(!mappings.isMapped(property)) {
if (!mappings.isMapped(property)) {
return;
}
@@ -313,20 +310,20 @@ public class PersistentEntityJackson2Module extends SimpleModule implements Init
Object propertyValue = wrapper.getProperty(property);
try {
jgen.writeObjectField(property.getName(), propertyValue);
} catch(IOException e) {
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
});
jgen.writeArrayFieldStart("links");
for(Link l : links) {
for (Link l : links) {
jgen.writeObject(l);
}
jgen.writeEndArray();
} catch(IllegalStateException e) {
throw (IOException)e.getCause();
} catch (IllegalStateException e) {
throw (IOException) e.getCause();
} finally {
jgen.writeEndObject();
}

View File

@@ -29,64 +29,64 @@ import org.springframework.hateoas.Link;
/**
* @author Jon Brisbin
*/
public class PersistentEntityToJsonSchemaConverter
extends RepositoryInformationSupport
implements ConditionalGenericConverter,
InitializingBean {
public class PersistentEntityToJsonSchemaConverter extends RepositoryInformationSupport implements
ConditionalGenericConverter, InitializingBean {
private static final TypeDescriptor STRING_TYPE = TypeDescriptor.valueOf(String.class);
private static final TypeDescriptor SCHEMA_TYPE = TypeDescriptor.valueOf(JsonSchema.class);
private Set<ConvertiblePair> convertiblePairs = new HashSet<ConvertiblePair>();
private ResourceMappings mappings;
@Override public void afterPropertiesSet() throws Exception {
@Override
public void afterPropertiesSet() throws Exception {
for(Class<?> domainType : repositories) {
for (Class<?> domainType : repositories) {
convertiblePairs.add(new ConvertiblePair(domainType, JsonSchema.class));
}
this.mappings = new ResourceMappings(config, repositories);
}
@Override public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
return (Class.class.isAssignableFrom(sourceType.getType()) && JsonSchema.class.isAssignableFrom(targetType.getType()));
@Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
return (Class.class.isAssignableFrom(sourceType.getType()) && JsonSchema.class.isAssignableFrom(targetType
.getType()));
}
@Override public Set<ConvertiblePair> getConvertibleTypes() {
@Override
public Set<ConvertiblePair> getConvertibleTypes() {
return convertiblePairs;
}
public JsonSchema convert(Class<?> domainType) {
return (JsonSchema)convert(domainType, STRING_TYPE, SCHEMA_TYPE);
return (JsonSchema) convert(domainType, STRING_TYPE, SCHEMA_TYPE);
}
@SuppressWarnings({"unchecked", "rawtypes"})
@Override public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
PersistentEntity<?, ?> persistentEntity = repositories.getPersistentEntity((Class<?>)source);
PersistentEntity<?, ?> persistentEntity = repositories.getPersistentEntity((Class<?>) source);
final ResourceMetadata metadata = mappings.getMappingFor(persistentEntity.getClass());
String entityDesc = persistentEntity.getType().isAnnotationPresent(Description.class)
? ((Description)persistentEntity.getType().getAnnotation(Description.class)).value()
: null;
String entityDesc = persistentEntity.getType().isAnnotationPresent(Description.class) ? ((Description) persistentEntity
.getType().getAnnotation(Description.class)).value() : null;
final JsonSchema jsonSchema = new JsonSchema(persistentEntity.getName(), entityDesc);
persistentEntity.doWithProperties(new PropertyHandler() {
@Override public void doWithPersistentProperty(PersistentProperty persistentProperty) {
@Override
public void doWithPersistentProperty(PersistentProperty persistentProperty) {
Class<?> propertyType = persistentProperty.getType();
String type = uncapitalize(propertyType.getSimpleName());
boolean notNull = (persistentProperty.getField().isAnnotationPresent(Nonnull.class)
|| persistentProperty.getGetter().isAnnotationPresent(Nonnull.class))
|| (persistentProperty.getField().isAnnotationPresent(NotNull.class)
|| persistentProperty.getGetter().isAnnotationPresent(NotNull.class));
String desc = persistentProperty.getField().isAnnotationPresent(Description.class)
? persistentProperty.getField().getAnnotation(Description.class).value()
: persistentProperty.getGetter().isAnnotationPresent(Description.class)
? persistentProperty.getGetter().getAnnotation(Description.class).value()
: null;
boolean notNull = (persistentProperty.getField().isAnnotationPresent(Nonnull.class) || persistentProperty
.getGetter().isAnnotationPresent(Nonnull.class))
|| (persistentProperty.getField().isAnnotationPresent(NotNull.class) || persistentProperty.getGetter()
.isAnnotationPresent(NotNull.class));
String desc = persistentProperty.getField().isAnnotationPresent(Description.class) ? persistentProperty
.getField().getAnnotation(Description.class).value() : persistentProperty.getGetter().isAnnotationPresent(
Description.class) ? persistentProperty.getGetter().getAnnotation(Description.class).value() : null;
JsonSchema.Property property;
if(persistentProperty.isCollectionLike()) {
if (persistentProperty.isCollectionLike()) {
property = new JsonSchema.ArrayProperty("array", desc, notNull);
} else {
property = new JsonSchema.Property(type, desc, notNull);
@@ -98,9 +98,10 @@ public class PersistentEntityToJsonSchemaConverter
final List<Link> links = new ArrayList<Link>();
persistentEntity.doWithAssociations(new AssociationHandler() {
@Override public void doWithAssociation(Association association) {
@Override
public void doWithAssociation(Association association) {
PersistentProperty persistentProperty = association.getInverse();
if(!metadata.isMapped(persistentProperty)) {
if (!metadata.isMapped(persistentProperty)) {
return;
}

Some files were not shown because too many files have changed in this diff Show More