From 6200a5fef913501dcd526ec9c726fb69a7f1e792 Mon Sep 17 00:00:00 2001 From: Oliver Grande Date: Tue, 14 Apr 2020 17:12:22 +0200 Subject: [PATCH 001/192] Feature/transient fields (#142) * Fix null pointer if no enumerations are part of servcie * Enable HAS and enumeration as return type of operations * Allow Enumerations as operation parameter * Provide java based operations converted enumeration * Add SourceClear addon * Delete SourceClean addon * Enumerations at UDF functions - Works for bound functions - Works for functions with import * Correct unit tests * Enable multiple values for flags enumerations * Switch detection default between Embedded and Entity type * Allow collection attributes for metadata * Enable query without collection attributes * Rework query result conversion to reduce memory consumtion * Missing Metadata pom * First step entity with collections as return of function/action * Bugfix: Expand on Parent with $filter on navigation path * Enable the use of Join Tables - Filter on navigation via Join Table generally not supported * Create new query for inlinecount * Enable Join Tables@Navigation Filter - Not working mapped associations - Not working $count * Enable Join Tables@Navigation Filter - With mapped associations - With $count, know issue EclipsLink two sub types * Increase Version --> 0.2.6 * Remove deprecated JPAExecutableQuery * Bugfix: unidirectional join table based association * Access collection properties via navigation - New version * Access collection properties w and w/o $select * Access collection properties which are part of complex property * CUD operations on collection properties * Filter on collection properties pre optimization * Filter on collection properties any/all * Filter on collection w/o filter on $count and orderby $count * Correct issue #29 - Correct /$count implementation in JPAJoinQuery - Clean-up Hibernate differences -- Subquery from clause -- Id Class determination * Increase Version to 0.2.7 * Enable ..@odata.navigationLink in case of odata.metadata=full - links@complex types not yet working * Preparation for solution of issue OLINGO-1143 * Correct NullPointer and some clean-ups * Support order by $count - Increase version to 0.2.8 * Intermediate merge clean-up * Solve merge problem navigate complex collections * Resolve merge conflict converter * Correct error collection property and expand=* * Enable filter $count on collection property * Update version and url * Create and use page provider * Recreate change for solution of issue OLINGO-1143 * Finalize top level server driven paging * Correct string handling error * Correct link problem * Enable skiptoken to have other type than String * Move paging so next request injects old uriInfo correctly * Enable deep insert via complex properties * Ignore test for next commit * Enable create of a new entity linked by a to one using PATCH * Update to Olingo 4.5.0 - use new Olingo version - adopt one test to changed @odata.context content * Collection attributes rework. Issue #60 - Change processor pom -> javax.servlet became provided * Enable annotation for properties to mark them authorization relevant * Enable multiple protected properties at complex attributes * Rework EdmProtectedBy annotation to handle multiple claims at complex * Process protection * Rework handling of ignored protected * Made inner class static * Fixing issue #60 * $count query not working correctly on complex collection attributes * Various small bugs - Reorg. pom.xml - Correct http status on empty result - Correct empty check for collection properties * Correct typo in interface JPAODataPagingProvider * Prepare JPAODataDatabaseTableFunction for paging * Change to HSQLDB * Remove function from sql-file to work around problems with Derby * Correct NullPointerException EdmEntitySetResult * Determine result of create dependent based on before image * EntityType getAttribute did not return value for embedded id * Provide CUD example and correct query status codes * Correct query response * Maven Archetype for Spring based service * Upgrade to Junit5 to get support for Java > 1.8 * Extract interface for better unit test support - Cleanup tests * Clean-up interface implementation * Add SQL function handling * Complete DB function changes * Clean-up test class * Clean-up test class * Update Version number * Update Version number * Additional test for API classes * Enable suppress of wildcard in metadata * Enable wildcards during query processing * Increase information on error during filter * Support of PUT on collection properties and primitive properties * Fix Null Pointer on PATCH with return != minimal * Claims where not respected by queries issue #69 part one - /$count - ?$count=true - paging queries * Claims where not respected by queries issue #69 part two - $filter - Update on Olingo 4.6.0 * Restrict the DISTINCT to protections only * Increase test coverage - New tests - Rework vocabulary handling * Cleanup Vocabularies II - Add Action and Function - Remove NavigationProperty and dependent * Additional test and solution of issue #78 * Enable new annotation EdmVisibleFor at properties * Introduction of Request Context - Deprecation of two variants of JPAODataGetHandler.process - Increase test coverage * Restrict EdmVisiableFor to nullable non key attributes * Skip properties from selection that do not belong to provided group * Handle collection properties and navigation path * Enable groups at complex collections * Handle OrderBy clause * Correct unit test * Rework test containing images * Rework context handling - Move of cud handler to request context - Move of DebugSupport to request context (is request specific because of isUserAuthorized) - Introduction of builder for Service Context to get a leaner creation of handler * Providing groups during modifying requests * Re-enable old shortcut with late metadata provisioning * Update pom for missing jackson dependency * Update Archetype to version 0.3.4 * Update Version * Extension of session context, so an emf can be provided * Ignore annotation qualified if empty * Go back to Olingo JSON deserializer * Add qualifier to annotation * Increase release * Clean-up JPAEdmNameBuilder * Preparation of custom name builder - Create public interface - replace class by new interface * Revoke test adoption * Providing custome name builder * Update annotation EdmFunction * Increase release * Adopt archetype - Simplify service - Add integration test * Modify example did not persist on create * Deep Insert did not responded deep * Always select ETag * Complete ETag handling * Missing Context Changes * Reset unit test to current pushed state * Increase test coverage * Adopt test to real number of complex types * Enable V4.01 JSON format as request and response * Additional Integration tests support OData V4.01 JSON * Allow usage of different types of transaction * Increase Spring support * Bugfix/issue83 (#120) * Update Version * Extension of session context, so an emf can be provided * Preparation of custom name builder - Create public interface - replace class by new interface * Revoke test adoption * Providing custome name builder * Update annotation EdmFunction * Increase release * Adopt archetype - Simplify service - Add integration test * Modify example did not persist on create * Deep Insert did not responded deep * Always select ETag * Complete ETag handling * Missing Context Changes * Reset unit test to current pushed state * Increase test coverage * Adopt test to real number of complex types * Enable V4.01 JSON format as request and response * Additional Integration tests support OData V4.01 JSON * Allow usage of different types of transaction * Increase Spring support * Restrict $expand select by key range * Support root with navigation like AdministrativeDivision(...)/Children * Protect dilution of test coverage by test package (#133) * Increase release * Increase release (#136) * Protect dilution of test coverage by test package (#135) * Remove deprecated artifacts (#134) * Remove deprecated artefacts * Missing test adoptions * Upgrade Olingo version and processor version * Feature/transient fields (#137) * Increase release * Upgrade Olingo version and processor version * Prevent NPE on expand empty result (#138) * Correct SonarQube and SpotBug hints * Feature/transient fields (#139) * Increase release * Upgrade Olingo version and processor version * Correct SonarQube and SpotBug hints * SpotBugs and clean-ups * Build metadata I * First draft of criteria builder and query implementation (#140) * First draft of criteria builder and query implementation * Add Transient * First join version * Correct structured type * Test adoption was missing * Update criteria builder * Solve enum error * Support aggregation function * Correct buildInverseJoinColumns() error * Add Test buildInverseJoinColumns() error * Enable table join without entity type * Correct Error table name * Own test for JPAEdmProvider and correct name builder error * Additional test * Support parallel processing of batch requests * Complete synchronized creation of metadata * Enable transient field calculator * Suppress transient fields at $filter and $orderby * Enable transient collections and collections with transient attributes * Additional tests for changing operations * Enable absolute path in url --- README.md | 2 +- jpa-archetype/jpa-archetype-spring/pom.xml | 36 + .../META-INF/maven/archetype-metadata.xml | 50 + .../resources/archetype-resources/pom.xml | 124 ++ .../src/main/java/SpringApp.java | 12 + .../config/EclipseLinkJpaConfiguration.java | 76 + .../java/config/ProcessorConfiguration.java | 31 + .../main/java/controller/ODataController.java | 33 + .../src/main/java/model/EntityTemplate.java | 59 + .../main/java/model/ValueObjectTemplate.java | 52 + .../java/model/ValueObjectTemplateKey.java | 56 + .../src/main/resources/application-test.yml | 25 + .../src/main/resources/application.yml | 25 + .../main/resources/db/migration/V1_0__jpa.sql | 10 + .../src/test/java/AppTest.java | 20 + .../java/integrationtest/ControllerTest.java | 158 ++ .../requests/CreateEntityViaBatch.txt | 38 + jpa-archetype/pom.xml | 21 + jpa-tutorial/.gitignore | 1 + jpa/.classpath | 26 - jpa/.gitignore | 7 + jpa/odata-jpa-annotation/.classpath | 27 - jpa/odata-jpa-annotation/.gitignore | 4 + .../.settings/org.eclipse.jdt.core.prefs | 9 +- .../org.eclipse.wst.common.component | 5 - ....eclipse.wst.common.project.facet.core.xml | 2 +- jpa/odata-jpa-annotation/pom.xml | 57 +- .../core/edm/annotation/EdmAnnotation.java | 2 +- .../core/edm/annotation/EdmEnumeration.java | 62 + .../core/edm/annotation/EdmFunction.java | 7 +- .../core/edm/annotation/EdmProtectedBy.java | 40 + .../core/edm/annotation/EdmProtections.java | 19 + .../core/edm/annotation/EdmTransient.java | 34 + .../EdmTransientPropertyCalculator.java | 45 + .../core/edm/annotation/EdmVisibleFor.java | 29 + .../odata/v4/core/annotation/Immutable.java | 16 + jpa/odata-jpa-coverage/pom.xml | 80 + jpa/odata-jpa-metadata/.classpath | 37 - jpa/odata-jpa-metadata/.gitignore | 5 + .../.settings/org.eclipse.jdt.core.prefs | 9 +- .../org.eclipse.wst.common.component | 6 - ....eclipse.wst.common.project.facet.core.xml | 2 +- jpa/odata-jpa-metadata/model/.gitignore | 3 + jpa/odata-jpa-metadata/pom.xml | 33 +- .../jpa/metadata/api/JPAEdmProvider.java | 172 +- .../metadata/api/JPAEntityManagerFactory.java | 15 +- .../jpa/metadata/api/JPAJoinColumn.java | 17 + .../annotation/AbstractVocabularyReader.java | 70 + .../core/edm/mapper/annotation/Action.java | 43 + .../core/edm/mapper/annotation/AppliesTo.java | 20 +- .../edm/mapper/annotation/ComplexType.java | 148 +- .../mapper/annotation/EntityKeyElement.java | 23 - .../edm/mapper/annotation/EntityType.java | 132 -- .../core/edm/mapper/annotation/EnumType.java | 96 +- .../core/edm/mapper/annotation/Function.java | 53 + .../core/edm/mapper/annotation/Member.java | 28 +- .../mapper/annotation/NavigationProperty.java | 148 -- .../core/edm/mapper/annotation/Parameter.java | 62 + .../core/edm/mapper/annotation/Property.java | 185 +- .../edm/mapper/annotation/PropertyRef.java | 24 - .../annotation/ReferentialConstraint.java | 31 - .../edm/mapper/annotation/ReturnType.java | 56 + .../core/edm/mapper/annotation/Schema.java | 172 +- .../edm/mapper/annotation/SchemaReader.java | 68 +- .../core/edm/mapper/annotation/Term.java | 160 +- .../edm/mapper/annotation/TermReader.java | 63 +- .../edm/mapper/annotation/TypeDefinition.java | 120 +- .../core/edm/mapper/api/JPAAction.java | 4 +- .../mapper/api/JPAAssociationAttribute.java | 5 +- .../edm/mapper/api/JPAAssociationPath.java | 26 +- .../core/edm/mapper/api/JPAAttribute.java | 58 +- .../mapper/api/JPACollectionAttribute.java | 27 + .../mapper/api/JPADescriptionAttribute.java | 9 +- .../edm/mapper/api/JPAEdmNameBuilder.java | 103 + .../core/edm/mapper/api/JPAElement.java | 16 +- .../core/edm/mapper/api/JPAEntityType.java | 30 +- .../mapper/api/JPAEnumerationAttribute.java | 27 + .../core/edm/mapper/api/JPAFunction.java | 2 + .../core/edm/mapper/api/JPAJoinTable.java | 30 + .../metadata/core/edm/mapper/api/JPAPath.java | 39 +- .../edm/mapper/api/JPAProtectionInfo.java | 32 + .../edm/mapper/api/JPAServiceDocument.java | 24 +- .../edm/mapper/api/JPAStructuredType.java | 115 +- .../exception/ODataJPAModelException.java | 45 +- .../IntermediateModelItemAccess.java | 9 +- .../IntermediateNavigationPropertyAccess.java | 5 +- .../extention/IntermediatePropertyAccess.java | 11 +- .../mapper/impl/DefaultEdmPostProcessor.java | 19 +- .../IntermediatOperationResultParameter.java | 18 +- .../impl/IntermediateActionFactory.java | 5 +- .../impl/IntermediateCollectionProperty.java | 341 ++++ .../mapper/impl/IntermediateComplexType.java | 26 +- .../impl/IntermediateDataBaseFunction.java | 96 +- .../impl/IntermediateDescriptionProperty.java | 283 ++- .../impl/IntermediateEmbeddedIdProperty.java | 26 +- .../impl/IntermediateEntityContainer.java | 56 +- .../mapper/impl/IntermediateEntitySet.java | 11 +- .../mapper/impl/IntermediateEntityType.java | 305 ++- .../impl/IntermediateEnumerationType.java | 186 +- .../edm/mapper/impl/IntermediateFunction.java | 27 +- .../impl/IntermediateFunctionFactory.java | 7 +- .../mapper/impl/IntermediateJavaAction.java | 107 +- .../mapper/impl/IntermediateJavaFunction.java | 57 +- .../mapper/impl/IntermediateJoinColumn.java | 17 +- .../mapper/impl/IntermediateJoinTable.java | 191 ++ .../mapper/impl/IntermediateModelElement.java | 110 +- .../impl/IntermediateNavigationProperty.java | 337 +++- .../mapper/impl/IntermediateOperation.java | 1 + .../impl/IntermediateOperationFactory.java | 3 +- .../impl/IntermediateOperationHelper.java | 33 +- .../impl/IntermediateOperationParameter.java | 15 +- .../edm/mapper/impl/IntermediateProperty.java | 644 ++++--- .../mapper/impl/IntermediateReferences.java | 36 +- .../edm/mapper/impl/IntermediateSchema.java | 194 +- .../impl/IntermediateServiceDocument.java | 103 +- .../impl/IntermediateSimpleProperty.java | 164 ++ .../impl/IntermediateStructuredType.java | 773 ++++++-- .../mapper/impl/JPAAssociationPathImpl.java | 206 +- .../mapper/impl/JPADefaultEdmNameBuilder.java | 136 ++ .../edm/mapper/impl/JPAEdmNameBuilder.java | 227 --- .../core/edm/mapper/impl/JPANameBuilder.java | 9 +- .../mapper/impl/JPAOnConditionItemImpl.java | 5 + .../core/edm/mapper/impl/JPAPathImpl.java | 89 +- .../edm/mapper/impl/JPAProtectionInfo.java | 43 + .../impl/JPAServiceDocumentFactory.java | 14 +- .../edm/mapper/impl/JPATypeConvertor.java | 62 +- .../core/edm/mapper/impl/ODataEnum.java | 5 - .../edm/mapper/impl/ODataEnumerationType.java | 5 - .../mapper/impl/OffsetDateTimeConverter.java | 29 + .../metadata-exceptions-i18n.properties | 104 +- .../metadata-exceptions-i18n_de.properties | 45 - .../jpa/metadata/api/TestJPAEdmProvider.java | 314 +++ .../mapper/annotation/TestAnnotationPOJO.java | 10 +- .../mapper/annotation/TestSchemaReader.java | 393 +++- .../edm/mapper/annotation/TestTermReader.java | 71 +- .../TestODataJPAMessageTextBuffer.java | 14 +- .../exception/TestODataJPAModelException.java | 9 +- .../edm/mapper/impl/CustomJPANameBuilder.java | 76 + .../core/edm/mapper/impl/TestHelper.java | 86 +- .../impl/TestIntermediateActionFactory.java | 22 +- .../TestIntermediateCollectionProperty.java | 211 ++ .../impl/TestIntermediateComplexType.java | 196 +- .../impl/TestIntermediateContainer.java | 84 +- .../TestIntermediateDataBaseFunction.java | 165 +- .../TestIntermediateDescriptionProperty.java | 307 ++- .../TestIntermediateEmbeddedIdProperty.java | 64 + .../impl/TestIntermediateEntitySet.java | 41 +- .../impl/TestIntermediateEntityType.java | 370 +++- .../impl/TestIntermediateEnumerationType.java | 147 +- .../impl/TestIntermediateFunctionFactory.java | 22 +- .../impl/TestIntermediateJavaAction.java | 115 +- .../impl/TestIntermediateJavaFunction.java | 127 +- .../impl/TestIntermediateModelElement.java | 82 + .../TestIntermediateNavigationProperty.java | 417 +++- .../mapper/impl/TestIntermediateProperty.java | 384 ---- .../impl/TestIntermediateReferences.java | 33 +- .../mapper/impl/TestIntermediateSchema.java | 54 +- .../impl/TestIntermediateServiceDocument.java | 276 ++- .../impl/TestIntermediateSimpleProperty.java | 706 +++++++ .../impl/TestIntermediateWrongAnnotation.java | 179 ++ .../mapper/impl/TestJPAEdmNameBuilder.java | 15 +- .../impl/TestJPAOnConditionItemImpl.java | 42 + .../core/edm/mapper/impl/TestJPAPath.java | 160 +- .../mapper/impl/TestJPAProtectionInfo.java | 64 + .../edm/mapper/impl/TestJPATypeConvertor.java | 339 ++++ .../core/edm/mapper/impl/TestMappingRoot.java | 13 +- .../impl/TestOffsetDateTimeConverter.java | 56 + .../core/edm/mapper/testaction/Actions.java | 30 + .../mapper/testaction/function/Function.java | 14 + .../edm/mapper/testobjects/DayOfWeek.java | 19 +- .../testobjects/ExampleJavaActions.java | 11 +- .../testobjects/ExampleJavaFunctions.java | 18 +- .../testobjects/ExampleJavaOneFunction.java | 2 +- .../edm/mapper/testobjects/FileAccess.java | 22 + .../testobjects/FileAccessConverter.java | 28 + .../edm/mapper/testobjects/WrongMember.java | 18 + .../testobjects/WrongMemberConverter.java | 28 + .../edm/mapper/testobjects/WrongType.java | 20 + .../testobjects/WrongTypeConverter.java | 19 + .../core/edm/mapper/util/MemberDouble.java | 63 + .../annotations/Org.OData.Aggregation.V1.xml | 202 ++ .../annotations/Org.OData.Capabilities.V1.xml | 774 ++++---- .../annotations/Org.OData.Core.V1.xml | 251 ++- .../Org.OData.Repeatability.V1.xml | 85 + .../annotations/Org.Olingo.Test.V1.xml | 50 +- .../src/test/resources/annotations/empty.xml | 0 .../src/test/resources/metadata/TripPin.xml | 2 +- jpa/odata-jpa-processor-cb/.gitignore | 14 + jpa/odata-jpa-processor-cb/pom.xml | 36 + .../cb/api/EntityManagerFactoryWrapper.java | 99 + .../processor/cb/api/ProcessorSelection.java | 77 + .../processor/cb/api/ProcessorSubquery.java | 20 + .../jpa/processor/cb/api/SqlAggregation.java | 19 + .../jpa/processor/cb/api/SqlArithmetic.java | 21 + .../jpa/processor/cb/api/SqlConvertable.java | 8 + .../jpa/processor/cb/api/SqlJoinType.java | 44 + .../jpa/processor/cb/api/SqlKeyWords.java | 39 + .../jpa/processor/cb/api/SqlNullCheck.java | 18 + .../processor/cb/api/SqlStringFunctions.java | 23 + .../jpa/processor/cb/api/SqlSubQuery.java | 20 + .../processor/cb/api/SqlTimeFunctions.java | 19 + .../cb/exeptions/InternalServerError.java | 12 + .../cb/exeptions/NotImplementedException.java | 10 + .../processor/cb/impl/AbstractJoinImp.java | 206 ++ .../jpa/processor/cb/impl/AliasBuilder.java | 19 + .../processor/cb/impl/CollectionJoinImpl.java | 119 ++ .../cb/impl/CriteriaBuilderImpl.java | 1691 +++++++++++++++++ .../processor/cb/impl/CriteriaQueryImpl.java | 758 ++++++++ .../cb/impl/EntityManagerWrapper.java | 301 +++ .../jpa/processor/cb/impl/ExpressionImpl.java | 460 +++++ .../jpa/processor/cb/impl/FromImpl.java | 585 ++++++ .../jpa/processor/cb/impl/JoinTableJoin.java | 95 + .../jpa/processor/cb/impl/OrderImpl.java | 40 + .../processor/cb/impl/ParameterBuffer.java | 36 + .../jpa/processor/cb/impl/PathImpl.java | 231 +++ .../jpa/processor/cb/impl/PathJoin.java | 60 + .../jpa/processor/cb/impl/PredicateImpl.java | 385 ++++ .../jpa/processor/cb/impl/RootImpl.java | 20 + .../jpa/processor/cb/impl/SimpleJoin.java | 46 + .../jpa/processor/cb/impl/SubqueryImpl.java | 296 +++ .../jpa/processor/cb/impl/TupleImpl.java | 169 ++ .../jpa/processor/cb/impl/TypedQueryImpl.java | 311 +++ .../cb/joiner/ExpressionCollector.java | 48 + .../processor/cb/joiner/ExpressionJoiner.java | 42 + .../cb/joiner/StringBuilderCollector.java | 60 + .../cb/joiner/StringBuilderJoiner.java | 39 + .../processor/cb/impl/AliasBuilderTest.java | 26 + .../processor/cb/impl/BuilderBaseTest.java | 33 + .../cb/impl/CriteriaBuilderDerbyTest.java | 38 + .../cb/impl/CriteriaBuilderH2Test.java | 36 + .../cb/impl/CriteriaBuilderHSQLDBTest.java | 36 + .../cb/impl/CriteriaBuilderImplTest.java | 785 ++++++++ .../cb/impl/CriteriaBuilderOverallTest.java | 282 +++ .../cb/impl/CritertaQueryImplTest.java | 141 ++ .../jpa/processor/cb/impl/FromImplTest.java | 196 ++ .../jpa/processor/cb/impl/PathImplTest.java | 54 + .../jpa/processor/cb/impl/TupleImplTest.java | 137 ++ jpa/odata-jpa-processor-parallel/.gitignore | 1 + jpa/odata-jpa-processor-parallel/pom.xml | 45 + .../JPAODataBatchParallelRequestGroup.java | 66 + .../core/api/JPAODataBatchRequestGroup.java | 16 + .../JPAODataBatchSequentialRequestGroup.java | 48 + .../api/JPAODataParallelBatchProcessor.java | 99 + ...JPAODataParallelBatchProcessorFactory.java | 14 + .../exception/ODataJPABatchException.java | 36 + .../ODataJPABatchRuntimeException.java | 15 + .../processor-exceptions-i18n.properties | 21 + ...AODataBatchSequentialRequestGroupTest.java | 104 + ...JPAODataBatchAbstractRequestGroupTest.java | 61 + ...JPAODataBatchParallelRequestGroupTest.java | 146 ++ ...AODataBatchSequentialRequestGroupTest.java | 88 + ...ParallelBatchProcessorIntegrationTest.java | 143 ++ .../JPAODataParallelBatchProcessorTest.java | 218 +++ .../test/util/IntegrationTestHelper.java | 113 ++ jpa/odata-jpa-processor/.classpath | 33 - jpa/odata-jpa-processor/.gitignore | 5 + .../.settings/org.eclipse.jdt.core.prefs | 9 +- .../org.eclipse.wst.common.component | 13 +- ....eclipse.wst.common.project.facet.core.xml | 2 +- jpa/odata-jpa-processor/pom.xml | 146 +- .../api/JPAAbstractCUDRequestHandler.java | 10 +- .../core/api/JPACUDRequestHandler.java | 72 + .../jpa/processor/core/api/JPAClaimsPair.java | 43 + .../api/JPADefaultBatchProcessorFactory.java | 11 + .../core/api/JPADefaultErrorProcessor.java | 33 + .../processor/core/api/JPAEmptyDebugger.java | 23 - .../processor/core/api/JPAErrorProcessor.java | 8 + .../core/api/JPAErrorProcessorWrapper.java | 35 + .../core/api/JPAODataBatchProcessor.java | 209 +- .../api/JPAODataBatchProcessorFactory.java | 9 + .../core/api/JPAODataCRUDContext.java | 7 - .../core/api/JPAODataCRUDContextAccess.java | 64 + .../core/api/JPAODataCRUDHandler.java | 23 +- .../core/api/JPAODataCRUDRequestContext.java | 7 + .../core/api/JPAODataClaimProvider.java | 16 + .../core/api/JPAODataClaimsProvider.java | 37 + .../core/api/JPAODataContextImpl.java | 151 -- .../core/api/JPAODataDatabaseProcessor.java | 5 + .../JPAODataDefaultTransactionFactory.java | 98 + .../core/api/JPAODataGetContext.java | 53 - .../core/api/JPAODataGetHandler.java | 160 +- .../core/api/JPAODataGroupProvider.java | 17 + .../core/api/JPAODataGroupsProvider.java | 43 + .../jpa/processor/core/api/JPAODataPage.java | 34 + .../core/api/JPAODataPagingProvider.java | 33 + .../core/api/JPAODataRequestContext.java | 21 + .../api/JPAODataRequestContextAccess.java | 29 +- .../core/api/JPAODataRequestProcessor.java | 306 +-- .../core/api/JPAODataServiceContext.java | 393 ++++ .../api/JPAODataServiceDocumentProcessor.java | 72 + .../api/JPAODataSessionContextAccess.java | 29 - .../core/api/JPAODataTransactionFactory.java | 48 + .../core/api/JPAServiceDebugger.java | 9 +- .../example/JPAExampleCUDRequestHandler.java | 195 ++ .../example/JPAExampleModifyException.java | 33 + .../api/example/JPAExamplePagingProvider.java | 120 ++ .../core/converter/JPACollectionResult.java | 18 + .../converter/JPAComplexResultConverter.java | 5 +- .../core/converter/JPAExpandResult.java | 20 +- .../core/converter/JPAResultConverter.java | 14 + .../JPAStructuredResultConverter.java | 121 +- .../core/{modify => converter}/JPATuple.java | 24 +- .../converter/JPATupleAbstractConverter.java | 241 --- .../converter/JPATupleChildConverter.java | 298 +++ .../JPATupleCollectionConverter.java | 138 ++ .../JPATupleExpandResultConverter.java | 78 - .../converter/JPATupleResultConverter.java | 316 ++- .../JPAAbstractDatabaseProcessor.java | 154 ++ .../database/JPADefaultDatabaseProcessor.java | 132 +- .../database/JPAODataDatabaseOperations.java | 5 +- .../JPAODataDatabaseProcessorFactory.java | 27 +- .../core/database/JPAODataDatabaseSearch.java | 20 +- .../JPAODataDatabaseTableFunction.java | 8 +- .../database/JPA_DERBY_DatabaseProcessor.java | 90 +- .../database/JPA_HANA_DatabaseProcessor.java | 147 -- .../JPA_HSQLDB_DatabaseProcessor.java | 104 +- .../JPA_POSTSQL_DatabaseProcessor.java | 64 + .../exception/ODataJPAFilterException.java | 7 +- .../ODataJPAIllegalAccessException.java | 17 + .../ODataJPAInvocationTargetException.java | 43 + .../exception/ODataJPAProcessException.java | 22 +- .../exception/ODataJPAProcessorException.java | 155 +- .../exception/ODataJPAQueryException.java | 16 +- .../ODataJPASerializerException.java | 2 +- .../ODataJPATransactionException.java | 33 + .../core/exception/ODataJPAUtilException.java | 2 +- .../core/filter/JPAAbstractFilter.java | 41 +- .../filter/JPAAggregationOperationImp.java | 13 +- .../core/filter/JPAArithmeticOperatorImp.java | 7 +- .../core/filter/JPABinaryExpression.java | 30 + .../core/filter/JPABooleanOperatorImp.java | 12 +- .../core/filter/JPAComparisonOperatorImp.java | 8 +- .../filter/JPAEnumerationBasedOperator.java | 14 + .../core/filter/JPAEnumerationOperator.java | 63 + .../core/filter/JPAExistsOperation.java | 69 +- .../processor/core/filter/JPAExpression.java | 11 + .../core/filter/JPAExpressionOperator.java | 11 +- .../core/filter/JPAExpressionVisitor.java | 4 +- .../core/filter/JPAFilterComplier.java | 3 +- .../core/filter/JPAFilterComplierAccess.java | 15 + .../core/filter/JPAFilterCrossComplier.java | 75 +- .../core/filter/JPAFilterElementComplier.java | 34 +- .../core/filter/JPAFilterExpression.java | 18 +- .../core/filter/JPAFunctionOperator.java | 17 +- .../core/filter/JPALambdaAllOperation.java | 5 + .../core/filter/JPALambdaAnyOperation.java | 9 +- .../core/filter/JPALambdaOperation.java | 23 +- .../core/filter/JPALiteralOperator.java | 53 +- .../core/filter/JPAMemberOperator.java | 117 +- .../core/filter/JPAMemberVisitor.java | 9 +- .../core/filter/JPAMethodBasedExpression.java | 22 + .../processor/core/filter/JPAMethodCall.java | 17 +- .../core/filter/JPAMethodCallImp.java | 27 +- .../core/filter/JPAMethodExpression.java | 40 + .../core/filter/JPANavigationOperation.java | 149 +- .../core/filter/JPAOperationConverter.java | 338 ++-- .../processor/core/filter/JPAOperator.java | 2 + .../core/filter/JPAPrimitiveTypeOperator.java | 7 + .../core/filter/JPAUnaryBooleanOperator.java | 1 + .../filter/JPAUnaryBooleanOperatorImp.java | 5 + .../core/filter/JPAVisitableExpression.java | 9 + .../jpa/processor/core/filter/JPAVisitor.java | 194 +- .../core/modify/JPACUDRequestHandler.java | 50 - .../core/modify/JPAConversionHelper.java | 370 ++-- .../core/modify/JPACreateResult.java | 69 +- .../core/modify/JPACreateResultFactory.java | 15 +- .../core/modify/JPAEntityBasedResult.java | 51 + .../modify/JPAEntityCollectionResult.java | 71 + .../modify/JPAEntityNavigationLinkResult.java | 67 +- .../core/modify/JPAEntityResult.java | 82 +- .../core/modify/JPAMapBaseResult.java | 53 + .../core/modify/JPAMapCollectionResult.java | 69 + .../modify/JPAMapNavigationLinkResult.java | 36 +- .../processor/core/modify/JPAMapResult.java | 71 +- .../core/modify/JPAUpdateResult.java | 4 +- .../JPAAbstractGetRequestProcessor.java | 5 +- .../JPAAbstractRequestProcessor.java | 15 +- .../processor/JPAActionRequestProcessor.java | 142 +- .../processor/JPACUDRequestProcessor.java | 579 ++++-- .../JPACoreDebugger.java} | 12 +- .../processor/JPACountRequestProcessor.java | 25 +- .../core/processor/JPAEmptyDebugger.java | 26 + .../JPAFunctionRequestProcessor.java | 92 +- .../processor/core/processor/JPALogger.java | 93 + .../core/processor/JPAModifyUtil.java | 424 ++++- .../JPANavigationRequestProcessor.java | 262 ++- .../processor/JPAODataRequestContextImpl.java | 345 ++++ .../JPAOperationRequestProcessor.java | 98 +- .../core/processor/JPAProcessorFactory.java | 163 +- .../core/processor/JPARequestContext.java | 43 +- .../core/processor/JPARequestEntity.java | 56 +- .../core/processor/JPARequestEntityImpl.java | 41 +- .../core/processor/JPARequestLink.java | 6 +- .../core/processor/JPARequestLinkImpl.java | 17 +- .../core/processor/JPARequestProcessor.java | 4 +- .../deserializer/JsonDeserializer.java | 854 --------- .../processor/deserializer/package-info.java | 8 - .../core/query/EdmEntitySetInfo.java | 4 + .../core/query/EdmEntitySetResult.java | 24 +- .../processor/core/query/ExpressionUtil.java | 34 +- .../core/query/JPAAbstractJoinQuery.java | 981 ++++++++++ .../core/query/JPAAbstractQuery.java | 215 ++- .../query/JPACollectionExpandWrapper.java | 120 ++ .../core/query/JPACollectionFilterQuery.java | 161 ++ .../core/query/JPACollectionItemInfo.java | 25 + .../core/query/JPACollectionJoinQuery.java | 338 ++++ .../core/query/JPACollectionQueryResult.java | 152 ++ .../core/query/JPAConvertableResult.java | 48 + .../processor/core/query/JPACountQuery.java | 16 + .../core/query/JPAExecutableQuery.java | 573 ------ .../core/query/JPAExpandItemInfo.java | 45 +- .../core/query/JPAExpandItemInfoFactory.java | 216 ++- .../core/query/JPAExpandItemWrapper.java | 9 +- .../core/query/JPAExpandJoinQuery.java | 417 ++++ .../core/query/JPAExpandLevelWrapper.java | 16 +- .../processor/core/query/JPAExpandQuery.java | 250 --- .../core/query/JPAExpandQueryResult.java | 212 ++- .../core/query/JPAInlineItemInfo.java | 44 + .../processor/core/query/JPAJoinQuery.java | 229 +++ .../processor/core/query/JPAKeyBoundary.java | 37 + .../jpa/processor/core/query/JPAKeyPair.java | 76 + .../core/query/JPANavigationFilterQuery.java | 147 +- .../JPANavigationInheritFilterQuery.java | 40 - .../query/JPANavigationProptertyInfo.java | 107 +- .../core/query/JPANavigationQuery.java | 274 ++- .../core/query/JPANoSelectionException.java | 15 + .../jpa/processor/core/query/JPAQuery.java | 165 +- .../core/query/SelectOptionUtil.java | 51 + .../core/query/SelectionPathInfo.java | 88 + .../olingo/jpa/processor/core/query/Util.java | 207 +- .../serializer/JPAOperationSerializer.java | 3 +- .../core/serializer/JPASerializeComplex.java | 119 +- .../JPASerializeComplexCollection.java | 48 +- .../core/serializer/JPASerializeCount.java | 6 + .../core/serializer/JPASerializeCreate.java | 171 +- .../core/serializer/JPASerializeEntity.java | 71 +- .../JPASerializeEntityCollection.java | 57 +- .../core/serializer/JPASerializeFunction.java | 24 +- .../serializer/JPASerializePrimitive.java | 74 +- .../JPASerializePrimitiveAbstract.java | 19 +- .../JPASerializePrimitiveCollection.java | 43 +- .../core/serializer/JPASerializeValue.java | 25 +- .../core/serializer/JPASerializer.java | 19 +- .../core/serializer/JPASerializerFactory.java | 159 +- .../example-exceptions-i18n.properties | 21 + .../processor-exceptions-i18n.properties | 59 +- .../processor/core/api/JPAClaimsPairTest.java | 35 + .../core/api/JPAODataBatchProcessorTest.java | 165 +- .../core/api/JPAODataClaimsProviderTest.java | 58 + .../core/api/JPAODataContextAccessDouble.java | 32 +- ...JPAODataDefaultTransactionFactoryTest.java | 180 ++ .../processor/core/api/TestBatchRequests.java | 18 +- .../api/TestJPAAbstractCUDRequestHandler.java | 44 + .../core/api/TestJPAODataGetHandler.java | 158 ++ .../core/api/TestJPAODataGroupsProvider.java | 65 + .../api/TestJPAODataRequestProcessor.java | 143 ++ .../TestJPAODataServiceContextBuilder.java | 334 ++++ .../TestJPAODataServiceDocumentProcessor.java | 80 + .../JPAExampleCUDRequestHandlerTest.java | 525 +++++ .../example/JPAExamplePagingProviderTest.java | 298 +++ .../TestJPADefaultDatabaseProcessor.java | 122 ++ .../TestJPA_DERBY_DatabaseProcessor.java | 44 + .../TestJPA_HSQLDB_DatabaseProcessor.java | 44 + .../TestJPA_POSTSQL_DatabaseProcessor.java | 43 + .../TestJPA_XXX_DatabaseProcessor.java | 396 ++++ .../TestODataJPAProcessorException.java | 11 +- .../filter/TestJPAArithmeticOperator.java | 16 +- .../filter/TestJPACustomScalarFunctions.java | 34 +- .../core/filter/TestJPAFunctionOperator.java | 14 +- .../filter/TestJPAOperationConverter.java | 15 +- .../core/filter/TestJPAQueryWhereClause.java | 588 +++++- .../processor/core/filter/TestJPAVisitor.java | 17 +- .../core/filter/TestRetrieveSingleEntity.java | 4 +- .../core/modify/TestJPACUDRequestHelper.java | 815 ++++++-- .../core/modify/TestJPAConversionHelper.java | 30 +- .../modify/TestJPAConversionHelperEntity.java | 9 +- .../modify/TestJPAConversionHelperMap.java | 18 +- .../core/modify/TestJPACreateResult.java | 239 ++- .../core/modify/TestJPAEntityResult.java | 194 +- .../core/modify/TestJPAMapResult.java | 202 +- .../core/processor/JPACoreDebuggerTest.java | 56 + .../processor/TestCreateDeltaBasedResult.java | 162 ++ .../processor/TestCreateRequestEntity.java | 221 ++- .../processor/TestJPAActionProcessor.java | 272 ++- .../core/processor/TestJPAClearProcessor.java | 279 ++- .../processor/TestJPACreateProcessor.java | 459 ++++- .../processor/TestJPADeleteProcessor.java | 260 ++- .../processor/TestJPAModifyProcessor.java | 189 +- .../TestJPAODataRequestContextImpl.java | 300 +++ .../processor/TestJPARequestLinkImpl.java | 22 +- .../processor/TestJPAUpdateProcessor.java | 404 +++- .../core/processor/TestModifyUtil.java | 278 ++- .../core/query/TestEdmEntitySetResult.java | 88 + .../core/query/TestJPAExpandJoinQuery.java | 259 +++ .../query/TestJPAExpandQueryCreateResult.java | 96 +- .../core/query/TestJPAExpandQueryResult.java | 229 +++ .../core/query/TestJPAExpandResult.java | 156 -- .../processor/core/query/TestJPAFunction.java | 63 +- .../core/query/TestJPAFunctionDB.java | 149 ++ .../core/query/TestJPAFunctionJava.java | 38 +- .../core/query/TestJPAFunctionSerializer.java | 68 +- .../query/TestJPAInstanceResultConverter.java | 14 +- .../processor/core/query/TestJPAKeyPair.java | 198 ++ .../core/query/TestJPAProcessorExpand.java | 288 ++- .../TestJPAQueryBuildSelectionPathList.java | 282 +++ .../core/query/TestJPAQueryCollection.java | 356 ++++ .../core/query/TestJPAQueryFromClause.java | 209 +- .../query/TestJPAQueryJSONAnnotations.java | 79 + .../core/query/TestJPAQueryNavigation.java | 145 +- .../query/TestJPAQueryNavigationCount.java | 23 +- .../TestJPAQueryODataVersionSupport.java | 118 ++ .../core/query/TestJPAQueryOrderByClause.java | 116 +- .../core/query/TestJPAQuerySelectByPath.java | 165 +- .../core/query/TestJPAQuerySelectClause.java | 245 ++- .../TestJPAQuerySelectWithGroupClause.java | 133 ++ .../query/TestJPAQueryWithProtection.java | 561 ++++++ .../core/query/TestJPAServerDrivenPaging.java | 330 ++++ .../query/TestJPATupleChildConverter.java | 327 ++++ ...estJPATupleChildConverterCompoundKey.java} | 55 +- .../query/TestJPATupleResultConverter.java | 240 --- .../core/query/TestSelectionPathInfo.java | 90 + .../TestJPAOperationSerializer.java | 40 + .../serializer/TestJPASerializeComplex.java | 71 + .../serializer/TestJPASerializeCreate.java | 44 + .../serializer/TestJPASerializeEntity.java | 55 + .../TestJPASerializeEntityCollection.java | 59 + .../serializer/TestJPASerializePrimitive.java | 70 + .../serializer/TestJPASerializeValue.java | 85 + .../core/serializer/TestJPASerializer.java | 124 ++ .../TestJPASerializerCollection.java | 137 ++ .../TestJPASerializerComplexCollection.java | 42 + .../TestJPASerializerPrimitiveCollection.java | 43 + .../BusinessPartnerRoleWithoutSetter.java | 13 + .../core/testobjects/FileAccess.java | 22 + .../core/testobjects/FileAccessConverter.java | 28 + ...HeaderParamTransientPropertyConverter.java | 27 + .../OrganizationWithoutGetter.java | 17 + .../testobjects/TestFunctionParameter.java | 6 +- .../testobjects/TestFunctionReturnType.java | 45 +- .../TestJavaActionNoParameter.java | 22 +- .../core/testobjects/TestJavaActions.java | 25 +- ...woParameterTransientPropertyConverter.java | 35 + .../core/util/CountQueryMatcher.java | 34 + .../core/util/EdmEntitySetDouble.java | 12 +- .../core/util/EdmEntityTypeDouble.java | 8 +- .../util/EdmNavigationPropertyDouble.java | 2 +- .../core/util/EdmPropertyDouble.java | 8 +- .../processor/core/util/ExpandItemDouble.java | 8 +- .../core/util/ExpandOptionDouble.java | 2 +- .../core/util/IntegrationTestHelper.java | 114 +- .../core/util/JPAEntityTypeDouble.java | 214 +++ .../core/util/SelectOptionDouble.java | 46 +- .../core/util/ServiceMetadataDouble.java | 22 +- .../jpa/processor/core/util/TestBase.java | 22 +- .../processor/core/util/TestGroupBase.java | 104 + .../jpa/processor/core/util/TestHelper.java | 10 +- .../processor/core/util/TestQueryBase.java | 105 + .../jpa/processor/core/util/TupleDouble.java | 12 +- .../processor/core/util/UriHelperDouble.java | 2 +- .../processor/core/util/UriInfoDouble.java | 18 +- .../core/util/UriInfoResourceDouble.java | 10 +- .../util/UriResourceNavigationDouble.java | 2 +- .../core/util/UriResourcePropertyDouble.java | 3 +- .../ComplexSerializerOptionsMatcher.java | 17 + .../core/util/matcher/CountQueryMatcher.java | 34 + ...ityCollectionSerializerOptionsMatcher.java | 18 + .../EntitySerializerOptionsMatcher.java | 17 + .../core/util/matcher/InputStreamMatcher.java | 34 + .../PrimitiveSerializerOptionsMatcher.java | 17 + .../matcher/SerializerOptionsMatcher.java | 29 + jpa/odata-jpa-spring-support/pom.xml | 22 + ...itional-spring-configuration-metadata.json | 14 + jpa/odata-jpa-test/.classpath | 32 - jpa/odata-jpa-test/.gitignore | 4 + .../.settings/org.eclipse.jdt.core.prefs | 9 +- .../org.eclipse.wst.common.component | 6 - ....eclipse.wst.common.project.facet.core.xml | 3 +- jpa/odata-jpa-test/pom.xml | 202 +- .../errormodel/AdministrativeInformation.java | 53 + .../core/errormodel/ChangeInformation.java | 28 + .../CollectionAttributeProtected.java | 76 + .../errormodel/ComplextProtectedNoPath.java | 64 + .../ComplextProtectedWrongPath.java | 63 + .../core/errormodel/CompoundKey.java | 31 + .../errormodel/DummyPropertyCalculator.java | 37 + .../errormodel/EmbeddedKeyPartOfGroup.java | 30 + .../core/errormodel/KeyPartOfGroup.java | 29 + .../core/errormodel/MandatoryPartOfGroup.java | 39 + .../NavigationAttributeProtected.java | 62 + .../NavigationPropertyPartOfGroup.java | 39 + .../PersonDeepCollectionProtected.java | 39 + .../jpa/processor/core/errormodel/Team.java | 24 + ...thTransientCalculatorConstructorError.java | 23 + .../TeamWithTransientCalculatorError.java | 23 + .../TeamWithTransientEmbeddableKey.java | 17 + .../errormodel/TeamWithTransientError.java | 23 + .../core/errormodel/TeamWithTransientKey.java | 24 + ...ientPropertyCalculatorTwoConstructors.java | 32 + ...entPropertyCalculatorWrongConstructor.java | 33 + .../core/testmodel/ABCClassifiaction.java | 8 + .../core/testmodel/AccessRights.java | 22 + .../core/testmodel/AccessRightsConverter.java | 36 + .../core/testmodel/AddressDeepProtected.java | 18 + .../AddressDeepThreeProtections.java | 20 + .../testmodel/AdministrativeDivision.java | 238 ++- .../AdministrativeDivisionDescriptionKey.java | 26 +- .../testmodel/AdministrativeDivisionKey.java | 42 +- .../testmodel/AdministrativeInformation.java | 31 +- .../processor/core/testmodel/AssertList.java | 11 - .../core/testmodel/BestOrganization.java | 2 - .../core/testmodel/BusinessPartner.java | 77 +- .../testmodel/BusinessPartnerProtected.java | 116 ++ .../core/testmodel/BusinessPartnerRole.java | 47 +- .../testmodel/BusinessPartnerRoleKey.java | 10 + .../BusinessPartnerRoleProtected.java | 82 + .../BusinessPartnerRoleWithGroup.java | 100 + .../testmodel/BusinessPartnerWithGroups.java | 261 +++ .../core/testmodel/ChangeInformation.java | 18 +- .../testmodel/CollcetionInnerComplex.java | 42 + .../testmodel/CollcetionNestedComplex.java | 31 + .../CollcetionNestedComplexWithTransient.java | 38 + .../processor/core/testmodel/Collection.java | 77 + .../core/testmodel/CollectionDeep.java | 57 + .../CollectionFirstLevelComplex.java | 42 + .../testmodel/CollectionPartOfComplex.java | 55 + .../CollectionSecondLevelComplex.java | 59 + .../testmodel/CollectionWithTransient.java | 84 + .../jpa/processor/core/testmodel/Comment.java | 57 +- .../core/testmodel/CommunicationData.java | 1 + .../ComplexWithTransientComplexCollction.java | 30 + .../processor/core/testmodel/CountryKey.java | 22 +- .../core/testmodel/CountryRestriction.java | 45 + .../core/testmodel/DataSourceHelper.java | 64 +- .../core/testmodel/DateTimeConverter.java | 24 + .../core/testmodel/DeepProtectedExample.java | 31 + .../core/testmodel/DummyToBeIgnored.java | 22 +- .../core/testmodel/FullNameCalculator.java | 25 + .../processor/core/testmodel/ImageLoader.java | 122 +- .../core/testmodel/InhouseAddress.java | 65 + .../core/testmodel/InhouseAddressTable.java | 60 + .../testmodel/InhouseAddressWithGroup.java | 71 + .../InhouseAddressWithProtection.java | 62 + .../InhouseAddressWithThreeProtections.java | 64 + .../testmodel/InstanceRestrictionKey.java | 48 + .../processor/core/testmodel/JoinComplex.java | 22 + .../core/testmodel/JoinRelation.java | 13 + .../core/testmodel/JoinRelationKey.java | 61 + .../processor/core/testmodel/JoinSource.java | 36 + .../processor/core/testmodel/JoinTarget.java | 14 + .../core/testmodel/LogarithmCalculator.java | 32 + .../processor/core/testmodel/Membership.java | 22 + .../core/testmodel/MembershipKey.java | 56 + .../core/testmodel/Organization.java | 49 +- .../core/testmodel/OrganizationImage.java | 34 +- .../jpa/processor/core/testmodel/Person.java | 90 +- .../core/testmodel/PersonDeepProtected.java | 66 + .../testmodel/PersonDeepProtectedHidden.java | 55 + .../core/testmodel/PostalAddressData.java | 47 +- .../testmodel/PostalAddressDataWithGroup.java | 114 ++ .../testmodel/StreetPropertyCalculator.java | 27 + .../core/testmodel/SupportRelationship.java | 23 + .../jpa/processor/core/testmodel/Team.java | 24 + .../core/testmodel/TestDataConstants.java | 10 +- .../core/testmodel/TransientRefComplex.java | 33 + .../jpa/processor/core/testmodel/User.java | 53 + .../jpa/processor/core/util/Assertions.java | 67 + .../core/util/HttpRequestHeaderDouble.java | 33 +- .../core/util/HttpServletRequestDouble.java | 66 +- .../core/util/HttpServletResponseDouble.java | 4 +- .../core/util/ServletInputStreamDouble.java | 0 .../main/resources/META-INF/persistence.xml | 104 +- .../resources/db/migration/V1_0__olingo.sql | 300 ++- .../jpa/processor/test/TestAssociations.java | 18 +- .../processor/test/TestCriteriaBuilder.java | 120 +- .../test/TestEqualHashCodeMethods.java | 202 ++ .../TestEqualHashCodeMethodsErrorModel.java | 34 + .../TestEqualHashCodeMethodsTestModel.java | 91 + .../jpa/processor/test/TestFunctions.java | 24 +- .../processor/test/TestFunctionsHSQLDB.java | 16 +- .../test/TestStandardMethodsOfTestModel.java | 255 +++ jpa/pom.xml | 139 +- 681 files changed, 51777 insertions(+), 11998 deletions(-) create mode 100644 jpa-archetype/jpa-archetype-spring/pom.xml create mode 100644 jpa-archetype/jpa-archetype-spring/src/main/resources/META-INF/maven/archetype-metadata.xml create mode 100644 jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/pom.xml create mode 100644 jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/java/SpringApp.java create mode 100644 jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/java/config/EclipseLinkJpaConfiguration.java create mode 100644 jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/java/config/ProcessorConfiguration.java create mode 100644 jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/java/controller/ODataController.java create mode 100644 jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/java/model/EntityTemplate.java create mode 100644 jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/java/model/ValueObjectTemplate.java create mode 100644 jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/java/model/ValueObjectTemplateKey.java create mode 100644 jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/resources/application-test.yml create mode 100644 jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/resources/application.yml create mode 100644 jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/resources/db/migration/V1_0__jpa.sql create mode 100644 jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/test/java/AppTest.java create mode 100644 jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/test/java/integrationtest/ControllerTest.java create mode 100644 jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/test/resources/requests/CreateEntityViaBatch.txt create mode 100644 jpa-archetype/pom.xml create mode 100644 jpa-tutorial/.gitignore delete mode 100644 jpa/.classpath delete mode 100644 jpa/odata-jpa-annotation/.classpath delete mode 100644 jpa/odata-jpa-annotation/.settings/org.eclipse.wst.common.component create mode 100644 jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/core/edm/annotation/EdmEnumeration.java create mode 100644 jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/core/edm/annotation/EdmProtectedBy.java create mode 100644 jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/core/edm/annotation/EdmProtections.java create mode 100644 jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/core/edm/annotation/EdmTransient.java create mode 100644 jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/core/edm/annotation/EdmTransientPropertyCalculator.java create mode 100644 jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/core/edm/annotation/EdmVisibleFor.java create mode 100644 jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/odata/v4/core/annotation/Immutable.java create mode 100644 jpa/odata-jpa-coverage/pom.xml delete mode 100644 jpa/odata-jpa-metadata/.classpath delete mode 100644 jpa/odata-jpa-metadata/.settings/org.eclipse.wst.common.component create mode 100644 jpa/odata-jpa-metadata/model/.gitignore create mode 100644 jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/api/JPAJoinColumn.java create mode 100644 jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/AbstractVocabularyReader.java create mode 100644 jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/Action.java delete mode 100644 jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/EntityKeyElement.java delete mode 100644 jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/EntityType.java create mode 100644 jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/Function.java delete mode 100644 jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/NavigationProperty.java create mode 100644 jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/Parameter.java delete mode 100644 jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/PropertyRef.java delete mode 100644 jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/ReferentialConstraint.java create mode 100644 jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/ReturnType.java create mode 100644 jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPACollectionAttribute.java create mode 100644 jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAEdmNameBuilder.java create mode 100644 jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAEnumerationAttribute.java create mode 100644 jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAJoinTable.java create mode 100644 jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAProtectionInfo.java create mode 100644 jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateCollectionProperty.java create mode 100644 jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateJoinTable.java create mode 100644 jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateSimpleProperty.java create mode 100644 jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPADefaultEdmNameBuilder.java delete mode 100644 jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPAEdmNameBuilder.java create mode 100644 jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPAProtectionInfo.java delete mode 100644 jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/ODataEnum.java delete mode 100644 jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/ODataEnumerationType.java create mode 100644 jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/OffsetDateTimeConverter.java delete mode 100644 jpa/odata-jpa-metadata/src/main/resources/metadata-exceptions-i18n_de.properties create mode 100644 jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/api/TestJPAEdmProvider.java create mode 100644 jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/CustomJPANameBuilder.java create mode 100644 jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateCollectionProperty.java create mode 100644 jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateEmbeddedIdProperty.java create mode 100644 jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateModelElement.java delete mode 100644 jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateProperty.java create mode 100644 jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateSimpleProperty.java create mode 100644 jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateWrongAnnotation.java create mode 100644 jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestJPAOnConditionItemImpl.java create mode 100644 jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestJPAProtectionInfo.java create mode 100644 jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestJPATypeConvertor.java create mode 100644 jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestOffsetDateTimeConverter.java create mode 100644 jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testaction/Actions.java create mode 100644 jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testaction/function/Function.java create mode 100644 jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/FileAccess.java create mode 100644 jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/FileAccessConverter.java create mode 100644 jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/WrongMember.java create mode 100644 jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/WrongMemberConverter.java create mode 100644 jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/WrongType.java create mode 100644 jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/WrongTypeConverter.java create mode 100644 jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/util/MemberDouble.java create mode 100644 jpa/odata-jpa-metadata/src/test/resources/annotations/Org.OData.Aggregation.V1.xml create mode 100644 jpa/odata-jpa-metadata/src/test/resources/annotations/Org.OData.Repeatability.V1.xml create mode 100644 jpa/odata-jpa-metadata/src/test/resources/annotations/empty.xml create mode 100644 jpa/odata-jpa-processor-cb/.gitignore create mode 100644 jpa/odata-jpa-processor-cb/pom.xml create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/EntityManagerFactoryWrapper.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/ProcessorSelection.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/ProcessorSubquery.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlAggregation.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlArithmetic.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlConvertable.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlJoinType.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlKeyWords.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlNullCheck.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlStringFunctions.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlSubQuery.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlTimeFunctions.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/exeptions/InternalServerError.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/exeptions/NotImplementedException.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/impl/AbstractJoinImp.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/impl/AliasBuilder.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/impl/CollectionJoinImpl.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/impl/CriteriaBuilderImpl.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/impl/CriteriaQueryImpl.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/impl/EntityManagerWrapper.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/impl/ExpressionImpl.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/impl/FromImpl.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/impl/JoinTableJoin.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/impl/OrderImpl.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/impl/ParameterBuffer.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/impl/PathImpl.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/impl/PathJoin.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/impl/PredicateImpl.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/impl/RootImpl.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/impl/SimpleJoin.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/impl/SubqueryImpl.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/impl/TupleImpl.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/impl/TypedQueryImpl.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/joiner/ExpressionCollector.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/joiner/ExpressionJoiner.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/joiner/StringBuilderCollector.java create mode 100644 jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/joiner/StringBuilderJoiner.java create mode 100644 jpa/odata-jpa-processor-cb/src/test/java/com/sap/olingo/jpa/processor/cb/impl/AliasBuilderTest.java create mode 100644 jpa/odata-jpa-processor-cb/src/test/java/com/sap/olingo/jpa/processor/cb/impl/BuilderBaseTest.java create mode 100644 jpa/odata-jpa-processor-cb/src/test/java/com/sap/olingo/jpa/processor/cb/impl/CriteriaBuilderDerbyTest.java create mode 100644 jpa/odata-jpa-processor-cb/src/test/java/com/sap/olingo/jpa/processor/cb/impl/CriteriaBuilderH2Test.java create mode 100644 jpa/odata-jpa-processor-cb/src/test/java/com/sap/olingo/jpa/processor/cb/impl/CriteriaBuilderHSQLDBTest.java create mode 100644 jpa/odata-jpa-processor-cb/src/test/java/com/sap/olingo/jpa/processor/cb/impl/CriteriaBuilderImplTest.java create mode 100644 jpa/odata-jpa-processor-cb/src/test/java/com/sap/olingo/jpa/processor/cb/impl/CriteriaBuilderOverallTest.java create mode 100644 jpa/odata-jpa-processor-cb/src/test/java/com/sap/olingo/jpa/processor/cb/impl/CritertaQueryImplTest.java create mode 100644 jpa/odata-jpa-processor-cb/src/test/java/com/sap/olingo/jpa/processor/cb/impl/FromImplTest.java create mode 100644 jpa/odata-jpa-processor-cb/src/test/java/com/sap/olingo/jpa/processor/cb/impl/PathImplTest.java create mode 100644 jpa/odata-jpa-processor-cb/src/test/java/com/sap/olingo/jpa/processor/cb/impl/TupleImplTest.java create mode 100644 jpa/odata-jpa-processor-parallel/.gitignore create mode 100644 jpa/odata-jpa-processor-parallel/pom.xml create mode 100644 jpa/odata-jpa-processor-parallel/src/main/java/com/sap/olingo/jpa/processor/core/api/JPAODataBatchParallelRequestGroup.java create mode 100644 jpa/odata-jpa-processor-parallel/src/main/java/com/sap/olingo/jpa/processor/core/api/JPAODataBatchRequestGroup.java create mode 100644 jpa/odata-jpa-processor-parallel/src/main/java/com/sap/olingo/jpa/processor/core/api/JPAODataBatchSequentialRequestGroup.java create mode 100644 jpa/odata-jpa-processor-parallel/src/main/java/com/sap/olingo/jpa/processor/core/api/JPAODataParallelBatchProcessor.java create mode 100644 jpa/odata-jpa-processor-parallel/src/main/java/com/sap/olingo/jpa/processor/core/api/JPAODataParallelBatchProcessorFactory.java create mode 100644 jpa/odata-jpa-processor-parallel/src/main/java/com/sap/olingo/jpa/processor/core/exception/ODataJPABatchException.java create mode 100644 jpa/odata-jpa-processor-parallel/src/main/java/com/sap/olingo/jpa/processor/core/exception/ODataJPABatchRuntimeException.java create mode 100644 jpa/odata-jpa-processor-parallel/src/main/resources/processor-exceptions-i18n.properties create mode 100644 jpa/odata-jpa-processor-parallel/src/test/JPAODataBatchSequentialRequestGroupTest.java create mode 100644 jpa/odata-jpa-processor-parallel/src/test/java/com/sap/olingo/jpa/processor/core/api/JPAODataBatchAbstractRequestGroupTest.java create mode 100644 jpa/odata-jpa-processor-parallel/src/test/java/com/sap/olingo/jpa/processor/core/api/JPAODataBatchParallelRequestGroupTest.java create mode 100644 jpa/odata-jpa-processor-parallel/src/test/java/com/sap/olingo/jpa/processor/core/api/JPAODataBatchSequentialRequestGroupTest.java create mode 100644 jpa/odata-jpa-processor-parallel/src/test/java/com/sap/olingo/jpa/processor/core/api/JPAODataParallelBatchProcessorIntegrationTest.java create mode 100644 jpa/odata-jpa-processor-parallel/src/test/java/com/sap/olingo/jpa/processor/core/api/JPAODataParallelBatchProcessorTest.java create mode 100644 jpa/odata-jpa-processor-parallel/src/test/java/com/sap/olingo/jpa/processor/test/util/IntegrationTestHelper.java delete mode 100644 jpa/odata-jpa-processor/.classpath create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/api/JPACUDRequestHandler.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/api/JPAClaimsPair.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/api/JPADefaultBatchProcessorFactory.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/api/JPADefaultErrorProcessor.java delete mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/api/JPAEmptyDebugger.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/api/JPAErrorProcessor.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/api/JPAErrorProcessorWrapper.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/api/JPAODataBatchProcessorFactory.java delete mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/api/JPAODataCRUDContext.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/api/JPAODataCRUDContextAccess.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/api/JPAODataCRUDRequestContext.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/api/JPAODataClaimProvider.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/api/JPAODataClaimsProvider.java delete mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/api/JPAODataContextImpl.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/api/JPAODataDefaultTransactionFactory.java delete mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/api/JPAODataGetContext.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/api/JPAODataGroupProvider.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/api/JPAODataGroupsProvider.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/api/JPAODataPage.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/api/JPAODataPagingProvider.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/api/JPAODataRequestContext.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/api/JPAODataServiceContext.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/api/JPAODataServiceDocumentProcessor.java delete mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/api/JPAODataSessionContextAccess.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/api/JPAODataTransactionFactory.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/api/example/JPAExampleCUDRequestHandler.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/api/example/JPAExampleModifyException.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/api/example/JPAExamplePagingProvider.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/converter/JPACollectionResult.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/converter/JPAResultConverter.java rename jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/{modify => converter}/JPATuple.java (63%) delete mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/converter/JPATupleAbstractConverter.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/converter/JPATupleChildConverter.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/converter/JPATupleCollectionConverter.java delete mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/converter/JPATupleExpandResultConverter.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/database/JPAAbstractDatabaseProcessor.java delete mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/database/JPA_HANA_DatabaseProcessor.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/database/JPA_POSTSQL_DatabaseProcessor.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/exception/ODataJPAIllegalAccessException.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/exception/ODataJPAInvocationTargetException.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/exception/ODataJPATransactionException.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/filter/JPABinaryExpression.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/filter/JPAEnumerationBasedOperator.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/filter/JPAEnumerationOperator.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/filter/JPAExpression.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/filter/JPAMethodBasedExpression.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/filter/JPAMethodExpression.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/filter/JPAPrimitiveTypeOperator.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/filter/JPAVisitableExpression.java delete mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/modify/JPACUDRequestHandler.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/modify/JPAEntityBasedResult.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/modify/JPAEntityCollectionResult.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/modify/JPAMapBaseResult.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/modify/JPAMapCollectionResult.java rename jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/{api/JPACoreDeugger.java => processor/JPACoreDebugger.java} (72%) create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/processor/JPAEmptyDebugger.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/processor/JPALogger.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/processor/JPAODataRequestContextImpl.java delete mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/processor/deserializer/JsonDeserializer.java delete mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/processor/deserializer/package-info.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/query/JPAAbstractJoinQuery.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/query/JPACollectionExpandWrapper.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/query/JPACollectionFilterQuery.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/query/JPACollectionItemInfo.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/query/JPACollectionJoinQuery.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/query/JPACollectionQueryResult.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/query/JPAConvertableResult.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/query/JPACountQuery.java delete mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/query/JPAExecutableQuery.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/query/JPAExpandJoinQuery.java delete mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/query/JPAExpandQuery.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/query/JPAInlineItemInfo.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/query/JPAJoinQuery.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/query/JPAKeyBoundary.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/query/JPAKeyPair.java delete mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/query/JPANavigationInheritFilterQuery.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/query/JPANoSelectionException.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/query/SelectOptionUtil.java create mode 100644 jpa/odata-jpa-processor/src/main/java/com/sap/olingo/jpa/processor/core/query/SelectionPathInfo.java create mode 100644 jpa/odata-jpa-processor/src/main/resources/example-exceptions-i18n.properties create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/api/JPAClaimsPairTest.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/api/JPAODataClaimsProviderTest.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/api/JPAODataDefaultTransactionFactoryTest.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/api/TestJPAAbstractCUDRequestHandler.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/api/TestJPAODataGetHandler.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/api/TestJPAODataGroupsProvider.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/api/TestJPAODataRequestProcessor.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/api/TestJPAODataServiceContextBuilder.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/api/TestJPAODataServiceDocumentProcessor.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/api/example/JPAExampleCUDRequestHandlerTest.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/api/example/JPAExamplePagingProviderTest.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/database/TestJPADefaultDatabaseProcessor.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/database/TestJPA_DERBY_DatabaseProcessor.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/database/TestJPA_HSQLDB_DatabaseProcessor.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/database/TestJPA_POSTSQL_DatabaseProcessor.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/database/TestJPA_XXX_DatabaseProcessor.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/processor/JPACoreDebuggerTest.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/processor/TestCreateDeltaBasedResult.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/processor/TestJPAODataRequestContextImpl.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/query/TestEdmEntitySetResult.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/query/TestJPAExpandJoinQuery.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/query/TestJPAExpandQueryResult.java delete mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/query/TestJPAExpandResult.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/query/TestJPAFunctionDB.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/query/TestJPAKeyPair.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/query/TestJPAQueryBuildSelectionPathList.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/query/TestJPAQueryCollection.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/query/TestJPAQueryJSONAnnotations.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/query/TestJPAQueryODataVersionSupport.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/query/TestJPAQuerySelectWithGroupClause.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/query/TestJPAQueryWithProtection.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/query/TestJPAServerDrivenPaging.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/query/TestJPATupleChildConverter.java rename jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/query/{TestJPATupleResultConverterCompoundKey.java => TestJPATupleChildConverterCompoundKey.java} (66%) delete mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/query/TestJPATupleResultConverter.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/query/TestSelectionPathInfo.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/serializer/TestJPAOperationSerializer.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/serializer/TestJPASerializeComplex.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/serializer/TestJPASerializeCreate.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/serializer/TestJPASerializeEntity.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/serializer/TestJPASerializeEntityCollection.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/serializer/TestJPASerializePrimitive.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/serializer/TestJPASerializeValue.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/serializer/TestJPASerializer.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/serializer/TestJPASerializerCollection.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/serializer/TestJPASerializerComplexCollection.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/serializer/TestJPASerializerPrimitiveCollection.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/testobjects/BusinessPartnerRoleWithoutSetter.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/testobjects/FileAccess.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/testobjects/FileAccessConverter.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/testobjects/HeaderParamTransientPropertyConverter.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/testobjects/OrganizationWithoutGetter.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/testobjects/TwoParameterTransientPropertyConverter.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/util/CountQueryMatcher.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/util/JPAEntityTypeDouble.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/util/TestGroupBase.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/util/TestQueryBase.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/util/matcher/ComplexSerializerOptionsMatcher.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/util/matcher/CountQueryMatcher.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/util/matcher/EntityCollectionSerializerOptionsMatcher.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/util/matcher/EntitySerializerOptionsMatcher.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/util/matcher/InputStreamMatcher.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/util/matcher/PrimitiveSerializerOptionsMatcher.java create mode 100644 jpa/odata-jpa-processor/src/test/java/com/sap/olingo/jpa/processor/core/util/matcher/SerializerOptionsMatcher.java create mode 100644 jpa/odata-jpa-spring-support/pom.xml create mode 100644 jpa/odata-jpa-spring-support/src/main/resources/META-INF/additional-spring-configuration-metadata.json delete mode 100644 jpa/odata-jpa-test/.classpath delete mode 100644 jpa/odata-jpa-test/.settings/org.eclipse.wst.common.component create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/errormodel/AdministrativeInformation.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/errormodel/ChangeInformation.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/errormodel/CollectionAttributeProtected.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/errormodel/ComplextProtectedNoPath.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/errormodel/ComplextProtectedWrongPath.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/errormodel/CompoundKey.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/errormodel/DummyPropertyCalculator.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/errormodel/EmbeddedKeyPartOfGroup.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/errormodel/KeyPartOfGroup.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/errormodel/MandatoryPartOfGroup.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/errormodel/NavigationAttributeProtected.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/errormodel/NavigationPropertyPartOfGroup.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/errormodel/PersonDeepCollectionProtected.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/errormodel/Team.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/errormodel/TeamWithTransientCalculatorConstructorError.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/errormodel/TeamWithTransientCalculatorError.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/errormodel/TeamWithTransientEmbeddableKey.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/errormodel/TeamWithTransientError.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/errormodel/TeamWithTransientKey.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/errormodel/TransientPropertyCalculatorTwoConstructors.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/errormodel/TransientPropertyCalculatorWrongConstructor.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/ABCClassifiaction.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/AccessRights.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/AccessRightsConverter.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/AddressDeepProtected.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/AddressDeepThreeProtections.java delete mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/AssertList.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/BusinessPartnerProtected.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/BusinessPartnerRoleProtected.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/BusinessPartnerRoleWithGroup.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/BusinessPartnerWithGroups.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/CollcetionInnerComplex.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/CollcetionNestedComplex.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/CollcetionNestedComplexWithTransient.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/Collection.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/CollectionDeep.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/CollectionFirstLevelComplex.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/CollectionPartOfComplex.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/CollectionSecondLevelComplex.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/CollectionWithTransient.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/ComplexWithTransientComplexCollction.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/CountryRestriction.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/DateTimeConverter.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/DeepProtectedExample.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/FullNameCalculator.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/InhouseAddress.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/InhouseAddressTable.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/InhouseAddressWithGroup.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/InhouseAddressWithProtection.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/InhouseAddressWithThreeProtections.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/InstanceRestrictionKey.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/JoinComplex.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/JoinRelation.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/JoinRelationKey.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/JoinSource.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/JoinTarget.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/LogarithmCalculator.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/Membership.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/MembershipKey.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/PersonDeepProtected.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/PersonDeepProtectedHidden.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/PostalAddressDataWithGroup.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/StreetPropertyCalculator.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/SupportRelationship.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/Team.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/TransientRefComplex.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/testmodel/User.java create mode 100644 jpa/odata-jpa-test/src/main/java/com/sap/olingo/jpa/processor/core/util/Assertions.java rename jpa/{odata-jpa-processor/src/test => odata-jpa-test/src/main}/java/com/sap/olingo/jpa/processor/core/util/HttpRequestHeaderDouble.java (74%) rename jpa/{odata-jpa-processor/src/test => odata-jpa-test/src/main}/java/com/sap/olingo/jpa/processor/core/util/HttpServletRequestDouble.java (80%) rename jpa/{odata-jpa-processor/src/test => odata-jpa-test/src/main}/java/com/sap/olingo/jpa/processor/core/util/HttpServletResponseDouble.java (91%) rename jpa/{odata-jpa-processor/src/test => odata-jpa-test/src/main}/java/com/sap/olingo/jpa/processor/core/util/ServletInputStreamDouble.java (100%) create mode 100644 jpa/odata-jpa-test/src/test/java/com/sap/olingo/jpa/processor/test/TestEqualHashCodeMethods.java create mode 100644 jpa/odata-jpa-test/src/test/java/com/sap/olingo/jpa/processor/test/TestEqualHashCodeMethodsErrorModel.java create mode 100644 jpa/odata-jpa-test/src/test/java/com/sap/olingo/jpa/processor/test/TestEqualHashCodeMethodsTestModel.java create mode 100644 jpa/odata-jpa-test/src/test/java/com/sap/olingo/jpa/processor/test/TestStandardMethodsOfTestModel.java diff --git a/README.md b/README.md index 4106331e2..4438ea891 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ At the current state the JPA Processor provide support for: 2. Processing Get requests by converting them into Criteria Builder queries. 3. Supporting entity manipulations. -More details can be found in the [Tutorial](/jpa-tutorial/Tutorials/Introduction/Introduction.md) +More details can be found in the [Tutorial](https://github.com/SAP/olingo-jpa-processor-v4/blob/develop/jpa-tutorial/Tutorials/Introduction/Introduction.md) ## Dependencies ## License This project is licensed under the Apache Software License Version 2.0, except as noted otherwise in the [License file](/LICENSE.txt). diff --git a/jpa-archetype/jpa-archetype-spring/pom.xml b/jpa-archetype/jpa-archetype-spring/pom.xml new file mode 100644 index 000000000..5356bc57b --- /dev/null +++ b/jpa-archetype/jpa-archetype-spring/pom.xml @@ -0,0 +1,36 @@ + + 4.0.0 + + + com.sap.olingo + odata-jpa-archetype + 0.3.8 + + odata-jpa-archetype-spring + Archetype - odata-jpa-archetype-spring + + https://github.com/SAP/olingo-jpa-processor-v4 + jar + + + 1.8 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${project.build.source} + ${project.build.source} + true + true + -Xlint:unchecked + ${project.build.sourceEncoding} + + + + + diff --git a/jpa-archetype/jpa-archetype-spring/src/main/resources/META-INF/maven/archetype-metadata.xml b/jpa-archetype/jpa-archetype-spring/src/main/resources/META-INF/maven/archetype-metadata.xml new file mode 100644 index 000000000..a55ac5309 --- /dev/null +++ b/jpa-archetype/jpa-archetype-spring/src/main/resources/META-INF/maven/archetype-metadata.xml @@ -0,0 +1,50 @@ + + + + src/main/java + + **/*.java + + + + src/test/java + + **/*.java + + + + src/main/resources + + **/*.sql + **/*.json + **/*.xml + **/*.properties + **/*.yml + + + + src/test/resources + + **/*.txt + + + + + + + + + EntityTemplate + + + ValueObjectTemplate + + + 9010 + + + diff --git a/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/pom.xml b/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/pom.xml new file mode 100644 index 000000000..6a53e085b --- /dev/null +++ b/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/pom.xml @@ -0,0 +1,124 @@ + + + 4.0.0 + ${groupId} + ${artifactId} + ${version} + jar + + + org.springframework.boot + spring-boot-starter-parent + 2.1.0.RELEASE + + + + + 0.3.8-SNAPSHOT + 1.8 + + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-test + test + + + junit + junit + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.hibernate + hibernate-entitymanager + + + org.hibernate + hibernate-core + + + + + org.eclipse.persistence + javax.persistence + 2.1.1 + compile + + + org.eclipse.persistence + eclipselink + 2.7.1 + + + com.sap.olingo + odata-jpa-processor + ${jpa-processor} + + + com.sap.olingo + odata-jpa-spring-support + ${jpa-processor} + + + org.springframework.boot + spring-boot-configuration-processor + true + + + org.flywaydb + flyway-core + + + org.hsqldb + hsqldb + runtime + + + org.springframework.boot + spring-boot-devtools + true + + + io.rest-assured + spring-mock-mvc + test + + + org.junit.jupiter + junit-jupiter + 5.4.2 + test + + + org.junit.platform + junit-platform-launcher + 1.4.2 + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/java/SpringApp.java b/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/java/SpringApp.java new file mode 100644 index 000000000..c704b151d --- /dev/null +++ b/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/java/SpringApp.java @@ -0,0 +1,12 @@ +package $package; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringApp { + + public static void main(String[] args) { + SpringApplication.run(SpringApp.class, args); + } +} diff --git a/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/java/config/EclipseLinkJpaConfiguration.java b/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/java/config/EclipseLinkJpaConfiguration.java new file mode 100644 index 000000000..8568f3b79 --- /dev/null +++ b/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/java/config/EclipseLinkJpaConfiguration.java @@ -0,0 +1,76 @@ +package ${package}.config; + +import static org.eclipse.persistence.config.PersistenceUnitProperties.CACHE_SHARED_DEFAULT; +import static org.eclipse.persistence.config.PersistenceUnitProperties.CONNECTION_POOL_MAX; +import static org.eclipse.persistence.config.PersistenceUnitProperties.DDL_GENERATION; +import static org.eclipse.persistence.config.PersistenceUnitProperties.LOGGING_LEVEL; +import static org.eclipse.persistence.config.PersistenceUnitProperties.TRANSACTION_TYPE; +import static org.eclipse.persistence.config.PersistenceUnitProperties.WEAVING; + +import java.util.HashMap; +import java.util.Map; + +import javax.sql.DataSource; + +import org.eclipse.persistence.config.PersistenceUnitProperties; +import org.eclipse.persistence.logging.SessionLog; +import ${package}.model.EntityTemplate; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration; +import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties; +import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers; +import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter; +import org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter; +import org.springframework.transaction.jta.JtaTransactionManager; + +@Configuration +public class EclipseLinkJpaConfiguration extends JpaBaseConfiguration { + @Value("${odata.jpa.punit_name}") + private String punit; + + protected EclipseLinkJpaConfiguration(DataSource dataSource, JpaProperties properties, + ObjectProvider jtaTransactionManager, + ObjectProvider transactionManagerCustomizers) { + super(dataSource, properties, jtaTransactionManager, transactionManagerCustomizers); + } + + @Override + protected AbstractJpaVendorAdapter createJpaVendorAdapter() { + return new EclipseLinkJpaVendorAdapter(); + } + + @Override + protected Map getVendorProperties() { + // https://stackoverflow.com/questions/10769051/eclipselinkjpavendoradapter-instead-of-hibernatejpavendoradapter-issue + HashMap jpaProperties = new HashMap<>(); + jpaProperties.put(WEAVING, "false"); + // No table generation by JPA + jpaProperties.put(DDL_GENERATION, "none"); + jpaProperties.put(LOGGING_LEVEL, SessionLog.FINE_LABEL); + jpaProperties.put(TRANSACTION_TYPE, "RESOURCE_LOCAL"); + // do not cache entities locally, as this causes problems if multiple application instances are used + jpaProperties.put(CACHE_SHARED_DEFAULT, "false"); + // You can also tweak your application performance by configuring your database connection pool. + // https://www.eclipse.org/eclipselink/documentation/2.7/jpa/extensions/persistenceproperties_ref.htm#connectionpool + jpaProperties.put(CONNECTION_POOL_MAX, 50); + return jpaProperties; + } + + @Bean + public LocalContainerEntityManagerFactoryBean customerEntityManagerFactory( + final EntityManagerFactoryBuilder builder, @Autowired final DataSource ds) { + + return builder + .dataSource(ds) + .packages(EntityTemplate.class) + .properties(getVendorProperties()) + .jta(false) + .build(); + } +} \ No newline at end of file diff --git a/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/java/config/ProcessorConfiguration.java b/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/java/config/ProcessorConfiguration.java new file mode 100644 index 000000000..a6094b493 --- /dev/null +++ b/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/java/config/ProcessorConfiguration.java @@ -0,0 +1,31 @@ +package ${package}.config; + +import javax.persistence.EntityManagerFactory; + +import org.apache.olingo.commons.api.ex.ODataException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.sap.olingo.jpa.processor.core.api.JPAODataCRUDContextAccess; +import com.sap.olingo.jpa.processor.core.api.JPAODataServiceContext; + +@Configuration +public class ProcessorConfiguration { + @Value("${odata.jpa.punit_name}") + private String punit; + @Value("${odata.jpa.root_packages}") + private String rootPackages; + + @Bean + public JPAODataCRUDContextAccess sessionContext(@Autowired final EntityManagerFactory emf) throws ODataException { + + return JPAODataServiceContext.with() + .setPUnit(punit) + .setEntityManagerFactory(emf) + .setTypePackage(rootPackages) + .setRequestMappingPath("${punit}/v1") + .build(); + } +} \ No newline at end of file diff --git a/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/java/controller/ODataController.java b/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/java/controller/ODataController.java new file mode 100644 index 000000000..e35f40e08 --- /dev/null +++ b/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/java/controller/ODataController.java @@ -0,0 +1,33 @@ +package ${package}.controller; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.olingo.commons.api.ex.ODataException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.context.annotation.RequestScope; + +import com.sap.olingo.jpa.processor.core.api.JPAODataCRUDContextAccess; +import com.sap.olingo.jpa.processor.core.api.JPAODataCRUDHandler; +import com.sap.olingo.jpa.processor.core.api.example.JPAExampleCUDRequestHandler; + +@RestController +@RequestMapping("${punit}/v1/**") +@RequestScope +public class ODataController { + + @Autowired + private JPAODataCRUDContextAccess serviceContext; + + @RequestMapping(value = "**", method = { RequestMethod.GET, RequestMethod.PATCH, // NOSONAR + RequestMethod.POST, RequestMethod.DELETE }) + public void crud(final HttpServletRequest req, final HttpServletResponse resp) throws ODataException { + + final JPAODataCRUDHandler handler = new JPAODataCRUDHandler(serviceContext); + handler.getJPAODataRequestContext().setCUDRequestHandler(new JPAExampleCUDRequestHandler()); + handler.process(req, resp); + } +} diff --git a/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/java/model/EntityTemplate.java b/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/java/model/EntityTemplate.java new file mode 100644 index 000000000..626823973 --- /dev/null +++ b/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/java/model/EntityTemplate.java @@ -0,0 +1,59 @@ +package ${package}.model; + +import java.util.ArrayList; +import java.util.Collection; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.OneToMany; +import javax.persistence.Table; + +@Entity(name = "${entity-table}") +@Table(schema = "\"${schema}\"", name = "\"${entity-table}\"") +public class EntityTemplate { + @Id + @Column(name = "\"ID\"", length = 32) + private String id; + + @OneToMany(mappedBy = "entity", fetch = FetchType.LAZY, cascade = CascadeType.ALL) + private Collection valueObjects = new ArrayList<>(); + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public Collection getValueObjects() { + return valueObjects; + } + + public void setValueObjects(Collection valueObjects) { + this.valueObjects = valueObjects; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((id == null) ? 0 : id.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + EntityTemplate other = (EntityTemplate) obj; + if (id == null) { + if (other.id != null) return false; + } else if (!id.equals(other.id)) return false; + return true; + } +} diff --git a/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/java/model/ValueObjectTemplate.java b/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/java/model/ValueObjectTemplate.java new file mode 100644 index 000000000..c92a04239 --- /dev/null +++ b/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/java/model/ValueObjectTemplate.java @@ -0,0 +1,52 @@ +package ${package}.model; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.IdClass; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; + +@IdClass(ValueObjectTemplateKey.class) +@Entity(name = "${value-object-table}") +@Table(schema = "\"${schema}\"", name = "\"${value-object-table}\"") +public class ValueObjectTemplate { + @Id + @Column(name = "\"ID\"", length = 32) + private String id; + + @Id + @Column(name = "\"Entity\"", length = 32) + private String entityId; + + @ManyToOne(optional = false, fetch = FetchType.LAZY) + @JoinColumn(name = "\"Entity\"", insertable = false, updatable = false) + private EntityTemplate entity; + + public String getId() { + return id; + } + + public void setId(final String id) { + this.id = id; + } + + public String getEntityId() { + return entityId; + } + + public void setEntityId(final String entityId) { + this.entityId = entityId; + } + + public EntityTemplate getEntity() { + return entity; + } + + public void setEntity(final EntityTemplate entity) { + this.entityId = entity.getId(); + this.entity = entity; + } +} diff --git a/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/java/model/ValueObjectTemplateKey.java b/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/java/model/ValueObjectTemplateKey.java new file mode 100644 index 000000000..6b1ab103c --- /dev/null +++ b/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/java/model/ValueObjectTemplateKey.java @@ -0,0 +1,56 @@ +package ${package}.model; + +import java.io.Serializable; + +import javax.persistence.Id; + +public class ValueObjectTemplateKey implements Serializable { + + private static final long serialVersionUID = 1L; + + @Id + private String id; + + @Id + private String entityId; + + String getEmploymentId() { + return entityId; + } + + void setEmploymentId(String employmentId) { + this.entityId = employmentId; + } + + String getId() { + return id; + } + + void setId(String id) { + this.id = id; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((entityId == null) ? 0 : entityId.hashCode()); + result = prime * result + ((id == null) ? 0 : id.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + ValueObjectTemplateKey other = (ValueObjectTemplateKey) obj; + if (entityId == null) { + if (other.entityId != null) return false; + } else if (!entityId.equals(other.entityId)) return false; + if (id == null) { + if (other.id != null) return false; + } else if (!id.equals(other.id)) return false; + return true; + } +} diff --git a/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/resources/application-test.yml b/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/resources/application-test.yml new file mode 100644 index 000000000..ae68ff530 --- /dev/null +++ b/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/resources/application-test.yml @@ -0,0 +1,25 @@ +logging: + level: + org: + springframework: DEBUG +odata: + jpa: + punit_name: ${punit} + root_packages: ${package} +server: + port: 9010 +spring: + datasource: + driver-class-name: org.hsqldb.jdbc.JDBCDriver + password: '' + url: jdbc:hsqldb:mem:${schema};DB_CLOSE_DELAY=-1 + username: sa + flyway: + password: '' + schemas: + - ${schema} + url: jdbc:hsqldb:mem:${schema};DB_CLOSE_DELAY=-1 + user: sa + servlet: + multipart: + enabled: false diff --git a/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/resources/application.yml b/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/resources/application.yml new file mode 100644 index 000000000..95f10b92e --- /dev/null +++ b/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/resources/application.yml @@ -0,0 +1,25 @@ +logging: + level: + org: + springframework: INFO +odata: + jpa: + punit_name: ${punit} + root_packages: ${package} +server: + port: ${port} +spring: + datasource: + driver-class-name: org.hsqldb.jdbc.JDBCDriver + password: '' + url: jdbc:hsqldb:file:${punit};DB_CLOSE_DELAY=-1 + username: sa + flyway: + password: '' + schemas: + - ${schema} + url: jdbc:hsqldb:file:${punit};DB_CLOSE_DELAY=-1 + user: sa + servlet: + multipart: + enabled: false diff --git a/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/resources/db/migration/V1_0__jpa.sql b/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/resources/db/migration/V1_0__jpa.sql new file mode 100644 index 000000000..b7152652d --- /dev/null +++ b/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/main/resources/db/migration/V1_0__jpa.sql @@ -0,0 +1,10 @@ +SET schema "${schema}"; + +CREATE TABLE "${entity-table}"( + "ID" VARCHAR(32) NOT NULL , + PRIMARY KEY ("ID")); + +CREATE TABLE "${value-object-table}"( + "Entity" VARCHAR(32) NOT NULL , + "ID" VARCHAR(32) NOT NULL , + PRIMARY KEY ("Entity", "ID")); \ No newline at end of file diff --git a/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/test/java/AppTest.java b/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/test/java/AppTest.java new file mode 100644 index 000000000..183a67179 --- /dev/null +++ b/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/test/java/AppTest.java @@ -0,0 +1,20 @@ +package ${package}; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +/** + * Unit test for simple App. + */ + +public class AppTest { + + /** + * Rigourous Test :-) + */ + @Test + public void testApp() { + assertTrue(true); + } +} diff --git a/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/test/java/integrationtest/ControllerTest.java b/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/test/java/integrationtest/ControllerTest.java new file mode 100644 index 000000000..2e8c041d5 --- /dev/null +++ b/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/test/java/integrationtest/ControllerTest.java @@ -0,0 +1,158 @@ +package ${package}.integrationtest; + +import static io.restassured.module.mockmvc.RestAssuredMockMvc.given; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.hasItems; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.File; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Collection; + +import org.apache.olingo.commons.api.http.HttpStatusCode; +import ${package}.SpringApp; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.web.context.WebApplicationContext; + +import io.restassured.http.ContentType; +import io.restassured.module.mockmvc.RestAssuredMockMvc; +import io.restassured.path.xml.XmlPath; +import io.restassured.path.xml.element.Node; + +@ExtendWith(SpringExtension.class) +@SpringBootTest(classes = SpringApp.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@TestPropertySource(properties = { "spring.config.location=classpath:application-test.yml" }) +public class ControllerTest { + + @Autowired + private WebApplicationContext context; + @LocalServerPort + private int port; + + @BeforeEach + public void setup() { + RestAssuredMockMvc.webAppContextSetup(context); + } + + @Test + public void testRetrieveServiceDocument() { + final String xml = given() + .accept(ContentType.XML) + .when() + .get("/${punit}/v1/") + .then() + .statusCode(HttpStatusCode.OK.getStatusCode()) + .contentType(ContentType.XML) + .extract() + .asString(); + + final XmlPath path = new XmlPath(xml); + final Collection n = ((Node) ((Node) path.get("service")).get("workspace")).get("collection"); + assertNotNull(n); + assertFalse(n.isEmpty()); + } + + @Test + public void testRetrieveMetadataDocument() { + final String xml = given() + .when() + .get("/${punit}/v1/$metadata") + .then() + .statusCode(HttpStatusCode.OK.getStatusCode()) + .contentType(ContentType.XML) + .extract() + .asString(); + + final XmlPath path = new XmlPath(xml); + final Node n = ((Node) ((Node) path.get("edmx:Edmx")).get("DataServices")).get("Schema"); + assertNotNull(n); + assertEquals("${punit}", n.getAttribute("Namespace")); + assertNotNull(n.get("EntityContainer")); + } + + @Test + public void testCreateInstance() { + given() + .contentType("application/json") + .body("{ \"Id\" : \"1\" }") + .when() + .post("/${punit}/v1/${entity-table}s") + .then() + .statusCode(HttpStatusCode.CREATED.getStatusCode()); + given() + .accept(ContentType.JSON) + .when() + .get("/${punit}/v1/${entity-table}s('1')") + .then() + .statusCode(HttpStatusCode.OK.getStatusCode()); + } + + @Test + public void testCreateInstanceWithBatch() throws URISyntaxException { + + URI uri = getClass().getClassLoader() + .getResource("requests/CreateEntityViaBatch.txt").toURI(); + + File myFile = new File(uri); + final String responce = given() + .contentType("multipart/mixed;boundary=abc") + .body(myFile) + .when() + .post("/${punit}/v1/$batch") + .then() + .statusCode(HttpStatusCode.ACCEPTED.getStatusCode()) + .extract() + .asString(); + + given() + .accept(ContentType.JSON) + .when() + .get("/${punit}/v1/${entity-table}s('2')") + .then() + .statusCode(HttpStatusCode.OK.getStatusCode()); + + final String[] partResults = responce.split("--changeset"); + assertTrue(partResults[1].contains("HTTP/1.1 201")); + assertTrue(partResults[2].contains("HTTP/1.1 400")); + } + + @Test + public void testCreateInstanceDeep() { + given() + .contentType(ContentType.JSON) + .accept(ContentType.JSON) + .body("{ \"Id\" : \"3\", \"ValueObjects\" : [{\"Id\" : \"1\"}, {\"Id\" : \"2\"}] }") + .when() + .post("/${punit}/v1/${entity-table}s") + .then() + .statusCode(HttpStatusCode.CREATED.getStatusCode()) + .body("ValueObjects.Id", hasItems("1", "2")) + .body("Id", equalTo("3")) + .extract() + .asString(); + given() + .accept(ContentType.JSON) + .when() + .get("/${punit}/v1/${value-object-table}s(EntityId='3',Id='2')") + .then() + .statusCode(HttpStatusCode.OK.getStatusCode()); + + } + + @AfterEach + public void teardown() { + RestAssuredMockMvc.reset(); + } +} diff --git a/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/test/resources/requests/CreateEntityViaBatch.txt b/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/test/resources/requests/CreateEntityViaBatch.txt new file mode 100644 index 000000000..3b62af6ed --- /dev/null +++ b/jpa-archetype/jpa-archetype-spring/src/main/resources/archetype-resources/src/test/resources/requests/CreateEntityViaBatch.txt @@ -0,0 +1,38 @@ +--abc +Content-Type: multipart/mixed; boundary=xyz + +--xyz +Content-Type: application/http +Content-Transfer-Encoding: binary +Content-Id: 1 +Prefer: return=minimal + +POST ${entity-table}s HTTP/1.1 +Accept: application/json +Content-Type: application/json + +{ + "Id" : "2" +} + +--xyz-- + +--abc +Content-Type: multipart/mixed; boundary=xyz2 + +--xyz2 +Content-Type: application/http +Content-Transfer-Encoding: binary +Content-Id: 1 +Prefer: return=minimal + +POST ${entity-table}s HTTP/1.1 +Accept: application/json +Content-Type: application/json + +{ + "Id" : "2" +} + +--xyz2-- +--abc-- \ No newline at end of file diff --git a/jpa-archetype/pom.xml b/jpa-archetype/pom.xml new file mode 100644 index 000000000..dcb266346 --- /dev/null +++ b/jpa-archetype/pom.xml @@ -0,0 +1,21 @@ + + + 4.0.0 + com.sap.olingo + odata-jpa-archetype + 0.3.8 + pom + https://github.com/SAP/olingo-jpa-processor-v4 + + + UTF-8 + 1.8 + 0.3.8-SNAPSHOT + + + + odata-jpa-archetype-spring + + \ No newline at end of file diff --git a/jpa-tutorial/.gitignore b/jpa-tutorial/.gitignore new file mode 100644 index 000000000..4b7c4ed07 --- /dev/null +++ b/jpa-tutorial/.gitignore @@ -0,0 +1 @@ +/*.txt diff --git a/jpa/.classpath b/jpa/.classpath deleted file mode 100644 index e506d29d5..000000000 --- a/jpa/.classpath +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/jpa/.gitignore b/jpa/.gitignore index 41c1f923c..6012aab3d 100644 --- a/jpa/.gitignore +++ b/jpa/.gitignore @@ -1,4 +1,11 @@ +.settings/ target/ **/target/ /target/ /.pmd +.classpath + +# --- EclipseIDE stuff START +.settings/ +.metadata +*.log diff --git a/jpa/odata-jpa-annotation/.classpath b/jpa/odata-jpa-annotation/.classpath deleted file mode 100644 index 7b6b45925..000000000 --- a/jpa/odata-jpa-annotation/.classpath +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/jpa/odata-jpa-annotation/.gitignore b/jpa/odata-jpa-annotation/.gitignore index f39050ae3..bcb74aa8a 100644 --- a/jpa/odata-jpa-annotation/.gitignore +++ b/jpa/odata-jpa-annotation/.gitignore @@ -1,3 +1,7 @@ target/ **/target/ /.pmd + +# JDT-specific (Eclipse Java Development Tools) +.classpath +/.sts4-cache/ diff --git a/jpa/odata-jpa-annotation/.settings/org.eclipse.jdt.core.prefs b/jpa/odata-jpa-annotation/.settings/org.eclipse.jdt.core.prefs index 62a317c86..d2ac26b61 100644 --- a/jpa/odata-jpa-annotation/.settings/org.eclipse.jdt.core.prefs +++ b/jpa/odata-jpa-annotation/.settings/org.eclipse.jdt.core.prefs @@ -1,8 +1,11 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 -org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning -org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning +org.eclipse.jdt.core.compiler.release=disabled +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/jpa/odata-jpa-annotation/.settings/org.eclipse.wst.common.component b/jpa/odata-jpa-annotation/.settings/org.eclipse.wst.common.component deleted file mode 100644 index d7da6d749..000000000 --- a/jpa/odata-jpa-annotation/.settings/org.eclipse.wst.common.component +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/jpa/odata-jpa-annotation/.settings/org.eclipse.wst.common.project.facet.core.xml b/jpa/odata-jpa-annotation/.settings/org.eclipse.wst.common.project.facet.core.xml index 0ae797003..ee260d978 100644 --- a/jpa/odata-jpa-annotation/.settings/org.eclipse.wst.common.project.facet.core.xml +++ b/jpa/odata-jpa-annotation/.settings/org.eclipse.wst.common.project.facet.core.xml @@ -1,5 +1,5 @@ - + diff --git a/jpa/odata-jpa-annotation/pom.xml b/jpa/odata-jpa-annotation/pom.xml index e52857bf9..3c62aac71 100644 --- a/jpa/odata-jpa-annotation/pom.xml +++ b/jpa/odata-jpa-annotation/pom.xml @@ -1,29 +1,32 @@ - - 4.0.0 - - com.sap.olingo - odata-jpa - 0.1.9-SNAPSHOT - - odata-jpa-annotation - odata-jpa-annotation - http://maven.apache.org - - UTF-8 - - - - junit - junit - 4.12 - test - - - org.apache.olingo - odata-commons-api - ${odata.version} - - + + 4.0.0 + + com.sap.olingo + odata-jpa + 0.3.8-SNAPSHOT + + odata-jpa-annotation + odata-jpa-annotation + https://github.com/SAP/olingo-jpa-processor-v4 + + + + org.apache.olingo + odata-commons-api + ${odata.version} + + + org.eclipse.persistence + javax.persistence + ${jpa.version} + + + com.google.code.findbugs + jsr305 + 3.0.2 + + \ No newline at end of file diff --git a/jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/core/edm/annotation/EdmAnnotation.java b/jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/core/edm/annotation/EdmAnnotation.java index 911f92ee5..ad8abc703 100644 --- a/jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/core/edm/annotation/EdmAnnotation.java +++ b/jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/core/edm/annotation/EdmAnnotation.java @@ -9,7 +9,7 @@ /** * Can be used to annotate attributes. The annotations are converted into OData annotations. - * For detaials see + * For details see * OData Version 4.0 Part 3 - 14.3 Element edm:Annotation diff --git a/jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/core/edm/annotation/EdmEnumeration.java b/jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/core/edm/annotation/EdmEnumeration.java new file mode 100644 index 000000000..08d3ceeb6 --- /dev/null +++ b/jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/core/edm/annotation/EdmEnumeration.java @@ -0,0 +1,62 @@ +package com.sap.olingo.jpa.metadata.core.edm.annotation; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import javax.persistence.AttributeConverter; +import javax.persistence.Enumerated; + +/** + * Annotation to tag Java enumerations that shall be provided via an OData service. For details about OData Enumerations + * see: 10 + * Enumeration Type. + * The following conversion rule have been established: + *
    + *
  • Name is taken from the enumeration name
  • + *
  • UnderlyingType is derived from the converter, if no converter is provided Edm.Int32 is taken and a + * field in an entity pojo needed to be annotated with @Enumerated.
  • + *
  • Member
  • + *
      + *
    • Name is the name of a constant
    • + *
    • Value is determined via the converter, if no converter is provided the value is determined via the method + * ordinal
    • + *
    + *
+ * @author Oliver Grande + * + */ + +@Retention(RUNTIME) +@Target(TYPE) +public @interface EdmEnumeration { + + /** + * Converter to convert that converts the enumeration value. If no converter is provided, the ordinal is taken. + */ + Class[], ? extends Number>> converter() default DummyConverter.class; + + boolean isFlags() default false; + + /** + * Converter shall be optional, as java does not support default null a + * dummy converter implementation is needed. + */ + static class DummyConverter implements AttributeConverter[], Integer> { + + @Override + public Integer convertToDatabaseColumn(Enum[] attributes) { + return attributes[0].ordinal(); + } + + @Enumerated + @Override + public Enum[] convertToEntityAttribute(Integer dbData) { + return null; // NOSONAR + } + + } +} diff --git a/jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/core/edm/annotation/EdmFunction.java b/jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/core/edm/annotation/EdmFunction.java index 31aa5eb11..96abfb37d 100644 --- a/jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/core/edm/annotation/EdmFunction.java +++ b/jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/core/edm/annotation/EdmFunction.java @@ -1,6 +1,7 @@ package com.sap.olingo.jpa.metadata.core.edm.annotation; import java.lang.annotation.ElementType; +import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @@ -12,6 +13,7 @@ * @author Oliver Grande * */ +@Repeatable(EdmFunctions.class) @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.TYPE, ElementType.METHOD }) public @interface EdmFunction { @@ -51,10 +53,11 @@ } /** - * Defines the name of the function in the service document + * Defines the name of the function in the service document. This is a required attribute for database based functions + * and can be omitted for java based functions. * @return */ - String name(); + String name() default ""; EdmParameter[] parameter() default {}; diff --git a/jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/core/edm/annotation/EdmProtectedBy.java b/jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/core/edm/annotation/EdmProtectedBy.java new file mode 100644 index 000000000..1d71b389a --- /dev/null +++ b/jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/core/edm/annotation/EdmProtectedBy.java @@ -0,0 +1,40 @@ +package com.sap.olingo.jpa.metadata.core.edm.annotation; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * Describes which authorization claim shall be used to filter the annotated attribute. In case multiple attributes of + * an entity are annotated they are connected via an AND operation. This annotation is respected also if the attribute + * is marked to be ignored. + * @author Oliver Grande + * + */ +@Repeatable(EdmProtections.class) +@Retention(RUNTIME) +@Target(FIELD) +public @interface EdmProtectedBy { + /** + * Name of the authorization claim + * @return + */ + String name(); + + /** + * Optional: At embedded attributes the path to the attribute that shall be protected by the claim. In case the path + * is composed, path segments joined together by forward slashes (/).

The correctness of the pass is check late + * during request processing. + * @return + */ + String path() default ""; + + /** + * Optional: In case the protected attributes is of type string also wildcards are supported. '*' and '%' representing + * zero or more characters and '+' as well as '_' for a single character. + */ + boolean wildcardSupported() default true; +} diff --git a/jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/core/edm/annotation/EdmProtections.java b/jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/core/edm/annotation/EdmProtections.java new file mode 100644 index 000000000..2e3308092 --- /dev/null +++ b/jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/core/edm/annotation/EdmProtections.java @@ -0,0 +1,19 @@ +package com.sap.olingo.jpa.metadata.core.edm.annotation; + +import static java.lang.annotation.ElementType.FIELD; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Allows to combine either multiple claims for a simple attribute, which will be combined with AND, + * or to be able to protect multiple attributes at a complex attribute. + * @author Oliver Grande + * + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(FIELD) +public @interface EdmProtections { + public abstract EdmProtectedBy[] value(); +} diff --git a/jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/core/edm/annotation/EdmTransient.java b/jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/core/edm/annotation/EdmTransient.java new file mode 100644 index 000000000..6fcb40cf6 --- /dev/null +++ b/jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/core/edm/annotation/EdmTransient.java @@ -0,0 +1,34 @@ +/** + * + */ +package com.sap.olingo.jpa.metadata.core.edm.annotation; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * The annotation marks properties that are transient, but shall be part of the Edm. + * @author Oliver Grande + * Created: 25.11.2019 + */ + +@Target({ FIELD }) +@Retention(value = RUNTIME) +public @interface EdmTransient { + /** + * Optional: An array of path to attributes that need to be present to build the annotated one. In case the path + * is composed, path segments joined together by forward slashes (/) e.g address/cityName.

The correctness + * of the path is check when the entity type is build. + */ + String[] requiredAttributes() default {}; + + /** + * A calculator is an implementation of {@link EdmTransientPropertyCalculator}. It provides the transient property or + * property collection. + * @return + */ + Class> calculator(); +} diff --git a/jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/core/edm/annotation/EdmTransientPropertyCalculator.java b/jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/core/edm/annotation/EdmTransientPropertyCalculator.java new file mode 100644 index 000000000..956a27e31 --- /dev/null +++ b/jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/core/edm/annotation/EdmTransientPropertyCalculator.java @@ -0,0 +1,45 @@ +/** + * + */ +package com.sap.olingo.jpa.metadata.core.edm.annotation; + +import java.util.Collections; +import java.util.List; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.persistence.Tuple; + +/** + * Transient property converter.

+ * The converter provides the + * An instance of the converter is created once per OData request. That is it could be created multiple times per http + * request in case of a $batch request.

+ * An implementing class may provide one constructor having no parameter or a combination of the following: + *

    + *
  • An Entity Manager: javax.persistence.EntityManager
  • + *
  • All header: java.util.Map>
  • + *
+ * @author Oliver Grande
+ * Created: 14.03.2020 + * + */ +public interface EdmTransientPropertyCalculator { + /** + * This method is called in case the transient property is a primitive, simple property. + * @param row one row read from the database + * @return calculated value for the property + */ + default @Nullable I calculateProperty(@Nonnull final Tuple row) { + return null; + } + + /** + * This method is called in case the transient property is a collection property. + * @param row one row read from the database + * @return list of calculated values for the collection property + */ + default @Nonnull List calculateCollectionProperty(@Nonnull final Tuple row) { + return Collections.emptyList(); + } +} diff --git a/jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/core/edm/annotation/EdmVisibleFor.java b/jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/core/edm/annotation/EdmVisibleFor.java new file mode 100644 index 000000000..d06d750fb --- /dev/null +++ b/jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/core/edm/annotation/EdmVisibleFor.java @@ -0,0 +1,29 @@ +package com.sap.olingo.jpa.metadata.core.edm.annotation; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * The annotation can be used to assign attributes or properties to field or visibility groups. On case such a group is + * provided during a GET request all properties that are assigned to that group and all properties that are assigned to + * no group, or in other words that are not annotated, get selected. In case properties that belong to another group are + * requested, a null value is returned.

+ * + * Note: Keys, mandatory fields as well as association or navigation properties can not be annotated + * + * @author Oliver Grande + * + */ +@Retention(RUNTIME) +@Target(FIELD) +public @interface EdmVisibleFor { + /** + * List of field groups an attribute or property belongs to. + * @return + */ + String[] value(); + +} diff --git a/jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/odata/v4/core/annotation/Immutable.java b/jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/odata/v4/core/annotation/Immutable.java new file mode 100644 index 000000000..b8052823c --- /dev/null +++ b/jpa/odata-jpa-annotation/src/main/java/com/sap/olingo/jpa/metadata/odata/v4/core/annotation/Immutable.java @@ -0,0 +1,16 @@ +package com.sap.olingo.jpa.metadata.odata.v4.core.annotation; + +import static java.lang.annotation.ElementType.FIELD; + +import java.lang.annotation.Target; + +/** + * OData core annotation Immutable
+ * A value for this non-key property can be provided on insert and remains unchanged on update + * @author Oliver Grande + * + */ +@Target(FIELD) +public @interface Immutable { + boolean value() default true; +} diff --git a/jpa/odata-jpa-coverage/pom.xml b/jpa/odata-jpa-coverage/pom.xml new file mode 100644 index 000000000..1634474ef --- /dev/null +++ b/jpa/odata-jpa-coverage/pom.xml @@ -0,0 +1,80 @@ + + 4.0.0 + + com.sap.olingo + odata-jpa + 0.3.8-SNAPSHOT + + + odata-jpa-coverage + odata-jpa-coverage + https://github.com/SAP/olingo-jpa-processor-v4 + + + UTF-8 + + + + + com.sap.olingo + odata-jpa-annotation + ${project.version} + + + com.sap.olingo + odata-jpa-metadata + ${project.version} + + + com.sap.olingo + odata-jpa-processor + ${project.version} + + + com.sap.olingo + odata-jpa-processor-cb + ${project.version} + + + com.sap.olingo + odata-jpa-test + ${project.version} + + + com.sap.olingo + odata-jpa-processor-parallel + ${project.version} + + + + + + + org.jacoco + jacoco-maven-plugin + 0.8.5 + + + + prepare-agent + + + + report + prepare-package + + report-aggregate + + + + + + org.eluder.coveralls + coveralls-maven-plugin + ${coveralls.version} + + + + pom + \ No newline at end of file diff --git a/jpa/odata-jpa-metadata/.classpath b/jpa/odata-jpa-metadata/.classpath deleted file mode 100644 index cc14032cb..000000000 --- a/jpa/odata-jpa-metadata/.classpath +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/jpa/odata-jpa-metadata/.gitignore b/jpa/odata-jpa-metadata/.gitignore index 6975666da..79ed6e80d 100644 --- a/jpa/odata-jpa-metadata/.gitignore +++ b/jpa/odata-jpa-metadata/.gitignore @@ -1,4 +1,9 @@ +.settings/ target/ **/target/ /.pmd /*.log + +# JDT-specific (Eclipse Java Development Tools) +.classpath +/.sts4-cache/ diff --git a/jpa/odata-jpa-metadata/.settings/org.eclipse.jdt.core.prefs b/jpa/odata-jpa-metadata/.settings/org.eclipse.jdt.core.prefs index 14f521d2a..13ba4736b 100644 --- a/jpa/odata-jpa-metadata/.settings/org.eclipse.jdt.core.prefs +++ b/jpa/odata-jpa-metadata/.settings/org.eclipse.jdt.core.prefs @@ -1,5 +1,8 @@ eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 -org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning -org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning +org.eclipse.jdt.core.compiler.release=disabled +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/jpa/odata-jpa-metadata/.settings/org.eclipse.wst.common.component b/jpa/odata-jpa-metadata/.settings/org.eclipse.wst.common.component deleted file mode 100644 index f58abccb8..000000000 --- a/jpa/odata-jpa-metadata/.settings/org.eclipse.wst.common.component +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/jpa/odata-jpa-metadata/.settings/org.eclipse.wst.common.project.facet.core.xml b/jpa/odata-jpa-metadata/.settings/org.eclipse.wst.common.project.facet.core.xml index 0ae797003..ee260d978 100644 --- a/jpa/odata-jpa-metadata/.settings/org.eclipse.wst.common.project.facet.core.xml +++ b/jpa/odata-jpa-metadata/.settings/org.eclipse.wst.common.project.facet.core.xml @@ -1,5 +1,5 @@ - + diff --git a/jpa/odata-jpa-metadata/model/.gitignore b/jpa/odata-jpa-metadata/model/.gitignore new file mode 100644 index 000000000..b57e6db1d --- /dev/null +++ b/jpa/odata-jpa-metadata/model/.gitignore @@ -0,0 +1,3 @@ +/model.di +/model.notation +/model.uml diff --git a/jpa/odata-jpa-metadata/pom.xml b/jpa/odata-jpa-metadata/pom.xml index 8aedf8ce7..0fdcd2c39 100644 --- a/jpa/odata-jpa-metadata/pom.xml +++ b/jpa/odata-jpa-metadata/pom.xml @@ -5,31 +5,27 @@ 4.0.0 com.sap.olingo - odata-jpa - 0.1.9-SNAPSHOT + odata-jpa + 0.3.8-SNAPSHOT odata-jpa-metadata odata-jpa-metadata - http://maven.apache.org + https://github.com/SAP/olingo-jpa-processor-v4 UTF-8 - - - junit - junit - 4.12 - test - + + com.sap.olingo odata-jpa-test test ${project.version} + com.sap.olingo odata-jpa-annotation @@ -38,7 +34,7 @@ org.eclipse.persistence javax.persistence - 2.1.0 + 2.2.0 org.apache.olingo @@ -51,14 +47,6 @@ odata-commons-api ${odata.version} - - - org.mockito - mockito-all - 1.9.5 - test - org.apache.olingo odata-server-api @@ -79,7 +67,12 @@ reflections 0.9.11 + + com.google.code.findbugs + jsr305 + 3.0.2 + - + \ No newline at end of file diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/api/JPAEdmProvider.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/api/JPAEdmProvider.java index 6baa966a9..a0d94d229 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/api/JPAEdmProvider.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/api/JPAEdmProvider.java @@ -3,7 +3,9 @@ import java.util.Enumeration; import java.util.List; import java.util.Locale; +import java.util.Objects; +import javax.annotation.Nonnull; import javax.persistence.EntityManagerFactory; import javax.persistence.metamodel.Metamodel; @@ -17,6 +19,7 @@ import org.apache.olingo.commons.api.edm.provider.CsdlEntityContainerInfo; import org.apache.olingo.commons.api.edm.provider.CsdlEntitySet; import org.apache.olingo.commons.api.edm.provider.CsdlEntityType; +import org.apache.olingo.commons.api.edm.provider.CsdlEnumType; import org.apache.olingo.commons.api.edm.provider.CsdlFunction; import org.apache.olingo.commons.api.edm.provider.CsdlFunctionImport; import org.apache.olingo.commons.api.edm.provider.CsdlSchema; @@ -25,9 +28,10 @@ import org.apache.olingo.commons.api.edmx.EdmxReference; import org.apache.olingo.commons.api.ex.ODataException; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEdmNameBuilder; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAServiceDocument; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAException; -import com.sap.olingo.jpa.metadata.core.edm.mapper.impl.JPAEdmNameBuilder; +import com.sap.olingo.jpa.metadata.core.edm.mapper.impl.JPADefaultEdmNameBuilder; import com.sap.olingo.jpa.metadata.core.edm.mapper.impl.JPAServiceDocumentFactory; public class JPAEdmProvider extends CsdlAbstractEdmProvider { @@ -36,22 +40,33 @@ public class JPAEdmProvider extends CsdlAbstractEdmProvider { private final JPAServiceDocument serviceDocument; // http://docs.oasis-open.org/odata/odata/v4.0/errata02/os/complete/part3-csdl/odata-v4.0-errata02-os-part3-csdl-complete.html#_Toc406397930 - public JPAEdmProvider(final String namespace, final EntityManagerFactory emf, - final JPAEdmMetadataPostProcessor postProcessor, final String packageName[]) throws ODataException { - super(); - this.nameBuilder = new JPAEdmNameBuilder(namespace); - serviceDocument = new JPAServiceDocumentFactory(namespace, emf.getMetamodel(), postProcessor, packageName) - .getServiceDocument(); + public JPAEdmProvider(@Nonnull final String namespace, @Nonnull final EntityManagerFactory emf, + final JPAEdmMetadataPostProcessor postProcessor, final String[] packageName) throws ODataException { + this(namespace, Objects.requireNonNull(emf.getMetamodel()), postProcessor, packageName); + } + + public JPAEdmProvider(@Nonnull final String namespace, final Metamodel jpaMetamodel, + final JPAEdmMetadataPostProcessor postProcessor, final String[] packageName) throws ODataException { + + this(jpaMetamodel, postProcessor, packageName, new JPADefaultEdmNameBuilder(namespace)); } - public JPAEdmProvider(final String namespace, final Metamodel jpaMetamodel, - final JPAEdmMetadataPostProcessor postProcessor, final String packageName[]) throws ODataException { + public JPAEdmProvider(final Metamodel jpaMetamodel, final JPAEdmMetadataPostProcessor postProcessor, + final String[] packageName, final JPAEdmNameBuilder nameBuilder) throws ODataException { super(); - this.nameBuilder = new JPAEdmNameBuilder(namespace); - serviceDocument = new JPAServiceDocumentFactory(namespace, jpaMetamodel, postProcessor, packageName) + this.nameBuilder = nameBuilder; + // After this call either a schema exists or an exception has been thrown + this.serviceDocument = new JPAServiceDocumentFactory(nameBuilder, jpaMetamodel, postProcessor, packageName) .getServiceDocument(); } + /** + * This method should return a {@link CsdlComplexType} or null if nothing is found. + * + * @param complexTypeName full qualified name of complex type + * @return for the given name + * @throws ODataException + */ @Override public CsdlComplexType getComplexType(final FullQualifiedName complexTypeName) throws ODataException { for (final CsdlSchema schema : serviceDocument.getAllSchemas()) { @@ -63,35 +78,61 @@ public CsdlComplexType getComplexType(final FullQualifiedName complexTypeName) t return null; } + /** + * Returns the entity container of this edm + * @return of this edm + * @throws ODataException + */ @Override public CsdlEntityContainer getEntityContainer() throws ODataException { return serviceDocument.getEdmEntityContainer(); } + /** + * This method should return an {@link CsdlEntityContainerInfo} or null if nothing is found + * + * @param entityContainerName (null for default container) + * @return for the given name + * @throws ODataException + */ @Override public CsdlEntityContainerInfo getEntityContainerInfo(final FullQualifiedName entityContainerName) throws ODataException { - // This method is invoked when displaying the Service Document at e.g. - // .../DemoService.svc + // This method is invoked when displaying the Service Document at e.g.: .../DemoService.svc if (entityContainerName == null - || entityContainerName.equals(nameBuilder.buildFQN(nameBuilder.buildContainerName()))) { + || entityContainerName.equals(buildFQN(nameBuilder.buildContainerName()))) { final CsdlEntityContainerInfo entityContainerInfo = new CsdlEntityContainerInfo(); - entityContainerInfo.setContainerName(nameBuilder.buildFQN(nameBuilder.buildContainerName())); + entityContainerInfo.setContainerName(buildFQN(nameBuilder.buildContainerName())); return entityContainerInfo; } return null; } + /** + * This method should return an {@link CsdlEntitySet} or null if nothing is found + * + * @param entityContainer this EntitySet is contained in + * @param entitySetName name of entity set + * @return for the given container and entityset name + * @throws ODataException + */ @Override public CsdlEntitySet getEntitySet(final FullQualifiedName entityContainerFQN, final String entitySetName) throws ODataException { final CsdlEntityContainer container = serviceDocument.getEdmEntityContainer(); - if (entityContainerFQN.equals(nameBuilder.buildFQN(container.getName()))) { + if (entityContainerFQN.equals(buildFQN(container.getName()))) { return container.getEntitySet(entitySetName); } return null; } + /** + * This method should return an {@link CsdlEntityType} or null if nothing is found + * + * @param entityTypeName full qualified name of entity type + * @return for the given name + * @throws ODataException + */ @Override public CsdlEntityType getEntityType(final FullQualifiedName entityTypeName) throws ODataException { @@ -103,26 +144,52 @@ public CsdlEntityType getEntityType(final FullQualifiedName entityTypeName) thro return null; } + /** + * This method should return a {@link CsdlFunctionImport} or null if nothing is found + * + * @param entityContainer this FunctionImport is contained in + * @param functionImportName name of function import + * @return for the given container name and function import name + * @throws ODataException + */ @Override public CsdlFunctionImport getFunctionImport(final FullQualifiedName entityContainerFQN, final String functionImportName) throws ODataException { final CsdlEntityContainer container = serviceDocument.getEdmEntityContainer(); - if (entityContainerFQN.equals(nameBuilder.buildFQN(container.getName()))) { + if (entityContainerFQN.equals(buildFQN(container.getName()))) { return container.getFunctionImport(functionImportName); } return null; } + /** + * This method should return a list of all {@link CsdlFunction} for the FullQualifiedname or null if nothing is + * found + * + * @param functionName full qualified name of function + * @return List of or null + * @throws ODataException + */ @Override public List getFunctions(final FullQualifiedName functionName) throws ODataException { for (final CsdlSchema schema : serviceDocument.getEdmSchemas()) { if (schema.getNamespace().equals(functionName.getNamespace())) { - return schema.getFunctions(functionName.getName()); + final List functions = schema.getFunctions(functionName.getName()); + return functions.isEmpty() ? null : functions; } } - return null; + return null; // NOSONAR see documentation } + /** + * This method should return a list of all {@link CsdlAction} for the FullQualifiedname + * or null if nothing is found + * + * @param actionName full qualified name of action + * @return List of + * or null + * @throws ODataException + */ @Override public List getActions(final FullQualifiedName actionName) throws ODataException { for (final CsdlSchema schema : serviceDocument.getEdmSchemas()) { @@ -130,30 +197,77 @@ public List getActions(final FullQualifiedName actionName) throws OD return schema.getActions(actionName.getName()); } } - return null; + return null; // NOSONAR see documentation } + /** + * This method should return an {@link CsdlActionImport} or null if nothing is found + * + * @param entityContainer this ActionImport is contained in + * @param actionImportName name of action import + * @return for the given container and ActionImport name + * @throws ODataException + */ @Override public CsdlActionImport getActionImport(final FullQualifiedName entityContainerFQN, final String actionImportName) throws ODataException { final CsdlEntityContainer container = serviceDocument.getEdmEntityContainer(); - if (entityContainerFQN.equals(nameBuilder.buildFQN(container.getName()))) { + if (entityContainerFQN.equals(buildFQN(container.getName()))) { return container.getActionImport(actionImportName); } return null; } + /** + * This method should return an {@link CsdlEnumType} or null if nothing is found + * + * @param enumTypeName full qualified name of enum type + * @return for given name + * @throws ODataException + */ @Override - public CsdlAnnotations getAnnotationsGroup(final FullQualifiedName targetName, String qualifier) + public CsdlEnumType getEnumType(final FullQualifiedName enumTypeNameFQN) throws ODataException { + + for (final CsdlSchema schema : serviceDocument.getEdmSchemas()) { + if (schema.getNamespace().equals(enumTypeNameFQN.getNamespace())) { + return schema.getEnumType(enumTypeNameFQN.getName()); + } + } + return null; + } + + /** + * Gets annotations group. + * + * @param targetName full qualified name of target + * @param qualifier for the given target. Might be null. + * @return group for the given Target + * @throws ODataException + */ + @Override + public CsdlAnnotations getAnnotationsGroup(final FullQualifiedName targetName, final String qualifier) throws ODataException { return null; } + /** + * This method should return a {@link CsdlTerm} for the FullQualifiedName or null if nothing is found. + * @param termName the name of the Term + * @return or null + * @throws ODataException + */ @Override public CsdlTerm getTerm(final FullQualifiedName termName) throws ODataException { return serviceDocument.getTerm(termName); } + /** + * This method should return an {@link CsdlTypeDefinition} or null if nothing is found + * + * @param typeDefinitionName full qualified name of type definition + * @return for given name + * @throws ODataException + */ @Override public CsdlTypeDefinition getTypeDefinition(final FullQualifiedName typeDefinitionName) throws ODataException { for (final CsdlSchema schema : serviceDocument.getAllSchemas()) { @@ -164,6 +278,12 @@ public CsdlTypeDefinition getTypeDefinition(final FullQualifiedName typeDefiniti return null; } + /** + * This method should return a collection of all {@link CsdlSchema} + * + * @return List of + * @throws ODataException + */ @Override public List getSchemas() throws ODataException { return serviceDocument.getEdmSchemas(); @@ -181,4 +301,12 @@ public List getReferences() { return serviceDocument.getReferences(); } + public JPAEdmNameBuilder getEdmNameBuilder() { + return nameBuilder; + } + + protected final FullQualifiedName buildFQN(final String name) { + return new FullQualifiedName(nameBuilder.getNamespace(), name); + } + } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/api/JPAEntityManagerFactory.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/api/JPAEntityManagerFactory.java index 5dac2b23b..50f23c3b1 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/api/JPAEntityManagerFactory.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/api/JPAEntityManagerFactory.java @@ -11,17 +11,21 @@ public class JPAEntityManagerFactory { private static final String ENTITY_MANAGER_DATA_SOURCE = "javax.persistence.nonJtaDataSource"; private static Map> emfMap; + private JPAEntityManagerFactory() { + throw new IllegalStateException("JPAEntityManagerFactory class"); + } + public static EntityManagerFactory getEntityManagerFactory(final String pUnit, final Map ds) { if (pUnit == null) { return null; } if (emfMap == null) { - emfMap = new HashMap>(); + emfMap = new HashMap<>(); } - Integer dsKey = new Integer(ds.hashCode()); + Integer dsKey = ds.hashCode(); if (emfMap.containsKey(pUnit)) { final Map dsMap = emfMap.get(pUnit); - EntityManagerFactory emf = dsMap.get(ds); + EntityManagerFactory emf = dsMap.get(dsKey); if (emf != null) return emf; @@ -30,7 +34,7 @@ public static EntityManagerFactory getEntityManagerFactory(final String pUnit, f return emf; } else { - final Map dsMap = new HashMap(); + final Map dsMap = new HashMap<>(); emfMap.put(pUnit, dsMap); final EntityManagerFactory emf = Persistence.createEntityManagerFactory(pUnit, ds); dsMap.put(dsKey, emf); @@ -39,9 +43,8 @@ public static EntityManagerFactory getEntityManagerFactory(final String pUnit, f } public static EntityManagerFactory getEntityManagerFactory(final String pUnit, final DataSource ds) { - final Map properties = new HashMap(); + final Map properties = new HashMap<>(); properties.put(ENTITY_MANAGER_DATA_SOURCE, ds); return getEntityManagerFactory(pUnit, properties); } - } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/api/JPAJoinColumn.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/api/JPAJoinColumn.java new file mode 100644 index 000000000..3a00be8ff --- /dev/null +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/api/JPAJoinColumn.java @@ -0,0 +1,17 @@ +/** + * + */ +package com.sap.olingo.jpa.metadata.api; + +/** + * @author Oliver Grande + * Created: 02.02.2020 + * + */ +public interface JPAJoinColumn { + + String getReferencedColumnName(); + + String getName(); + +} diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/AbstractVocabularyReader.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/AbstractVocabularyReader.java new file mode 100644 index 000000000..c50661106 --- /dev/null +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/AbstractVocabularyReader.java @@ -0,0 +1,70 @@ +/** + * + */ +package com.sap.olingo.jpa.metadata.core.edm.mapper.annotation; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.net.URI; +import java.net.URL; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +import javax.annotation.Nonnull; + +import org.apache.olingo.commons.api.edm.provider.CsdlAbstractEdmItem; + +import com.fasterxml.jackson.dataformat.xml.JacksonXmlModule; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; +import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException.MessageKeys; + +/** + * @author Oliver Grande + * Created: 15.12.2019 + * + */ +abstract class AbstractVocabularyReader { + final JacksonXmlModule module; + final XmlMapper xmlMapper; + + /** + * + */ + AbstractVocabularyReader() { + super(); + module = new JacksonXmlModule(); + module.setDefaultUseWrapper(false); + xmlMapper = new XmlMapper(module); + } + + protected String loadXML(@Nonnull final String path) throws IOException, ODataJPAModelException { + final Optional url = Optional.ofNullable(this.getClass().getClassLoader().getResource(path)); + final File file = new File(url.orElseThrow( + () -> new ODataJPAModelException(MessageKeys.FILE_NOT_FOUND, path)).getFile()); + final StringBuilder content = new StringBuilder(); + try (final FileReader reader = new FileReader(file); + final BufferedReader br = new BufferedReader(reader)) { + String line; + while ((line = br.readLine()) != null) { + content.append(line); + } + } + return content.toString(); + } + + protected abstract Map convertEDMX(Edmx edmx); + + public Edmx readFromResource(@Nonnull final String path) throws IOException, ODataJPAModelException { + return xmlMapper.readValue(loadXML(Objects.requireNonNull(path)), Edmx.class); + } + + public Edmx readFromURI(@Nonnull final URI uri) throws IOException { + return xmlMapper.readValue(uri.toURL(), Edmx.class); + + } + +} \ No newline at end of file diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/Action.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/Action.java new file mode 100644 index 000000000..7a5a34648 --- /dev/null +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/Action.java @@ -0,0 +1,43 @@ +package com.sap.olingo.jpa.metadata.core.edm.mapper.annotation; + +import java.util.Arrays; +import java.util.Objects; + +import org.apache.olingo.commons.api.edm.provider.CsdlAction; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class Action extends CsdlAction { + + @Override + @JacksonXmlProperty(localName = "Name") + public CsdlAction setName(final String name) { + Objects.requireNonNull(name, "Name is a required attribute of actions"); + return super.setName(name); + } + + @Override + @JacksonXmlProperty(localName = "IsBound") + public CsdlAction setBound(final boolean isBound) { + return super.setBound(isBound); + } + + @Override + @JacksonXmlProperty(localName = "EntitySetPath") + public CsdlAction setEntitySetPath(String entitySetPath) { + return super.setEntitySetPath(entitySetPath); + } + + @JacksonXmlProperty(localName = "Parameter") + public void setParameters(final Parameter[] parameters) { + this.parameters.addAll(Arrays.asList(parameters)); + } + + @JacksonXmlProperty(localName = "ReturnType") + public void setReturnType(final ReturnType returnType) { + super.setReturnType(returnType); + } + +} diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/AppliesTo.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/AppliesTo.java index 6f2bcd6d1..37c2dec29 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/AppliesTo.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/AppliesTo.java @@ -92,21 +92,21 @@ public enum AppliesTo { private final String value; - AppliesTo(String v) { + private AppliesTo(String v) { value = v; } public String value() { return value; } - - public static AppliesTo fromValue(String v) { - for (AppliesTo c : AppliesTo.values()) { - if (c.value.equals(v)) { - return c; - } - } - throw new IllegalArgumentException(v); - } +// +// public static AppliesTo fromValue(String v) { +// for (AppliesTo c : AppliesTo.values()) { +// if (c.value.equals(v)) { +// return c; +// } +// } +// throw new IllegalArgumentException(v); +// } } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/ComplexType.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/ComplexType.java index 63a4e3aca..51c45c753 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/ComplexType.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/ComplexType.java @@ -1,154 +1,48 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.annotation; -import java.util.ArrayList; -import java.util.List; - -import org.apache.olingo.commons.api.edm.FullQualifiedName; import org.apache.olingo.commons.api.edm.provider.CsdlComplexType; -import org.apache.olingo.commons.api.edm.provider.CsdlNavigationProperty; -import org.apache.olingo.commons.api.edm.provider.CsdlProperty; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonSetter; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +/** + * Complex Type for vocabulary definitions
+ * Not supported: NavigationProperty, no use case known + * @author Oliver Grande + * + */ @JsonIgnoreProperties(ignoreUnknown = true) class ComplexType extends CsdlComplexType { - @JacksonXmlProperty(localName = "Name", isAttribute = true) - private String name; - @JacksonXmlProperty(localName = "Abstract", isAttribute = true) - private Boolean isAbstract; - @JacksonXmlProperty(localName = "OpenType", isAttribute = true) - private Boolean isOpenType; - @JacksonXmlProperty(localName = "BaseType", isAttribute = true) - private FullQualifiedName baseType; - @JacksonXmlProperty(localName = "Property") - private List properties = new ArrayList(); - @JacksonXmlProperty(localName = "NavigationProperty") - private List navigationProperties = new ArrayList(); - -//@JacksonXmlProperty(localName = "Annotation") -//protected List annotations; - @Override - public String getName() { - return name; - } - - @Override - public boolean isOpenType() { - return isOpenType; - } - - @Override - public String getBaseType() { - return baseType.getFullQualifiedNameAsString(); - } - - @Override - public FullQualifiedName getBaseTypeFQN() { - return baseType; - } - - @Override - public boolean isAbstract() { - return isAbstract; - } - @Override - public List getProperties() { - List csdlProperties = new ArrayList(); - - for (Property p : properties) { - csdlProperties.add(p); - } - return csdlProperties; - } - - @Override - public CsdlProperty getProperty(String name) { - - for (Property p : properties) { - if (p.getName().equals(name)) - return p; - } - return null; - } - - @Override - public List getNavigationProperties() { - List csdlNaviProperties = new ArrayList(); - - for (NavigationProperty p : navigationProperties) { - csdlNaviProperties.add(p); - } - return csdlNaviProperties; - } - - @Override - public CsdlNavigationProperty getNavigationProperty(String name) { - - for (NavigationProperty p : navigationProperties) { - if (p.getName().equals(name)) - return p; - } - return null; - } - - @Override - public CsdlComplexType setName(String name) { - this.name = name; - return this; + @JacksonXmlProperty(localName = "Name", isAttribute = true) + public CsdlComplexType setName(final String name) { + return super.setName(name); } @Override - public CsdlComplexType setOpenType(boolean isOpenType) { - this.isOpenType = isOpenType; - return this; - } + @JacksonXmlProperty(localName = "OpenType", isAttribute = true) + public CsdlComplexType setOpenType(final boolean isOpenType) { + return super.setOpenType(isOpenType); - @JsonSetter - @Override - public CsdlComplexType setBaseType(String baseType) { - this.baseType = new FullQualifiedName(baseType); - return this; } @Override - public CsdlComplexType setBaseType(FullQualifiedName baseType) { - this.baseType = baseType; - return this; + @JacksonXmlProperty(localName = "BaseType", isAttribute = true) + public CsdlComplexType setBaseType(final String baseType) { + return super.setBaseType(baseType); } @Override - public CsdlComplexType setAbstract(boolean isAbstract) { - this.isAbstract = isAbstract; - return this; + @JacksonXmlProperty(localName = "Abstract", isAttribute = true) + public CsdlComplexType setAbstract(final boolean isAbstract) { + return super.setAbstract(isAbstract); } - @JsonSetter - void setProperties(Property[] properties) { - for (Property p : properties) { + @JacksonXmlProperty(localName = "Property") + public void setProperties(Property[] properties) { + for (final Property p : properties) { this.properties.add(p); } } - - @JsonSetter - public void setNavigationProperties(NavigationProperty[] navigationProperties) { - for (NavigationProperty p : navigationProperties) { - this.navigationProperties.add(p); - } - } - -// @Override -// public CsdlComplexType setAnnotations(List annotations) { -// // TODO Auto-generated method stub -// return super.setAnnotations(annotations); -// } - -// @Override -// public List getAnnotations() { -// return annotations(); -// } - } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/EntityKeyElement.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/EntityKeyElement.java deleted file mode 100644 index bc18fdae0..000000000 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/EntityKeyElement.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.sap.olingo.jpa.metadata.core.edm.mapper.annotation; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.olingo.commons.api.edm.provider.CsdlPropertyRef; - -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; - -public class EntityKeyElement { - - @JacksonXmlProperty(localName = "PropertyRef") - protected List propertyRefs; - - List getPropertyRef() { - List csdlPropertyRefs = new ArrayList(); - for (PropertyRef p : propertyRefs) { - csdlPropertyRefs.add(p); - } - return csdlPropertyRefs; - } - -} diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/EntityType.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/EntityType.java deleted file mode 100644 index cab6cc369..000000000 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/EntityType.java +++ /dev/null @@ -1,132 +0,0 @@ -package com.sap.olingo.jpa.metadata.core.edm.mapper.annotation; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.olingo.commons.api.edm.FullQualifiedName; -import org.apache.olingo.commons.api.edm.provider.CsdlEntityType; -import org.apache.olingo.commons.api.edm.provider.CsdlNavigationProperty; -import org.apache.olingo.commons.api.edm.provider.CsdlProperty; -import org.apache.olingo.commons.api.edm.provider.CsdlPropertyRef; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class EntityType extends CsdlEntityType { - -//protected List keyOrPropertyOrNavigationProperty; - - @JacksonXmlProperty(localName = "Name", isAttribute = true) - private String name; - @JacksonXmlProperty(localName = "Abstract", isAttribute = true) - private Boolean isAbstract; - @JacksonXmlProperty(localName = "BaseType", isAttribute = true) - private String baseType; - @JacksonXmlProperty(localName = "OpenType", isAttribute = true) - protected Boolean isOpenType; - @JacksonXmlProperty(localName = "HasStream", isAttribute = true) - protected Boolean hasStream; - - @JacksonXmlProperty(localName = "Property") - private List properties; - @JacksonXmlProperty(localName = "NavigationProperty") - private List navigationProperties; - @JacksonXmlProperty(localName = "Key") - private List key; -//@XmlElement(name = "Annotation", type = Annotation.class) - - @Override - public boolean hasStream() { - return hasStream; - } - - @Override - public List getKey() { -// - if (key != null || !key.isEmpty()) - return key.get(0).getPropertyRef(); - return new ArrayList(); - } - - @Override - public String getName() { - return name; - } - - @Override - public boolean isOpenType() { - return isOpenType; - } - - @Override - public String getBaseType() { - return baseType; - } - - @Override - public FullQualifiedName getBaseTypeFQN() { - return new FullQualifiedName(baseType); - } - - @Override - public boolean isAbstract() { - return isAbstract; - } - - @Override - public List getProperties() { - List csdlProperties = new ArrayList(); - - for (Property p : properties) { - csdlProperties.add(p); - } - return csdlProperties; - } - - @Override - public CsdlProperty getProperty(String name) { - - for (Property p : properties) { - if (p.getName().equals(name)) - return p; - } - return null; - } - - @Override - public List getNavigationProperties() { - List csdlNaviProperties = new ArrayList(); - - for (NavigationProperty p : navigationProperties) { - csdlNaviProperties.add(p); - } - return csdlNaviProperties; - } - - @Override - public CsdlNavigationProperty getNavigationProperty(String name) { - - for (NavigationProperty p : navigationProperties) { - if (p.getName().equals(name)) - return p; - } - return null; - } - -// @Override -// public List getAnnotations() { -// // TODO Auto-generated method stub -// return super.getAnnotations(); -// } - -// @Override -// protected T getOneByName(String name, Collection items) { -// return super.getOneByName(name, items); -// } - -// @Override -// protected List getAllByName(String name, Collection items) { -// return super.getAllByName(name, items); -// } -} diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/EnumType.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/EnumType.java index c3f136b74..177ba1139 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/EnumType.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/EnumType.java @@ -1,105 +1,35 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.annotation; -import java.util.ArrayList; -import java.util.List; - -import org.apache.olingo.commons.api.edm.FullQualifiedName; -import org.apache.olingo.commons.api.edm.provider.CsdlEnumMember; import org.apache.olingo.commons.api.edm.provider.CsdlEnumType; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonSetter; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; @JsonIgnoreProperties(ignoreUnknown = true) public class EnumType extends CsdlEnumType { - @JacksonXmlProperty(localName = "Name", isAttribute = true) - private String name; - - @JacksonXmlProperty(localName = "IsFlags", isAttribute = true) - private boolean isFlags; - - @JacksonXmlProperty(localName = "UnderlyingType") - private FullQualifiedName underlyingType; - - @JacksonXmlProperty(localName = "Member") - private Member[] members; - @Override - public String getName() { - return name; - } - - @Override - public boolean isFlags() { - return isFlags; + @JacksonXmlProperty(localName = "Name", isAttribute = true) + public CsdlEnumType setName(final String name) { + return super.setName(name); } @Override - public String getUnderlyingType() { - return underlyingType.getFullQualifiedNameAsString(); + @JacksonXmlProperty(localName = "IsFlags", isAttribute = true) + public CsdlEnumType setFlags(final boolean isFlags) { + return super.setFlags(isFlags); } @Override - public List getMembers() { - List csdlMembers = new ArrayList(); - for (CsdlEnumMember m : members) { - csdlMembers.add(m); - } - return csdlMembers; + @JacksonXmlProperty(localName = "UnderlyingType") + public CsdlEnumType setUnderlyingType(final String underlyingType) { + return super.setUnderlyingType(underlyingType); } - @Override - public CsdlEnumMember getMember(String name) { - for (CsdlEnumMember m : members) { - if (m.getName().equals(name)) - return super.getMember(name); + @JacksonXmlProperty(localName = "Member") + public void setMembers(final Member[] members) { + for (final Member m : members) { + this.getMembers().add(m); } - return null; - } - - @Override - public CsdlEnumMember getMember(Integer index) { - return members[index]; - } - - @Override - public CsdlEnumType setName(String name) { - this.name = name; - return this; } - - @Override - public CsdlEnumType setFlags(boolean isFlags) { - this.isFlags = isFlags; - return this; - } - - @Override - @JsonSetter - public CsdlEnumType setUnderlyingType(String underlyingType) { - this.underlyingType = new FullQualifiedName(underlyingType); - return this; - } - - @Override - public CsdlEnumType setUnderlyingType(FullQualifiedName underlyingType) { - this.underlyingType = underlyingType; - return this; - } - - @JsonSetter - public void setMembers(Member[] members) { - this.members = members; - } - -// @Override -// public List getAnnotations() { -// return annotations; -// } - -//@JacksonXmlProperty(localName = "Annotation") -//protected List annotations; - } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/Function.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/Function.java new file mode 100644 index 000000000..cf5108f0f --- /dev/null +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/Function.java @@ -0,0 +1,53 @@ +package com.sap.olingo.jpa.metadata.core.edm.mapper.annotation; + +import java.util.Arrays; +import java.util.Objects; + +import org.apache.olingo.commons.api.edm.provider.CsdlFunction; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; + +/** + * Function as part of a OData vocabulary.
+ * @author Oliver Grande + * + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class Function extends CsdlFunction { + + @Override + @JacksonXmlProperty(localName = "IsBound") + public CsdlFunction setBound(final boolean isBound) { + return super.setBound(isBound); + } + + @Override + @JacksonXmlProperty(localName = "IsComposable") + public CsdlFunction setComposable(final boolean isComposable) { + return super.setComposable(isComposable); + } + + @Override + @JacksonXmlProperty(localName = "EntitySetPath") + public CsdlFunction setEntitySetPath(String entitySetPath) { + return super.setEntitySetPath(entitySetPath); + } + + @Override + @JacksonXmlProperty(localName = "Name") + public CsdlFunction setName(final String name) { + Objects.requireNonNull(name, "Name is a required attribute of functions"); + return super.setName(name); + } + + @JacksonXmlProperty(localName = "Parameter") + public void setParameters(final Parameter[] parameters) { + this.parameters.addAll(Arrays.asList(parameters)); + } + + @JacksonXmlProperty(localName = "ReturnType") + public void setReturnType(final ReturnType returnType) { + super.setReturnType(returnType); + } +} diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/Member.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/Member.java index 3ebee0bdb..1896c8327 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/Member.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/Member.java @@ -8,31 +8,15 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class Member extends CsdlEnumMember { - @JacksonXmlProperty(localName = "Name", isAttribute = true) - private String name; - - @JacksonXmlProperty(localName = "Value", isAttribute = true) - private String value; - - @Override - public String getName() { - return name; - } - - @Override - public String getValue() { - return value; - } - @Override - public CsdlEnumMember setName(String name) { - this.name = name; - return this; + @JacksonXmlProperty(localName = "Name", isAttribute = true) + public CsdlEnumMember setName(final String name) { + return super.setName(name); } @Override - public CsdlEnumMember setValue(String value) { - this.value = value; - return this; + @JacksonXmlProperty(localName = "Value", isAttribute = true) + public CsdlEnumMember setValue(final String value) { + return super.setValue(value); } } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/NavigationProperty.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/NavigationProperty.java deleted file mode 100644 index a4d97fb38..000000000 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/NavigationProperty.java +++ /dev/null @@ -1,148 +0,0 @@ -package com.sap.olingo.jpa.metadata.core.edm.mapper.annotation; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.olingo.commons.api.edm.FullQualifiedName; -import org.apache.olingo.commons.api.edm.provider.CsdlNavigationProperty; -import org.apache.olingo.commons.api.edm.provider.CsdlReferentialConstraint; - -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; - -public class NavigationProperty extends CsdlNavigationProperty { - - @JacksonXmlProperty(localName = "Name", isAttribute = true) - private String name; - @JacksonXmlProperty(localName = "Type", isAttribute = true) - private FullQualifiedName type; - @JacksonXmlProperty(localName = "Nullable", isAttribute = true) - private Boolean isNullable; - @JacksonXmlProperty(localName = "Partner", isAttribute = true) - private String partner; - @JacksonXmlProperty(localName = "ContainsTarget", isAttribute = true) - private Boolean containsTarget; - - @JacksonXmlProperty(localName = "ReferentialConstraint") - List referentialConstraints; - -// @JacksonXmlProperty(localName = "OnDelete") -// List oneDelete; - - @Override - public String getName() { - return name; - } - - @Override - public boolean isCollection() { - return super.isCollection(); - } - - @Override - public FullQualifiedName getTypeFQN() { - // TODO Auto-generated method stub - return super.getTypeFQN(); - } - - @Override - public String getType() { - // TODO Auto-generated method stub - return super.getType(); - } - - @Override - public String getPartner() { - return partner; - } - - @Override - public boolean isContainsTarget() { - return containsTarget; - } - - @Override - public List getReferentialConstraints() { - List csdlConstraints = new ArrayList(); - for (CsdlReferentialConstraint rc : referentialConstraints) { - csdlConstraints.add(rc); - } - return csdlConstraints; - } - - @Override - public Boolean isNullable() { - return isNullable; - } - - @Override - public CsdlNavigationProperty setCollection(boolean isCollection) { - return this; - } - - @Override - public CsdlNavigationProperty setName(String name) { - this.name = name; - return this; - } - - @Override - public CsdlNavigationProperty setType(FullQualifiedName type) { - this.type = type; - return this; - } - - @JsonSetter - @Override - public CsdlNavigationProperty setType(String type) { - this.type = new FullQualifiedName(type); - return this; - } - - @Override - public CsdlNavigationProperty setPartner(String partner) { - this.partner = partner; - return this; - } - - @Override - public CsdlNavigationProperty setContainsTarget(boolean containsTarget) { - this.containsTarget = containsTarget; - return this; - } - - @Override - public CsdlNavigationProperty setReferentialConstraints(List referentialConstraints) { - return this; - } - - @JsonSetter - void setReferentialConstraints(ReferentialConstraint[] referentialConstraints) { - for (ReferentialConstraint rc : referentialConstraints) { - this.referentialConstraints.add(rc); - } - } - - @Override - public CsdlNavigationProperty setNullable(Boolean nullable) { - this.isNullable = nullable; - return this; - } - -// @Override -// public List getAnnotations() { -// return super.getAnnotations(); -// } - -// @Override -// public CsdlOnDelete getOnDelete() { -// // TODO Auto-generated method stub -// return super.getOnDelete(); -// } - -// @Override -// public List getAnnotations() { -// // TODO Auto-generated method stub -// return super.getAnnotations(); -// } -} diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/Parameter.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/Parameter.java new file mode 100644 index 000000000..ec8b05d29 --- /dev/null +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/Parameter.java @@ -0,0 +1,62 @@ +package com.sap.olingo.jpa.metadata.core.edm.mapper.annotation; + +import java.util.Objects; + +import org.apache.olingo.commons.api.edm.FullQualifiedName; +import org.apache.olingo.commons.api.edm.geo.SRID; +import org.apache.olingo.commons.api.edm.provider.CsdlParameter; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class Parameter extends CsdlParameter { + + @Override + @JacksonXmlProperty(localName = "Name") + public CsdlParameter setName(final String name) { + Objects.requireNonNull(name, "Name is a required attribute of parameter"); + return super.setName(name); + } + + @Override + @JacksonXmlProperty(localName = "Type") + public CsdlParameter setType(final String type) { + Objects.requireNonNull(type, "Type is a required attribute of parameters"); + if (type.startsWith("Collection")) { + setCollection(true); + return super.setType(new FullQualifiedName(type.split("[()]")[1])); + } + return super.setType(new FullQualifiedName(type)); + } + + @Override + @JacksonXmlProperty(localName = "Nullable") + public CsdlParameter setNullable(final boolean nullable) { + return super.setNullable(nullable); + } + + @Override + @JacksonXmlProperty(localName = "MaxLength", isAttribute = true) + public CsdlParameter setMaxLength(Integer maxLength) { + return super.setMaxLength(maxLength); + } + + @Override + @JacksonXmlProperty(localName = "Precision", isAttribute = true) + public CsdlParameter setPrecision(final Integer precision) { + return super.setPrecision(precision); + } + + @Override + @JacksonXmlProperty(localName = "Scale", isAttribute = true) + public CsdlParameter setScale(final Integer scale) { + return super.setScale(scale); + } + + @JacksonXmlProperty(localName = "SRID", isAttribute = true) + void setSrid(final String srid) { + Objects.requireNonNull(srid); + super.setSrid(SRID.valueOf(srid)); + } +} diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/Property.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/Property.java index a66b6fc9e..4d29923d6 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/Property.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/Property.java @@ -1,187 +1,74 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.annotation; +import java.util.Objects; + import org.apache.olingo.commons.api.edm.FullQualifiedName; import org.apache.olingo.commons.api.edm.geo.SRID; -import org.apache.olingo.commons.api.edm.provider.CsdlMapping; import org.apache.olingo.commons.api.edm.provider.CsdlProperty; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonSetter; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; @JsonIgnoreProperties(ignoreUnknown = true) public class Property extends CsdlProperty { - @JacksonXmlProperty(localName = "Name", isAttribute = true) - private String name; - @JacksonXmlProperty(localName = "Type", isAttribute = true) - private FullQualifiedName type; - @JacksonXmlProperty(localName = "Nullable", isAttribute = true) - private Boolean isNullable; - @JacksonXmlProperty(localName = "DefaultValue", isAttribute = true) - private String defaultValue; - @JacksonXmlProperty(localName = "Unicode", isAttribute = true) - private Boolean isUnicode; - @JacksonXmlProperty(localName = "MaxLength", isAttribute = true) - private Integer maxLength; - @JacksonXmlProperty(localName = "Precision", isAttribute = true) - private Integer precision; - @JacksonXmlProperty(localName = "Scale", isAttribute = true) - private Integer scale; - @JacksonXmlProperty(localName = "SRID", isAttribute = true) - private SRID srid; - - @Override - public String getName() { - return name; - } - - @Override - public String getType() { - // TODO Auto-generated method stub - return super.getType(); - } - - @Override - public FullQualifiedName getTypeAsFQNObject() { - // TODO Auto-generated method stub - return super.getTypeAsFQNObject(); - } - - @Override - public boolean isCollection() { -// final int collStartIdx = typeExpression.indexOf("Collection("); -// final int collEndIdx = typeExpression.lastIndexOf(')'); - return false; - } - - @Override - public String getDefaultValue() { - return defaultValue; - } - - @Override - public boolean isNullable() { - return isNullable; - } - - @Override - public Integer getMaxLength() { - return new Integer(maxLength); - } - - @Override - public Integer getPrecision() { - return precision; - } - - @Override - public Integer getScale() { - return scale; - } - @Override - public boolean isUnicode() { - return isUnicode; - } - - @Override - public String getMimeType() { - return super.getMimeType(); - } - - @Override - public CsdlMapping getMapping() { - return super.getMapping(); - } - - @Override - public SRID getSrid() { - return srid; - } - - @Override - public CsdlProperty setName(String name) { - this.name = name; - return this; - } - - @Override - public CsdlProperty setType(FullQualifiedName type) { - this.type = type; - return this; - } - - @JsonSetter - @Override - public CsdlProperty setType(String type) { - this.type = new FullQualifiedName(type); - return this; - } - - @Override - public CsdlProperty setCollection(boolean isCollection) { - return this; - } - - @Override - public CsdlProperty setDefaultValue(String defaultValue) { - this.defaultValue = defaultValue; - return this; - } - - @Override - public CsdlProperty setNullable(boolean nullable) { - this.isNullable = nullable; - return this; + @JacksonXmlProperty(localName = "Name", isAttribute = true) + public CsdlProperty setName(final String name) { + Objects.requireNonNull(name); + return super.setName(name); } @Override - public CsdlProperty setMaxLength(Integer maxLength) { - this.maxLength = maxLength; - return this; + @JacksonXmlProperty(localName = "Type", isAttribute = true) + public CsdlProperty setType(final String type) { + Objects.requireNonNull(type); + if (type.startsWith("Collection")) { + setCollection(true); + return super.setType(new FullQualifiedName(type.split("[()]")[1])); + } + return super.setType(new FullQualifiedName(type)); } @Override - public CsdlProperty setPrecision(Integer precision) { - this.precision = precision; - return this; + @JacksonXmlProperty(localName = "DefaultValue", isAttribute = true) + public CsdlProperty setDefaultValue(final String defaultValue) { + return super.setDefaultValue(defaultValue); } @Override - public CsdlProperty setScale(Integer scale) { - this.scale = scale; - return this; + @JacksonXmlProperty(localName = "Nullable", isAttribute = true) + public CsdlProperty setNullable(final boolean nullable) { + return super.setNullable(nullable); } @Override - public CsdlProperty setUnicode(boolean unicode) { - this.isUnicode = unicode; - return this; + @JacksonXmlProperty(localName = "MaxLength", isAttribute = true) + public CsdlProperty setMaxLength(final Integer maxLength) { + return super.setMaxLength(maxLength); } @Override - public CsdlProperty setMimeType(String mimeType) { - return this; + @JacksonXmlProperty(localName = "Precision", isAttribute = true) + public CsdlProperty setPrecision(final Integer precision) { + return super.setPrecision(precision); } @Override - public CsdlProperty setMapping(CsdlMapping mapping) { - return this; + @JacksonXmlProperty(localName = "Scale", isAttribute = true) + public CsdlProperty setScale(final Integer scale) { + return super.setScale(scale); } @Override - public CsdlProperty setSrid(SRID srid) { - this.srid = srid; - return this; + @JacksonXmlProperty(localName = "Unicode", isAttribute = true) + public CsdlProperty setUnicode(final boolean unicode) { + return super.setUnicode(unicode); } - @JsonSetter - void setSrid(String srid) { - if (srid != null) - this.srid = SRID.valueOf(srid); - else - this.srid = null; + @JacksonXmlProperty(localName = "SRID", isAttribute = true) + void setSrid(final String srid) { + Objects.requireNonNull(srid); + super.setSrid(SRID.valueOf(srid)); } - } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/PropertyRef.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/PropertyRef.java deleted file mode 100644 index c0f5ed156..000000000 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/PropertyRef.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.sap.olingo.jpa.metadata.core.edm.mapper.annotation; - -import org.apache.olingo.commons.api.edm.provider.CsdlPropertyRef; - -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; - -public class PropertyRef extends CsdlPropertyRef { - - @JacksonXmlProperty(localName = "Name", isAttribute = true) - private String name; - - @JacksonXmlProperty(localName = "Alias", isAttribute = true) - private String alias; - - @Override - public String getName() { - return name; - } - - @Override - public String getAlias() { - return alias; - } -} diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/ReferentialConstraint.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/ReferentialConstraint.java deleted file mode 100644 index ebac51c62..000000000 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/ReferentialConstraint.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.sap.olingo.jpa.metadata.core.edm.mapper.annotation; - -import org.apache.olingo.commons.api.edm.provider.CsdlReferentialConstraint; - -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; - -public class ReferentialConstraint extends CsdlReferentialConstraint { - - @JacksonXmlProperty(localName = "Property", isAttribute = true) - protected String property; - @JacksonXmlProperty(localName = "ReferencedProperty", isAttribute = true) - protected String referencedProperty; - - @Override - public String getProperty() { - return property; - } - - @Override - public String getReferencedProperty() { - return referencedProperty; - } - -// @Override -// public List getAnnotations() { -// return super.getAnnotations(); -// } - -// @XmlElement(name = "Annotation") -// protected List annotation; -} diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/ReturnType.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/ReturnType.java new file mode 100644 index 000000000..787396299 --- /dev/null +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/ReturnType.java @@ -0,0 +1,56 @@ +package com.sap.olingo.jpa.metadata.core.edm.mapper.annotation; + +import java.util.Objects; + +import org.apache.olingo.commons.api.edm.FullQualifiedName; +import org.apache.olingo.commons.api.edm.geo.SRID; +import org.apache.olingo.commons.api.edm.provider.CsdlReturnType; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class ReturnType extends CsdlReturnType { + + @Override + @JacksonXmlProperty(localName = "Type") + public CsdlReturnType setType(final String type) { + Objects.requireNonNull(type, "Type is a required attribute of return type"); + if (type.startsWith("Collection")) { + setCollection(true); + return super.setType(new FullQualifiedName(type.split("[()]")[1])); + } + return super.setType(new FullQualifiedName(type)); + } + + @Override + @JacksonXmlProperty(localName = "Nullable") + public CsdlReturnType setNullable(final boolean nullable) { + return super.setNullable(nullable); + } + + @Override + @JacksonXmlProperty(localName = "MaxLength", isAttribute = true) + public CsdlReturnType setMaxLength(final Integer maxLength) { + return super.setMaxLength(maxLength); + } + + @Override + @JacksonXmlProperty(localName = "Precision", isAttribute = true) + public CsdlReturnType setPrecision(final Integer precision) { + return super.setPrecision(precision); + } + + @Override + @JacksonXmlProperty(localName = "Scale", isAttribute = true) + public CsdlReturnType setScale(final Integer scale) { + return super.setScale(scale); + } + + @JacksonXmlProperty(localName = "SRID", isAttribute = true) + void setSrid(final String srid) { + Objects.requireNonNull(srid); + super.setSrid(SRID.valueOf(srid)); + } + +} diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/Schema.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/Schema.java index f902c739b..d02b00ce9 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/Schema.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/Schema.java @@ -1,14 +1,14 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.annotation; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; -import javax.xml.bind.annotation.XmlAccessOrder; -import javax.xml.bind.annotation.XmlAccessorOrder; - +import org.apache.olingo.commons.api.edm.provider.CsdlAction; import org.apache.olingo.commons.api.edm.provider.CsdlComplexType; import org.apache.olingo.commons.api.edm.provider.CsdlEnumType; +import org.apache.olingo.commons.api.edm.provider.CsdlFunction; import org.apache.olingo.commons.api.edm.provider.CsdlSchema; import org.apache.olingo.commons.api.edm.provider.CsdlTerm; import org.apache.olingo.commons.api.edm.provider.CsdlTypeDefinition; @@ -17,7 +17,12 @@ import com.fasterxml.jackson.annotation.JsonSetter; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; -@XmlAccessorOrder(XmlAccessOrder.UNDEFINED) +/** + * http://docs.oasis-open.org/odata/ns/edmx + * @author Oliver Grande + * + */ + @JsonIgnoreProperties(ignoreUnknown = true) class Schema { @JacksonXmlProperty(isAttribute = true) @@ -30,19 +35,22 @@ class Schema { private String alias; @JacksonXmlProperty(localName = "EnumType") - private List enumerations = new ArrayList(); + private List enumerations = new ArrayList<>(); @JacksonXmlProperty(localName = "TypeDefinition") - private List typeDefinitions = new ArrayList(); -// -// @JacksonXmlProperty(localName = "EntityType") -// private List entityTypes = new ArrayList(); -// + private List typeDefinitions = new ArrayList<>(); + @JacksonXmlProperty(localName = "ComplexType") - private List complexTypes = new ArrayList(); + private List complexTypes = new ArrayList<>(); @JacksonXmlProperty(localName = "Term") - private List terms = new ArrayList(); + private List terms = new ArrayList<>(); + + @JacksonXmlProperty(localName = "Function") + private List functions = new ArrayList<>(); + + @JacksonXmlProperty(localName = "Action") + private List actions = new ArrayList<>(); CsdlSchema asCsdlSchema() { CsdlSchema csdlSchema = new CsdlSchema(); @@ -52,143 +60,73 @@ CsdlSchema asCsdlSchema() { csdlSchema.setEnumTypes(asEnumTypes()); csdlSchema.setComplexTypes(asComplexTypes()); csdlSchema.setTypeDefinitions(asTypeDefinitions()); + csdlSchema.setFunctions(asFunctions()); + csdlSchema.setActions(asActions()); return csdlSchema; } - String getAlias() { - return alias; - } - - ComplexType getComplexType(String name) { - - for (ComplexType c : complexTypes) { - if (c.getName().equals(name)) { - return c; - } - } - return null; - } - - List getComplexTypes() { - return Collections.unmodifiableList(complexTypes); - } - - private List asComplexTypes() { - List csdlComplexType = new ArrayList(); - - for (ComplexType c : complexTypes) { - csdlComplexType.add(c); - } - return Collections.unmodifiableList(csdlComplexType); - } - - EnumType getEnumType(String name) { - for (EnumType e : enumerations) { - if (e.getName().equals(name)) { - return e; - } - } - return null; - } - - List getEnumTypes() { - return Collections.unmodifiableList(enumerations); - } - - private List asEnumTypes() { - List csdlEnumType = new ArrayList(); - - for (EnumType e : enumerations) { - csdlEnumType.add(e); - } - return Collections.unmodifiableList(csdlEnumType); - } - String getNamespace() { return namespace; } - TypeDefinition getTypeDefinition(String name) { - - for (TypeDefinition e : typeDefinitions) { - if (e.getName().equals(name)) { - return e; - } - } - return null; + List getTerms() { + return Collections.unmodifiableList(terms); } - List getTypeDefinitions() { - return Collections.unmodifiableList(typeDefinitions); + void setAlias(String alias) { + this.alias = alias; } - private List asTypeDefinitions() { - List csdlTypeDefinion = new ArrayList(); + @JsonSetter + void setComplexTypes(ComplexType[] newComplexTypes) { + complexTypes.addAll(Arrays.asList(newComplexTypes)); + } - for (TypeDefinition t : typeDefinitions) { - csdlTypeDefinion.add(t); - } - return Collections.unmodifiableList(csdlTypeDefinion); + @JsonSetter + void setEnumerations(EnumType enumeration) { + this.enumerations.add(enumeration); } - void setAlias(String alias) { - this.alias = alias; + @JsonSetter + void setFunctions(Function[] newFunctions) { + functions.addAll(Arrays.asList(newFunctions)); } void setNamespace(String namespace) { this.namespace = namespace; } - /* - * <element name="Action" type="{http://docs.oasis-open.org/odata/ns/edm}TAction"/> - * <element name="Function" type="{http://docs.oasis-open.org/odata/ns/edm}TFunction"/> - * <element name="Annotations" type="{http://docs.oasis-open.org/odata/ns/edm}TAnnotations"/> - * <element name="EntityContainer" type="{http://docs.oasis-open.org/odata/ns/edm}TEntityContainer"/> - * <element ref="{http://docs.oasis-open.org/odata/ns/edm}Annotation"/> - */ - Term getTerm(String name) { - for (Term t : terms) { - if (t.getName().equals(name)) { - return t; - } - } - return null; + @JsonSetter + void setTerms(Term[] newTerms) { + terms.addAll(Arrays.asList(newTerms)); } - List getTerms() { - return Collections.unmodifiableList(terms); + @JsonSetter + void setTypeDefinitions(TypeDefinition typeDefinition) { + this.typeDefinitions.add(typeDefinition); } - private List asCsdlTerms() { - List csdlTerms = new ArrayList(); + private List asActions() { + return Collections.unmodifiableList(actions); + } - for (Term t : terms) { - csdlTerms.add(t); - } - return Collections.unmodifiableList(csdlTerms); + private List asComplexTypes() { + return Collections.unmodifiableList(complexTypes); } - @JsonSetter - void setComplexTypes(ComplexType[] newComplexTypes) { - for (ComplexType t : newComplexTypes) { - complexTypes.add(t); - } + private List asCsdlTerms() { + return Collections.unmodifiableList(terms); } - @JsonSetter - void setEnumerations(ArrayList enumerations) { - this.enumerations = enumerations; + private List asEnumTypes() { + return Collections.unmodifiableList(enumerations); } - @JsonSetter - void setTerms(Term[] newTerms) { - for (Term t : newTerms) { - terms.add(t); - } + private List asFunctions() { + return Collections.unmodifiableList(functions); } - @JsonSetter - void setTypeDefinitions(ArrayList typeDefinitions) { - this.typeDefinitions = typeDefinitions; + private List asTypeDefinitions() { + return Collections.unmodifiableList(typeDefinitions); } } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/SchemaReader.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/SchemaReader.java index 0ef01b91c..5ef723e03 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/SchemaReader.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/SchemaReader.java @@ -1,83 +1,37 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.annotation; import java.io.IOException; -import java.io.InputStream; -import java.net.MalformedURLException; import java.net.URI; -import java.net.URL; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import org.apache.olingo.commons.api.edm.provider.CsdlSchema; -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.fasterxml.jackson.dataformat.xml.JacksonXmlModule; -import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; -public class SchemaReader { - final private JacksonXmlModule module; - final private XmlMapper xmlMapper; +public class SchemaReader extends AbstractVocabularyReader { public SchemaReader() { super(); - module = new JacksonXmlModule(); - module.setDefaultUseWrapper(false); - xmlMapper = new XmlMapper(module); - - } - - public Map getSchemas(String path) throws JsonParseException, - JsonMappingException, IOException { - return convertEDMX(readFromResource(path)); - } - - public Map getSchemas(URI uri) throws JsonParseException, - JsonMappingException, MalformedURLException, IOException { - return convertEDMX(readFromURI(uri)); - } - - public Edmx readFromResource(final String path) throws JsonParseException, JsonMappingException, IOException { - - byte[] b = loadXML(path); - return xmlMapper.readValue(new String(b), Edmx.class); } - public Edmx readFromURI(final URI uri) throws JsonParseException, JsonMappingException, MalformedURLException, - IOException { - - return xmlMapper.readValue(uri.toURL(), Edmx.class); - + public Map getSchemas(final String path) throws IOException, ODataJPAModelException { + return path == null || path.isEmpty() ? Collections.emptyMap() : convertEDMX(readFromResource(path)); } - private byte[] loadXML(String path) { - - InputStream i = null; - byte[] image = null; - URL u = this.getClass().getClassLoader().getResource(path); - try { - i = u.openStream(); - image = new byte[i.available()]; - i.read(image); - } catch (IOException e1) { - e1.printStackTrace(); - } finally { - try { - i.close(); - return image; - } catch (IOException e) { - e.printStackTrace(); - } - } - return null; + public Map getSchemas(final URI uri) throws IOException { + return uri == null ? Collections.emptyMap() : convertEDMX(readFromURI(uri)); } - private Map convertEDMX(Edmx edmx) { + @SuppressWarnings("unchecked") + @Override + protected Map convertEDMX(Edmx edmx) { if (edmx != null && edmx.getDataService() != null) { Schema[] schemas = edmx.getDataService().getSchemas(); - Map edmSchemas = new HashMap(schemas.length); + Map edmSchemas = new HashMap<>(schemas.length); for (Schema schema : schemas) { String namespace = schema.getNamespace(); edmSchemas.put(namespace, schema.asCsdlSchema()); diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/Term.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/Term.java index 755e1a121..a8003aaa3 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/Term.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/Term.java @@ -1,178 +1,84 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.annotation; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import org.apache.olingo.commons.api.edm.geo.SRID; import org.apache.olingo.commons.api.edm.provider.CsdlTerm; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonSetter; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; @JsonIgnoreProperties(ignoreUnknown = true) class Term extends CsdlTerm { - Term() { - super(); - } - - @JacksonXmlProperty(localName = "Name", isAttribute = true) - private String name; - - @JacksonXmlProperty(localName = "Type", isAttribute = true) - private String type; - - @JacksonXmlProperty(localName = "BaseTerm", isAttribute = true) - private String baseTerm; - - @JacksonXmlProperty(localName = "Nullable", isAttribute = true) - private boolean nullable; - - @JacksonXmlProperty(localName = "DefaultValue", isAttribute = true) - private String defaultValue; - @JacksonXmlProperty(localName = "AppliesTo", isAttribute = true) - private String appliesTo; - - @JacksonXmlProperty(localName = "MaxLength", isAttribute = true) - private int maxLength; - - @JacksonXmlProperty(localName = "Precision", isAttribute = true) - private int precision; - - @JacksonXmlProperty(localName = "Scale", isAttribute = true) - private int scale; - - @JacksonXmlProperty(localName = "SRID", isAttribute = true) - private SRID srid; - - @Override - public String getName() { - return name; - } - - @Override - public String getType() { - return type; - } - - @Override - public String getBaseTerm() { - return baseTerm; - } - - @Override - public boolean isNullable() { - return nullable; - } - - @Override - public String getDefaultValue() { - return defaultValue; - } - - @Override - public List getAppliesTo() { - List result = new ArrayList(); + void setAppliesTo(final String appliesTo) { + final List result = new ArrayList<>(); if (appliesTo != null) { String[] list = appliesTo.split(" "); - for (String apply : list) { - result.add(apply); - } + result.addAll(Arrays.asList(list)); } - return result; - } - - @Override - public Integer getMaxLength() { - return maxLength; - } - - @Override - public Integer getPrecision() { - return precision; - } - - @Override - public Integer getScale() { - return scale; - } - - @Override - public SRID getSrid() { - return srid; - } - - @JsonSetter - void setAppliesTo(String appliesTo) { - this.appliesTo = appliesTo; - } - - @Override - public CsdlTerm setName(String name) { - this.name = name; - return this; + super.setAppliesTo(result); } @Override - public CsdlTerm setType(String type) { - this.type = type; - return this; + @JacksonXmlProperty(localName = "Name", isAttribute = true) + public CsdlTerm setName(final String name) { + return super.setName(name); } @Override - public CsdlTerm setBaseTerm(String baseTerm) { - this.baseTerm = baseTerm; - return this; + @JacksonXmlProperty(localName = "Type", isAttribute = true) + public CsdlTerm setType(final String type) { + return super.setType(type); } @Override - public CsdlTerm setAppliesTo(List appliesTo) { - return this; + @JacksonXmlProperty(localName = "BaseTerm", isAttribute = true) + public CsdlTerm setBaseTerm(final String baseTerm) { + return super.setBaseTerm(baseTerm); } @Override - public CsdlTerm setDefaultValue(String defaultValue) { - this.defaultValue = defaultValue; + public CsdlTerm setAppliesTo(final List appliesTo) { return this; } @Override - public CsdlTerm setNullable(boolean nullable) { - this.nullable = nullable; - return this; + @JacksonXmlProperty(localName = "DefaultValue", isAttribute = true) + public CsdlTerm setDefaultValue(final String defaultValue) { + return super.setDefaultValue(defaultValue); } @Override - public CsdlTerm setMaxLength(Integer maxLength) { - this.maxLength = maxLength; - return this; + @JacksonXmlProperty(localName = "Nullable", isAttribute = true) + public CsdlTerm setNullable(final boolean nullable) { + return super.setNullable(nullable); } @Override - public CsdlTerm setPrecision(Integer precision) { - this.precision = precision; - return this; + @JacksonXmlProperty(localName = "MaxLength", isAttribute = true) + public CsdlTerm setMaxLength(final Integer maxLength) { + return super.setMaxLength(maxLength); } @Override - public CsdlTerm setScale(Integer scale) { - this.scale = scale; - return this; + @JacksonXmlProperty(localName = "Precision", isAttribute = true) + public CsdlTerm setPrecision(final Integer precision) { + return super.setPrecision(precision); } @Override - public CsdlTerm setSrid(SRID srid) { - this.srid = srid; - return this; + @JacksonXmlProperty(localName = "Scale", isAttribute = true) + public CsdlTerm setScale(final Integer scale) { + return super.setScale(scale); } - @JsonSetter - void setSrid(String srid) { + @JacksonXmlProperty(localName = "SRID", isAttribute = true) + void setSrid(final String srid) { if (srid != null) - this.srid = SRID.valueOf(srid); - else - this.srid = null; + super.setSrid(SRID.valueOf(srid)); } } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/TermReader.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/TermReader.java index d44116026..329e8b051 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/TermReader.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/TermReader.java @@ -1,83 +1,38 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.annotation; import java.io.IOException; -import java.io.InputStream; -import java.net.MalformedURLException; import java.net.URI; -import java.net.URL; import java.util.HashMap; import java.util.Map; import org.apache.olingo.commons.api.edm.provider.CsdlTerm; -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.fasterxml.jackson.dataformat.xml.JacksonXmlModule; -import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; -public class TermReader { - final private JacksonXmlModule module; - final private XmlMapper xmlMapper; +public class TermReader extends AbstractVocabularyReader { public TermReader() { super(); - module = new JacksonXmlModule(); - module.setDefaultUseWrapper(false); - xmlMapper = new XmlMapper(module); - } - public Map> getTerms(String path) throws JsonParseException, JsonMappingException, - IOException { + public Map> getTerms(String path) throws IOException, ODataJPAModelException { return convertEDMX(readFromResource(path)); } - public Map> getTerms(URI uri) throws JsonParseException, JsonMappingException, - MalformedURLException, IOException { + public Map> getTerms(URI uri) throws IOException { return convertEDMX(readFromURI(uri)); } - public Edmx readFromResource(final String path) throws JsonParseException, JsonMappingException, IOException { - byte[] b = loadXML(path); - return xmlMapper.readValue(new String(b), Edmx.class); - } - - public Edmx readFromURI(final URI uri) throws JsonParseException, JsonMappingException, MalformedURLException, - IOException { - return xmlMapper.readValue(uri.toURL(), Edmx.class); - - } - - private byte[] loadXML(String path) { - - InputStream i = null; - byte[] image = null; - URL u = this.getClass().getClassLoader().getResource(path); - try { - i = u.openStream(); - image = new byte[i.available()]; - i.read(image); - } catch (IOException e1) { - e1.printStackTrace(); - } finally { - try { - i.close(); - return image; - } catch (IOException e) { - e.printStackTrace(); - } - } - return null; - } - - private Map> convertEDMX(Edmx edmx) { + @SuppressWarnings("unchecked") + @Override + protected Map> convertEDMX(Edmx edmx) { if (edmx != null && edmx.getDataService() != null) { Schema[] schemas = edmx.getDataService().getSchemas(); - Map> edmSchemas = new HashMap>(schemas.length); + Map> edmSchemas = new HashMap<>(schemas.length); for (Schema schema : schemas) { String namespace = schema.getNamespace(); - Map terms = new HashMap(); + Map terms = new HashMap<>(); for (CsdlTerm t : schema.getTerms()) { terms.put(t.getName(), t); } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/TypeDefinition.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/TypeDefinition.java index dad903016..a4003b7e0 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/TypeDefinition.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/TypeDefinition.java @@ -1,128 +1,56 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.annotation; -import org.apache.olingo.commons.api.edm.FullQualifiedName; +import java.util.Objects; + import org.apache.olingo.commons.api.edm.geo.SRID; import org.apache.olingo.commons.api.edm.provider.CsdlTypeDefinition; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonSetter; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; @JsonIgnoreProperties(ignoreUnknown = true) class TypeDefinition extends CsdlTypeDefinition { - TypeDefinition() { - super(); - } - - @JacksonXmlProperty(localName = "Name", isAttribute = true) - private String name; - @JacksonXmlProperty(localName = "UnderlyingType", isAttribute = true) - private String underlyingType; - @JacksonXmlProperty(localName = "MaxLength", isAttribute = true) - private Integer maxLength; - @JacksonXmlProperty(localName = "Precision", isAttribute = true) - private Integer precision; - @JacksonXmlProperty(localName = "Scale", isAttribute = true) - private Integer scale; - @JacksonXmlProperty(localName = "SRID", isAttribute = true) - private String srid; - @JacksonXmlProperty(localName = "Unicode", isAttribute = true) - private Boolean isUnicode; - -//@JacksonXmlProperty(localName = "Annotation") -//protected List annotations; - @Override - public String getName() { - return name; - } - - @Override - public String getUnderlyingType() { - return underlyingType; - } - - @Override - public Integer getMaxLength() { - return maxLength; - } - - @Override - public Integer getPrecision() { - return new Integer(precision.intValue()); - } - - @Override - public Integer getScale() { - return scale; - } - - @Override - public boolean isUnicode() { - return isUnicode; - } - - @Override - public SRID getSrid() { - if (srid != null) - return SRID.valueOf(srid); - else - return null; - } - - @Override - public TypeDefinition setName(String name) { - this.name = name; - return this; - } - - @JsonSetter - @Override - public CsdlTypeDefinition setUnderlyingType(String underlyingType) { - this.underlyingType = underlyingType; - return this; + @JacksonXmlProperty(localName = "Name", isAttribute = true) + public CsdlTypeDefinition setName(final String name) { + return super.setName(name); } @Override - public CsdlTypeDefinition setUnderlyingType(FullQualifiedName underlyingType) { - this.underlyingType = underlyingType.getFullQualifiedNameAsString(); - return this; + @JacksonXmlProperty(localName = "UnderlyingType", isAttribute = true) + public CsdlTypeDefinition setUnderlyingType(final String underlyingType) { + return super.setUnderlyingType(underlyingType); } @Override - public CsdlTypeDefinition setMaxLength(Integer maxLength) { - this.maxLength = maxLength; - return this; + @JacksonXmlProperty(localName = "MaxLength", isAttribute = true) + public CsdlTypeDefinition setMaxLength(final Integer maxLength) { + return super.setMaxLength(maxLength); } @Override - public CsdlTypeDefinition setPrecision(Integer precision) { - this.precision = precision; - return this; + @JacksonXmlProperty(localName = "Precision", isAttribute = true) + public CsdlTypeDefinition setPrecision(final Integer precision) { + return super.setPrecision(precision); } @Override - public CsdlTypeDefinition setScale(Integer scale) { - this.scale = scale; - return this; + @JacksonXmlProperty(localName = "Scale", isAttribute = true) + public CsdlTypeDefinition setScale(final Integer scale) { + return super.setScale(scale); } @Override - public CsdlTypeDefinition setUnicode(boolean unicode) { - this.isUnicode = unicode; - return this; + @JacksonXmlProperty(localName = "Unicode", isAttribute = true) + public CsdlTypeDefinition setUnicode(final boolean unicode) { + return super.setUnicode(unicode); } - @Override - public CsdlTypeDefinition setSrid(SRID srid) { - this.srid = srid.toString(); - return this; + @JacksonXmlProperty(localName = "SRID", isAttribute = true) + void setSrid(final String srid) { + Objects.requireNonNull(srid); + super.setSrid(SRID.valueOf(srid)); } -// @Override -// public List getAnnotations() { -// return annotations; -// } - } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAAction.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAAction.java index de4ce1b4f..db7f8593e 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAAction.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAAction.java @@ -2,8 +2,10 @@ import java.lang.reflect.Parameter; +import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; + public interface JPAAction extends JPAOperation, JPAJavaOperation { - JPAParameter getParameter(Parameter declairedParameter); + JPAParameter getParameter(Parameter declairedParameter) throws ODataJPAModelException; } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAAssociationAttribute.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAAssociationAttribute.java index e13c6c90a..1cfee0c0b 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAAssociationAttribute.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAAssociationAttribute.java @@ -2,13 +2,12 @@ import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; -//TODO remove extension public interface JPAAssociationAttribute extends JPAAttribute { public JPAStructuredType getTargetEntity() throws ODataJPAModelException; - public boolean isCollection(); + public JPAAssociationAttribute getPartner(); - JPAAssociationAttribute getPartner(); + public JPAAssociationPath getPath() throws ODataJPAModelException; } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAAssociationPath.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAAssociationPath.java index 9f69b9b80..c08d57f4b 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAAssociationPath.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAAssociationPath.java @@ -6,21 +6,37 @@ public interface JPAAssociationPath { - String PATH_SEPERATOR = "/"; - String getAlias(); + /** + * Only available if a Join Table was used + * @return + * @throws ODataJPAModelException + */ + List getInverseLeftJoinColumnsList() throws ODataJPAModelException; + List getJoinColumnsList() throws ODataJPAModelException; + JPAJoinTable getJoinTable(); + JPAAssociationAttribute getLeaf(); + List getLeftColumnsList() throws ODataJPAModelException; + + JPAAssociationAttribute getPartner(); + List getPath(); - JPAStructuredType getTargetType(); + List getRightColumnsList() throws ODataJPAModelException; JPAStructuredType getSourceType(); - boolean isCollection(); + JPAStructuredType getTargetType(); - JPAAssociationAttribute getPartner(); + /** + * @return True if the target entity is linked via a join table + */ + boolean hasJoinTable(); + + boolean isCollection(); } \ No newline at end of file diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAAttribute.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAAttribute.java index fb4719b1a..09ef4a933 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAAttribute.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAAttribute.java @@ -1,29 +1,75 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.api; +import java.lang.reflect.Constructor; +import java.util.List; +import java.util.Set; + import javax.persistence.AttributeConverter; import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind; import org.apache.olingo.commons.api.edm.provider.CsdlAbstractEdmItem; +import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmTransientPropertyCalculator; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; public interface JPAAttribute extends JPAElement { - public AttributeConverter getConverter(); + public AttributeConverter getConverter(); + + public EdmPrimitiveTypeKind getEdmType() throws ODataJPAModelException; + + public CsdlAbstractEdmItem getProperty() throws ODataJPAModelException; - public JPAStructuredType getStructuredType(); + public JPAStructuredType getStructuredType() throws ODataJPAModelException; + + /** + * Returns a list of names of the claims that shall be matched with this property + * @return + */ + public Set getProtectionClaimNames(); + + /** + * Provides a List of path to the protected attributed + * @return + * @throws ODataJPAModelException + */ + public List getProtectionPath(String claimName) throws ODataJPAModelException; public Class getType(); + public boolean isAssociation(); + + /** + * True if a to n association is involved + * @return + */ + public boolean isCollection(); + public boolean isComplex(); - public boolean isKey(); + public boolean isEnum(); - public boolean isAssociation(); + public boolean isEtag(); + + public boolean isKey(); public boolean isSearchable(); - public EdmPrimitiveTypeKind getEdmType() throws ODataJPAModelException; + public boolean hasProtection(); - public CsdlAbstractEdmItem getProperty() throws ODataJPAModelException; + public boolean isTransient(); + + /** + * + * @param + * @return + * @throws ODataJPAModelException + */ + public > Constructor getCalculatorConstructor() + throws ODataJPAModelException; + + /** + * @return A list of path pointing to the properties that are required to calculate the value of this property + */ + List getRequiredProperties(); } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPACollectionAttribute.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPACollectionAttribute.java new file mode 100644 index 000000000..65db012e5 --- /dev/null +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPACollectionAttribute.java @@ -0,0 +1,27 @@ +package com.sap.olingo.jpa.metadata.core.edm.mapper.api; + +import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; + +public interface JPACollectionAttribute extends JPAAttribute { + + JPAAssociationPath asAssociation() throws ODataJPAModelException; + + /** + * Returns for simple collections attributes the corresponding attribute of the target entity type. E.g. the following + * property definition:

+ * + * @ElementCollection(fetch = FetchType.LAZY)
+ * @CollectionTable(name = "\"Comment\"",
+ *     joinColumns = @@JoinColumn(name = "\"BusinessPartnerID\""))
+ * @Column(name = "\"Text\"")
+ * private List comment = new ArrayList<>(); + *


+ * creates a simple collection attribute. For this collection attribute jpa processor requires that a corresponding + * entity exists. This entity has to have a property pointing to the same database column, which is returned. + * + * @return In case of simple collections attributes the corresponding attribute of the target entity type otherwise + * null. + * @throws ODataJPAModelException + */ + JPAAttribute getTargetAttribute() throws ODataJPAModelException; +} diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPADescriptionAttribute.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPADescriptionAttribute.java index f447b7175..dba90d0e3 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPADescriptionAttribute.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPADescriptionAttribute.java @@ -1,15 +1,20 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.api; -import java.util.HashMap; +import java.util.Map; public interface JPADescriptionAttribute extends JPAAttribute { public boolean isLocationJoin(); + /** + * @return Property of description entity that contains the text/description + */ public JPAAttribute getDescriptionAttribute(); public JPAPath getLocaleFieldName(); - public HashMap getFixedValueAssignment(); + public Map getFixedValueAssignment(); + + public JPAAssociationAttribute asAssociationAttribute(); } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAEdmNameBuilder.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAEdmNameBuilder.java new file mode 100644 index 000000000..6ebaea42a --- /dev/null +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAEdmNameBuilder.java @@ -0,0 +1,103 @@ +/** + * + */ +package com.sap.olingo.jpa.metadata.core.edm.mapper.api; + +import javax.annotation.Nonnull; +import javax.persistence.metamodel.Attribute; +import javax.persistence.metamodel.EmbeddableType; +import javax.persistence.metamodel.EntityType; + +import org.apache.olingo.commons.api.edm.provider.CsdlEntityType; + +/** + * A name builder creates, based on information from the JPA entity model names, the names of the corresponding element + * of the OData entity data model (EDM) + * @author Oliver Grande + * Created: 15.09.2019 + * + */ +public interface JPAEdmNameBuilder { + + /** + * + * @param jpaEnbeddedType + * @return + */ + @Nonnull + String buildComplexTypeName(final EmbeddableType jpaEnbeddedType); + + /** + * Container names are + * Simple Identifier, + * so can contain only letters, digits and underscores. + * @return non empty unique name of an Entity Set + */ + @Nonnull + String buildContainerName(); + + default String buildEntitySetName(final CsdlEntityType entityType) { + return buildEntitySetName(entityType.getName()); + } + + /** + * Create a name of an + * Entity Set derived from the name of the corresponding entity type. + * @param entityTypeName + * @return non empty unique name of an Entity Set + */ + @Nonnull + String buildEntitySetName(final String entityTypeName); + + /** + * Creates the name of an Entity + * Type derived from JPA Entity Type. + * @param jpaEntityType + * @return non empty unique name of an Entity Type + */ + @Nonnull + String buildEntityTypeName(final EntityType jpaEntityType); + + /** + * Converts the internal java class name of an enumeration into the external entity data model + * Enumeration Type name. + * @param javaEnum + * @return non empty unique name of an Enumeration + */ + @Nonnull + String buildEnumerationTypeName(final Class> javaEnum); + + /** + * Converts the name of an JPA association attribute into the name of an EDM navigation property + * @param jpaAttribute + * @return non empty unique name of a Navigation Property + */ + @Nonnull + String buildNaviPropertyName(final Attribute jpaAttribute); + + /** + * Convert the internal name of a java based operation into the external entity data model name. + * @param internalOperationName + * @return non empty unique name of an Operation (Function or Action) + */ + @Nonnull + String buildOperationName(final String internalOperationName); + + /** + * Converts the name of an JPA attribute into the name of an EDM property + * @param jpaAttributeName + * @return non empty unique name of a property + */ + @Nonnull + String buildPropertyName(final String jpaAttributeName); + + /** + * @return name space to a schema + */ + @Nonnull + String getNamespace(); +} \ No newline at end of file diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAElement.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAElement.java index b25fb4bbd..e7126e900 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAElement.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAElement.java @@ -3,9 +3,21 @@ import org.apache.olingo.commons.api.edm.FullQualifiedName; public interface JPAElement { + /** + * Returns the full qualified name of an element + * @return + */ + public FullQualifiedName getExternalFQN(); + + /** + * Returns the element name published by the API + * @return + */ public String getExternalName(); + /** + * Returns the internally used (Java) name for an element + * @return + */ public String getInternalName(); - - public FullQualifiedName getExternalFQN(); } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAEntityType.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAEntityType.java index c9caf98bd..e2ef7f60b 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAEntityType.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAEntityType.java @@ -5,6 +5,20 @@ import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; public interface JPAEntityType extends JPAStructuredType { + /** + * Searches for a Collection Property defined by the name used in the OData metadata in all the collection properties + * that are available for this type via the OData service. That is: + *
    + *
  • All not ignored collection properties of this type. + *
  • All not ignored collection properties from super types. + *
  • All not ignored collection properties from embedded types. + *
+ * @param externalName + * @return + * @throws ODataJPAModelException + */ + public JPACollectionAttribute getCollectionAttribute(final String externalName) throws ODataJPAModelException; + /** * * @return Mime type of streaming content @@ -14,9 +28,12 @@ public interface JPAEntityType extends JPAStructuredType { public JPAPath getContentTypeAttributePath() throws ODataJPAModelException; + public JPAPath getEtagPath() throws ODataJPAModelException; + /** * Returns a resolved list of all attributes that are marked as Id, so the attributes of an EmbeddedId are returned as - * separate entries + * separate entries. For compound keys has the opposite order of the attributes in the entity or embedded id + * respectively. * @return * @throws ODataJPAModelException */ @@ -30,11 +47,17 @@ public interface JPAEntityType extends JPAStructuredType { public List getKeyPath() throws ODataJPAModelException; /** - * Returns the class of the Key. This could by either a primitive tape, the IdClass or the Embeddable of an EmbeddedId + * Returns the class of the Key. This could by either a primitive type, the IdClass or the Embeddable of an EmbeddedId * @return */ public Class getKeyType(); + /** + * True in case the entity type has a compound key, so an EmbeddedId or multiple id properties + * @return + */ + public boolean hasCompoundKey(); + /** * * @return @@ -54,6 +77,5 @@ public interface JPAEntityType extends JPAStructuredType { public boolean hasStream() throws ODataJPAModelException; - public List searchChildPath(JPAPath selectItemPath); - + public List searchChildPath(final JPAPath selectItemPath); } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAEnumerationAttribute.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAEnumerationAttribute.java new file mode 100644 index 000000000..acac982eb --- /dev/null +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAEnumerationAttribute.java @@ -0,0 +1,27 @@ +package com.sap.olingo.jpa.metadata.core.edm.mapper.api; + +import java.util.List; + +import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; + +public interface JPAEnumerationAttribute { + > T enumOf(final String value) throws ODataJPAModelException; + + > E enumOf(final T value) throws ODataJPAModelException; + + T valueOf(final String value) throws ODataJPAModelException; + + T valueOf(final List value) throws ODataJPAModelException; + + boolean isFlags() throws ODataJPAModelException; + + /** + * Converts a list of string representations either into an array of enumerations, if a converter is given, or + * otherwise the first value into an enumeration + * @param value + * @return + * @throws ODataJPAModelException + */ + Object convert(final List values) throws ODataJPAModelException; + +} diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAFunction.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAFunction.java index 38dfa204c..278be8dbc 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAFunction.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAFunction.java @@ -27,4 +27,6 @@ public interface JPAFunction extends JPAOperation { * @return The type of function */ public EdmFunctionType getFunctionType(); + + public boolean isBound() throws ODataJPAModelException; } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAJoinTable.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAJoinTable.java new file mode 100644 index 000000000..265853d70 --- /dev/null +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAJoinTable.java @@ -0,0 +1,30 @@ +package com.sap.olingo.jpa.metadata.core.edm.mapper.api; + +import java.util.List; + +import com.sap.olingo.jpa.metadata.api.JPAJoinColumn; +import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; + +public interface JPAJoinTable { + + public String getTableName(); + + public String getAlias(String dbFieldName); + + public String getInverseAlias(String dbFieldName); + + public JPAEntityType getEntityType(); + + public List getJoinColumns() throws ODataJPAModelException; + + /** + * Returns the list of inverse join columns with exchanged left/right order. + * @return + * @throws ODataJPAModelException + */ + public List getInversJoinColumns() throws ODataJPAModelException; + + public List getRawJoinInformation(); + + public List getRawInversJoinInformation() throws ODataJPAModelException; +} diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAPath.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAPath.java index 1c67debfa..74ef56686 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAPath.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAPath.java @@ -2,18 +2,55 @@ import java.util.List; +/** + * A path within an JPA entity to an attribute. + * @author Oliver Grande + * + */ public interface JPAPath extends Comparable { - String PATH_SEPERATOR = "/"; + final String PATH_SEPERATOR = "/"; + /** + * External unique identifier for a path. Two path are seen as equal if they have the same alias + * @return + */ String getAlias(); + /** + * @return the name of the data base table/view column of the leaf of a path + */ String getDBFieldName(); + /** + * @return the last element of a path + */ JPAAttribute getLeaf(); + /** + * @return all elements of a path + */ List getPath(); + /** + * @return true if the leaf of the path shall be ignored + */ boolean ignore(); + /** + * Returns true in case the leaf of the path is part of one of the provided groups or none of the path elements is + * annotated with EdmVisibleFor. The leaf is seen as a member of a group in case its EdmVisibleFor annotation contains + * the group or the groups is mentioned at any other element of the path.
+ * Note: Based on this inheritance of EdmVisibleFor a path is seen as inconsistent if multiple elements are + * annotated and the difference of the set of groups is not empty. + * @return + */ + public boolean isPartOfGroups(final List groups); + + /** + * + * @return True in case at least on of the elements of the path is a transient property + */ + public boolean isTransient(); + } \ No newline at end of file diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAProtectionInfo.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAProtectionInfo.java new file mode 100644 index 000000000..dc500ec6c --- /dev/null +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAProtectionInfo.java @@ -0,0 +1,32 @@ +package com.sap.olingo.jpa.metadata.core.edm.mapper.api; + +/** + * Provides information about a protected attribute + * @author Oliver Grande + * + */ +public interface JPAProtectionInfo { + /** + * The protected attribute + * @return + */ + public JPAAttribute getAttribute(); + + /** + * Path within the entity type to the attribute + * @return + */ + public JPAPath getPath(); + + /** + * Claim names that shall be used to protect this attribute + * @return + */ + public String getClaimName(); + + /** + * Returns the maintained wildcard setting. + * @return + */ + public boolean supportsWildcards(); +} diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAServiceDocument.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAServiceDocument.java index d9c461427..7730e12e2 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAServiceDocument.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAServiceDocument.java @@ -4,6 +4,7 @@ import org.apache.olingo.commons.api.edm.EdmAction; import org.apache.olingo.commons.api.edm.EdmComplexType; +import org.apache.olingo.commons.api.edm.EdmEnumType; import org.apache.olingo.commons.api.edm.EdmFunction; import org.apache.olingo.commons.api.edm.EdmType; import org.apache.olingo.commons.api.edm.FullQualifiedName; @@ -29,22 +30,29 @@ public interface JPAServiceDocument extends CustomETagSupport { * @return * @throws ODataJPAModelException */ - JPAEntityType getEntity(EdmType edmType) throws ODataJPAModelException; + JPAEntityType getEntity(final EdmType edmType) throws ODataJPAModelException; - JPAEntityType getEntity(FullQualifiedName typeName); + JPAEntityType getEntity(final FullQualifiedName typeName); - JPAEntityType getEntity(String edmEntitySetName) throws ODataJPAModelException; + JPAEntityType getEntity(final String edmEntitySetName) throws ODataJPAModelException; - JPAFunction getFunction(EdmFunction function); + JPAEntityType getEntity(Class entityClass) throws ODataJPAModelException; - JPAAction getAction(EdmAction action); + JPAFunction getFunction(final EdmFunction function); - JPAEntitySet getEntitySet(JPAEntityType entityType) throws ODataJPAModelException; + JPAAction getAction(final EdmAction action); + + JPAEntitySet getEntitySet(final JPAEntityType entityType) throws ODataJPAModelException; List getReferences(); - CsdlTerm getTerm(FullQualifiedName termName); + CsdlTerm getTerm(final FullQualifiedName termName); + + JPAStructuredType getComplexType(final EdmComplexType edmComplexType); + + JPAEnumerationAttribute getEnumType(final EdmEnumType type); - JPAStructuredType getComplexType(EdmComplexType edmComplexType); + JPAEnumerationAttribute getEnumType(final String fqnAsString); + JPAEdmNameBuilder getNameBuilder(); } \ No newline at end of file diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAStructuredType.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAStructuredType.java index 213d0e266..56263c702 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAStructuredType.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/api/JPAStructuredType.java @@ -1,6 +1,11 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.api; import java.util.List; +import java.util.Optional; + +import javax.annotation.Nonnull; + +import org.apache.olingo.server.api.uri.UriResourceProperty; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; @@ -11,35 +16,110 @@ * */ public interface JPAStructuredType extends JPAElement { + public JPAAssociationAttribute getAssociation(@Nonnull final String internalName) throws ODataJPAModelException; + + /** + * Searches for an AssociationPath defined by the name used in the OData metadata in all the navigation properties + * that are available for this type via the OData service. That is: + *
    + *
  • All not ignored navigation properties of this type. + *
  • All not ignored navigation properties from super types. + *
  • All not ignored navigation properties from embedded types. + *
+ * @param externalName + * @return + * @throws ODataJPAModelException + */ + public JPAAssociationPath getAssociationPath(@Nonnull final String externalName) throws ODataJPAModelException; + /** * Searches in the navigation properties that are available for this type via the OData service. That is: *
    *
  • All not ignored navigation properties of this type. - *
  • All not ignored navigation properties from supertypes are included - *
  • All not ignored navigation properties from embedded types are included. + *
  • All not ignored navigation properties from super types. + *
  • All not ignored navigation properties from embedded types. *
* @return null if no navigation property found. * @throws ODataJPAModelException */ public List getAssociationPathList() throws ODataJPAModelException; - public JPAAssociationAttribute getAssociation(String internalName) throws ODataJPAModelException; + public Optional getAttribute(@Nonnull final String internalName) throws ODataJPAModelException; - public JPAAssociationPath getAssociationPath(String externalName) throws ODataJPAModelException; + public Optional getAttribute(@Nonnull final UriResourceProperty uriResourceItem) + throws ODataJPAModelException; - public JPAAssociationPath getDeclaredAssociation(String externalName) throws ODataJPAModelException; + @Nonnull + public List getAttributes() throws ODataJPAModelException; - public JPAAttribute getAttribute(String internalName) throws ODataJPAModelException; + /** + * List of the path to all collection properties of this type. That is: + *
    + *
  • All not ignored collection properties of this type. + *
  • All not ignored collection properties from super types. + *
  • All not ignored collection properties from embedded types. + *
+ * @return + * @throws ODataJPAModelException + */ + @Nonnull + public List getCollectionAttributesPath() throws ODataJPAModelException; - public List getAttributes() throws ODataJPAModelException; + /** + * List of all associations that are declared at this type. That is: + *
    + *
  • All navigation properties of this type. + *
  • All navigation properties from super types. + *
+ * @return + * @throws ODataJPAModelException + */ + @Nonnull + public List getDeclaredAssociations() throws ODataJPAModelException; + + /** + * List of all attributes that are declared at this type. That is: + *
    + *
  • All properties of this type. + *
  • All properties from super types. + *
+ * @return + * @throws ODataJPAModelException + */ + @Nonnull + public List getDeclaredAttributes() throws ODataJPAModelException; + + public Optional getDeclaredAttribute(@Nonnull final String internalName) throws ODataJPAModelException; - public JPAPath getPath(String externalName) throws ODataJPAModelException; + /** + * List of all collection attributes that are declared at this type. That is: + *
    + *
  • All collection properties of this type. + *
  • All collection properties from super types. + *
+ * @return + * @throws ODataJPAModelException + */ + public List getDeclaredCollectionAttributes() throws ODataJPAModelException; + + /** + * List of all associations that are declared at this type. That is: + *
    + *
  • All not ignored collection properties of this type. + *
  • All not ignored collection properties from super types. + *
+ * @return + * @throws ODataJPAModelException + */ + public JPAPath getPath(final String externalName) throws ODataJPAModelException; + + public JPAPath getPath(final String externalName, final boolean respectIgnore) throws ODataJPAModelException; /** * List of all attributes that are available for this type via the OData service. That is: *
    *
  • All not ignored properties of the type. - *
  • All not ignored properties from supertypes. + *
  • All not ignored properties from super types. *
  • All not ignored properties from embedded types. *
* @return List of all attributes that are available via the OData service. @@ -47,18 +127,19 @@ public interface JPAStructuredType extends JPAElement { */ public List getPathList() throws ODataJPAModelException; - public Class getTypeClass(); - /** - * In case the type is within the given association path, the sub-path is returned. - * E.g. structured type is AdministrativeInformation and associationPath = AdministrativeInformation/Created/User - * Created/User is returned. - * @param associationPath + * List of all protected Attributes including protection/claim information. That is: + *
    + *
  • All not ignored protected properties of the type. + *
  • All not ignored protected properties from super types. + *
  • All not ignored protected properties from embedded types. + *
* @return * @throws ODataJPAModelException */ - public JPAAssociationPath getDeclaredAssociation(JPAAssociationPath associationPath) throws ODataJPAModelException; + public List getProtections() throws ODataJPAModelException; - public boolean isAbstract(); + public Class getTypeClass(); + public boolean isAbstract(); } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/exception/ODataJPAModelException.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/exception/ODataJPAModelException.java index f01780143..ce55cbadd 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/exception/ODataJPAModelException.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/exception/ODataJPAModelException.java @@ -10,31 +10,21 @@ public class ODataJPAModelException extends ODataJPAException { */ private static final long serialVersionUID = -7188499882306858747L; - public static enum MessageKeys implements ODataJPAMessageKey { - INVALID_ENTITY_TYPE, - INVALID_COMPLEX_TYPE, - INVALID_ASSOCIATION, - INVALID_ENTITY_SET, - INVALID_ENTITY_CONTAINER, - INVALID_ASSOCIATION_SET, - INVALID_FUNC_IMPORT, + public enum MessageKeys implements ODataJPAMessageKey { + INVALID_DESCIPTION_PROPERTY, + INVALID_COLLECTION_TYPE, - BUILDER_NULL, TYPE_NOT_SUPPORTED, - FUNC_ENTITY_SET_EXP, FUNC_RETURN_TYPE_EXP, - FUNC_RETURN_TYPE_ENTITY_NOT_FOUND, FUNC_RETURN_TYPE_UNKNOWN, FUNC_RETURN_TYPE_INVALID, - GENERAL, - INNER_EXCEPTION, - FUNC_PARAM_NAME_EXP, + FUNC_RETURN_NOT_SUPPORTED, FUNC_PARAM_ANNOTATION_MISSING, - FUNC_PARAM_OUT_WRONG_TYPE, - FUNC_PARAM_OUT_MISSING, - FUNC_PARAM_OUT_TO_MANY, + FUNC_PARAM_ONLY_PRIMITIVE, + FUNC_PARAM_BOUND_IGNORE, + FUNC_CONV_ERROR, FUNC_CONSTRUCTOR_MISSING, ACTION_RETURN_TYPE_INVALID, ACTION_RETURN_TYPE_EXP, @@ -43,13 +33,21 @@ public static enum MessageKeys implements ODataJPAMessageKey { ACTION_PARAM_TYPE_INVALID, ACTION_PARAM_BINGING_NOT_FOUND, ACTION_UNBOUND_ENTITY_SET, + ENUMERATION_ANNOTATION_MISSING, + ENUMERATION_UNSUPPORTED_TYPE, + ENUMERATION_NO_NEGATIVE_VALUE, - REF_ATTRIBUTE_NOT_FOUND, TYPE_MAPPER_COULD_NOT_INSANTIATE, - NOT_SUPPORTED_EMBEDDED_KEY, NOT_SUPPORTED_ATTRIBUTE_TYPE, NOT_SUPPORTED_NO_IMPLICIT_COLUMNS, + NOT_SUPPORTED_NO_IMPLICIT_COLUMNS_COMPEX, NOT_SUPPORTED_EMBEDDED_STREAM, + NOT_SUPPORTED_PROTECTED_COLLECTION, + NOT_SUPPORTED_PROTECTED_NAVIGATION, + NOT_SUPPORTED_NAVIGATION_PART_OF_GROUP, + NOT_SUPPORTED_MANDATORY_PART_OF_GROUP, + NOT_SUPPORTED_KEY_PART_OF_GROUP, + NOT_SUPPORTED_MIXED_PART_OF_GROUP, DESCRIPTION_LOCALE_FIELD_MISSING, DESCRIPTION_ANNOTATION_MISSING, @@ -57,7 +55,13 @@ public static enum MessageKeys implements ODataJPAMessageKey { PROPERTY_DEFAULT_ERROR, PROPERTY_MISSING_PRECISION, + PROPERTY_REQUIRED_UNKNOWN, + COMPLEX_PROPERTY_MISSING_PROTECTION_PATH, + COMPLEX_PROPERTY_WRONG_PROTECTION_PATH, REFERENCED_PROPERTY_NOT_FOUND, + TRANSIENT_CALCULATOR_TOO_MANY_CONSTRUCTORS, + TRANSIENT_CALCULATOR_WRONG_PARAMETER, + TRANSIENT_KEY_NOT_SUPPORTED, INHERITANCE_NOT_ALLOWED, TO_MANY_STREAMS, ANNOTATION_STREAM_INCOMPLETE, @@ -66,7 +70,8 @@ public static enum MessageKeys implements ODataJPAMessageKey { NAVI_PROPERTY_NOT_FOUND, ON_LEFT_ATTRIBUTE_NULL, ON_RIGHT_ATTRIBUTE_NULL, - PATH_ELEMENT_NOT_FOUND; + PATH_ELEMENT_NOT_FOUND, + FILE_NOT_FOUND; @Override public String getKey() { diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/extention/IntermediateModelItemAccess.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/extention/IntermediateModelItemAccess.java index 2f140c384..62d4019ee 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/extention/IntermediateModelItemAccess.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/extention/IntermediateModelItemAccess.java @@ -2,8 +2,15 @@ import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAElement; +/** + * @author Oliver Grande + * + */ public interface IntermediateModelItemAccess extends JPAElement { - + /** + * Element shall be ignored for metadata generation. + * @return + */ boolean ignore(); /** diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/extention/IntermediateNavigationPropertyAccess.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/extention/IntermediateNavigationPropertyAccess.java index 0e23fb9a7..51a8b6fed 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/extention/IntermediateNavigationPropertyAccess.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/extention/IntermediateNavigationPropertyAccess.java @@ -9,8 +9,9 @@ public interface IntermediateNavigationPropertyAccess extends IntermediateModelI public void setOnDelete(CsdlOnDelete onDelete); /** - * Enables to add annotations to a property, e.g. because the type of annotation is not enabled via - * {@link com.sap.olingo.jpa.metadata.core.edm.annotation.EdmAnnotation EdmAnnotation} or should be during runtime + * Enables to add annotations to a navigation property, e.g. because the type of annotation is not enabled via + * {@link com.sap.olingo.jpa.metadata.core.edm.annotation.EdmAnnotation EdmAnnotation} or should be changed during + * runtime * @param annotations */ public void addAnnotations(final List annotations); diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/extention/IntermediatePropertyAccess.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/extention/IntermediatePropertyAccess.java index 5725928ce..888815efb 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/extention/IntermediatePropertyAccess.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/extention/IntermediatePropertyAccess.java @@ -4,13 +4,22 @@ import org.apache.olingo.commons.api.edm.provider.CsdlAnnotation; +/** + * Override generated metadata for a property. + * @author Oliver Grande + * + */ public interface IntermediatePropertyAccess extends IntermediateModelItemAccess { public boolean isEtag(); /** * Enables to add annotations to a property, e.g. because the type of annotation is not enabled via - * {@link com.sap.olingo.jpa.metadata.core.edm.annotation.EdmAnnotation EdmAnnotation} or should be during runtime + * {@link com.sap.olingo.jpa.metadata.core.edm.annotation.EdmAnnotation EdmAnnotation} or should changed be during + * runtime * @param annotations */ public void addAnnotations(final List annotations); + + public boolean hasProtection(); + } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/DefaultEdmPostProcessor.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/DefaultEdmPostProcessor.java index 654fd36ac..d090b25cf 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/DefaultEdmPostProcessor.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/DefaultEdmPostProcessor.java @@ -1,22 +1,31 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; +import com.sap.olingo.jpa.metadata.api.JPAEdmMetadataPostProcessor; import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediateEntityTypeAccess; import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediateNavigationPropertyAccess; import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediatePropertyAccess; import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediateReferenceList; -final class DefaultEdmPostProcessor extends com.sap.olingo.jpa.metadata.api.JPAEdmMetadataPostProcessor { +final class DefaultEdmPostProcessor extends JPAEdmMetadataPostProcessor { @Override public void processNavigationProperty(final IntermediateNavigationPropertyAccess property, - final String jpaManagedTypeClassName) {} + final String jpaManagedTypeClassName) { + // Default shall do nothing + } @Override - public void processProperty(final IntermediatePropertyAccess property, final String jpaManagedTypeClassName) {} + public void processProperty(final IntermediatePropertyAccess property, final String jpaManagedTypeClassName) { + // Default shall do nothing + } @Override - public void provideReferences(IntermediateReferenceList references) {} + public void provideReferences(IntermediateReferenceList references) { + // Default shall do nothing + } @Override - public void processEntityType(IntermediateEntityTypeAccess entity) {} + public void processEntityType(IntermediateEntityTypeAccess entity) { + // Default shall do nothing + } } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediatOperationResultParameter.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediatOperationResultParameter.java index 18259345e..c39bcd01b 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediatOperationResultParameter.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediatOperationResultParameter.java @@ -16,14 +16,8 @@ class IntermediatOperationResultParameter implements JPAOperationResultParameter private final Class type; private final boolean isCollection; - public IntermediatOperationResultParameter(JPAOperation jpaOperation, final ReturnType jpaReturnType) { - this.jpaOperation = jpaOperation; - this.jpaReturnType = jpaReturnType; - this.type = jpaReturnType.type(); - this.isCollection = jpaReturnType.isCollection(); - } - - public IntermediatOperationResultParameter(JPAOperation jpaOperation, ReturnType jpaReturnType, Class returnType, + public IntermediatOperationResultParameter(final JPAOperation jpaOperation, final ReturnType jpaReturnType, + final Class returnType, boolean isCollection) { this.jpaOperation = jpaOperation; this.jpaReturnType = jpaReturnType; @@ -34,6 +28,14 @@ public IntermediatOperationResultParameter(JPAOperation jpaOperation, ReturnType this.type = returnType; } + public IntermediatOperationResultParameter(final JPAOperation jpaOperation, final ReturnType jpaReturnType, + final Class returnType) { + this.jpaOperation = jpaOperation; + this.jpaReturnType = jpaReturnType; + this.isCollection = jpaReturnType.isCollection(); + this.type = returnType; + } + @Override public Class getType() { return type; diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateActionFactory.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateActionFactory.java index cef3c5617..288e891dc 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateActionFactory.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateActionFactory.java @@ -6,6 +6,7 @@ import org.reflections.Reflections; import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmAction; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEdmNameBuilder; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.ODataAction; @@ -18,10 +19,10 @@ IntermediateOperation createOperation(JPAEdmNameBuilder nameBuilder, Intermediat } @SuppressWarnings("unchecked") - Map create(final JPAEdmNameBuilder nameBuilder, + Map create(final JPAEdmNameBuilder nameBuilder, final Reflections reflections, final IntermediateSchema schema) throws ODataJPAModelException { - return (Map) createOperationMap(nameBuilder, reflections, + return (Map) createOperationMap(nameBuilder, reflections, schema, ODataAction.class, EdmAction.class); } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateCollectionProperty.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateCollectionProperty.java new file mode 100644 index 000000000..82283dddd --- /dev/null +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateCollectionProperty.java @@ -0,0 +1,341 @@ +package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; + +import static com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException.MessageKeys.NOT_SUPPORTED_NO_IMPLICIT_COLUMNS; +import static com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException.MessageKeys.NOT_SUPPORTED_NO_IMPLICIT_COLUMNS_COMPEX; +import static com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException.MessageKeys.NOT_SUPPORTED_PROTECTED_COLLECTION; +import static javax.persistence.metamodel.Type.PersistenceType.EMBEDDABLE; + +import java.lang.reflect.AnnotatedElement; +import java.util.ArrayList; +import java.util.List; + +import javax.persistence.CollectionTable; +import javax.persistence.JoinColumn; +import javax.persistence.metamodel.PluralAttribute; +import javax.persistence.metamodel.Type; +import javax.persistence.metamodel.Type.PersistenceType; + +import org.apache.olingo.commons.api.edm.FullQualifiedName; + +import com.sap.olingo.jpa.metadata.api.JPAJoinColumn; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAAssociationAttribute; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAAssociationPath; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAAttribute; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPACollectionAttribute; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEdmNameBuilder; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAElement; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEntityType; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAJoinTable; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAOnConditionItem; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAPath; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAStructuredType; +import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; +import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException.MessageKeys; + +/** + * Represents a collection property. That is a property that may occur more than once. + *

For details about Complex Type metadata see: + * OData Version 4.0 Part 3 - 9 Complex Type + * @author Oliver Grande + * + */ + +class IntermediateCollectionProperty extends IntermediateProperty implements JPACollectionAttribute, + JPAAssociationAttribute { + private final IntermediateStructuredType sourceType; + private JPAJoinTable joinTable; // lazy builded + private JPAAssociationPathImpl associationPath; // lazy builded + private final JPAPath path; + + /** + * Copy with in new context + * @param jpaElement + * @param intermediateStructuredType + * @throws ODataJPAModelException + */ + public IntermediateCollectionProperty(final IntermediateCollectionProperty original, + final IntermediateStructuredType parent, final IntermediateProperty pathRoot) throws ODataJPAModelException { + + super(original.nameBuilder, original.jpaAttribute, original.schema); + this.sourceType = parent; + + final List newPath = new ArrayList<>(); + newPath.add(pathRoot); + if (original.path != null) { + newPath.addAll(original.path.getPath()); + this.path = new JPAPathImpl(pathRoot.getExternalName() + JPAPath.PATH_SEPERATOR + original.path.getAlias(), "", + newPath); + } else { + newPath.add(this); + this.path = new JPAPathImpl(pathRoot.getExternalName() + JPAPath.PATH_SEPERATOR + original.getExternalName(), "", + newPath); + } + } + + IntermediateCollectionProperty(final JPAEdmNameBuilder nameBuilder, + final PluralAttribute jpaAttribute, final IntermediateSchema schema, + final IntermediateStructuredType parent) throws ODataJPAModelException { + + super(nameBuilder, jpaAttribute, schema); + this.sourceType = parent; + this.path = null; + } + + @Override + public JPAAssociationPath asAssociation() throws ODataJPAModelException { + if (this.associationPath == null) { + final IntermediateCollectionTable joinTable = (IntermediateCollectionTable) getJoinTable(); + this.associationPath = new JPAAssociationPathImpl(this, sourceType, + path == null ? sourceType.getPath(getExternalName()) : path, + joinTable == null ? null : joinTable.getLeftJoinColumns()); + } + return associationPath; + + } + + @Override + public JPAAssociationAttribute getPartner() { + return null; + } + + @Override + public JPAAssociationPath getPath() throws ODataJPAModelException { + return asAssociation(); + } + + @Override + public JPAAttribute getTargetAttribute() throws ODataJPAModelException { + if (isComplex()) + return null; + else { + for (JPAAttribute a : ((IntermediateStructuredType) joinTable.getEntityType()).getAttributes()) { + if (dbFieldName.equals(((IntermediateProperty) a).getDBFieldName())) + return a; + } + return null; + } + } + + @Override + public JPAStructuredType getTargetEntity() throws ODataJPAModelException { + return getJoinTable().getEntityType(); + } + + @Override + public boolean isAssociation() { + return false; + } + + @Override + public boolean isCollection() { + return true; + } + + @Override + public boolean isComplex() { + return getRowType().getPersistenceType() == EMBEDDABLE; + } + + @Override + public boolean isEtag() { + return false; + } + + @Override + public boolean isKey() { + return false; + } + + @Override + public boolean isSearchable() { + return false; + } + + @Override + protected synchronized void lazyBuildEdmItem() throws ODataJPAModelException { + super.lazyBuildEdmItem(); + if (isComplex() + && schema.getComplexType(this.edmProperty.getTypeAsFQNObject().getName()) == null) + // Base type of collection '%1$s' of structured type '%2$s' not found + throw new ODataJPAModelException(MessageKeys.INVALID_COLLECTION_TYPE, getInternalName(), sourceType + .getInternalName()); + edmProperty.setCollection(true); + } + + @Override + void checkConsistancy() throws ODataJPAModelException { + // Collection Properties do not support EdmProtectedBy + if (hasProtection() || + (isComplex() && !getStructuredType().getProtections().isEmpty())) { + throw new ODataJPAModelException(NOT_SUPPORTED_PROTECTED_COLLECTION, this.managedType.getJavaType() + .getCanonicalName(), this.internalName); + } + } + + @Override + Class determineEntityType() { + return getRowType().getJavaType(); + } + + @Override + void determineIsVersion() { + isVersion = false; // Version is always false + } + + @Override + void determineStreamInfo() throws ODataJPAModelException { + // Stream properties not supported + } + + @Override + void determineStructuredType() { + if (getRowType().getPersistenceType() == PersistenceType.EMBEDDABLE) + type = schema.getStructuredType((PluralAttribute) jpaAttribute); + else + type = null; + } + + @Override + FullQualifiedName determineType() throws ODataJPAModelException { + return determineTypeByPersistanceType(getRowType().getPersistenceType()); + } + + @Override + String getDeafultValue() throws ODataJPAModelException { + // No defaults for collection properties + return null; + } + + JPAJoinTable getJoinTable() throws ODataJPAModelException { + if (joinTable == null) { + final javax.persistence.CollectionTable jpaJoinTable = ((AnnotatedElement) this.jpaAttribute.getJavaMember()) + .getAnnotation(javax.persistence.CollectionTable.class); + joinTable = jpaJoinTable != null ? new IntermediateCollectionTable(jpaJoinTable, schema) : null; + } + return joinTable; + } + + IntermediateStructuredType getSourceType() { + return sourceType; + } + + @Override + boolean isStream() { + // OData Version 4.0. Part 3: Common Schema Definition Language (CSDL) Plus Errata 03: + // Edm.Stream, or a type definition whose underlying type is Edm.Stream, cannot be used in collections or for + // non-binding parameters to functions or actions. + return false; + } + + private Type getRowType() { + return ((PluralAttribute) jpaAttribute).getElementType(); + } + + private class IntermediateCollectionTable implements JPAJoinTable { + private final CollectionTable jpaJoinTable; + private List joinColumns; + private final JPAEntityType jpaEntityType; + + public IntermediateCollectionTable(final CollectionTable jpaJoinTable, final IntermediateSchema schema) + throws ODataJPAModelException { + super(); + this.jpaJoinTable = jpaJoinTable; + this.jpaEntityType = schema.getEntityType(jpaJoinTable.catalog(), jpaJoinTable.schema(), jpaJoinTable.name()); + this.joinColumns = buildJoinColumns(sourceType); + } + + @Override + public String getAlias(String dbFieldName) { + for (IntermediateJoinColumn column : joinColumns) { + if (column.getName().equals(dbFieldName)) + return column.getReferencedColumnName(); + } + return null; + } + + @Override + public JPAEntityType getEntityType() { + return jpaEntityType; + } + + @Override + public String getInverseAlias(String dbFieldName) { + return null; + } + + @Override + public List getInversJoinColumns() throws ODataJPAModelException { + final List result = new ArrayList<>(); + + for (IntermediateJoinColumn column : joinColumns) { + result.add(new JPAOnConditionItemImpl( + ((IntermediateEntityType) jpaEntityType).getPathByDBField(column.getReferencedColumnName()), + sourceType.getPathByDBField(column.getName()))); + } + return result; + } + + @Override + public List getJoinColumns() throws ODataJPAModelException { + assert jpaEntityType != null; + final List result = new ArrayList<>(); + for (IntermediateJoinColumn column : joinColumns) { + result.add(new JPAOnConditionItemImpl( + sourceType.getPathByDBField(column.getName()), + ((IntermediateEntityType) jpaEntityType).getPathByDBField(column.getReferencedColumnName()))); + } + return result; + } + + @SuppressWarnings("unchecked") + @Override + public List getRawInversJoinInformation() throws ODataJPAModelException { + final List inversColumns = new ArrayList<>(joinColumns.size()); + for (final IntermediateJoinColumn column : joinColumns) { + final IntermediateJoinColumn inversColumn = new IntermediateJoinColumn(column.getReferencedColumnName(), column + .getName()); + inversColumns.add((T) inversColumn); + } + return inversColumns; + } + + @SuppressWarnings("unchecked") + @Override + public List getRawJoinInformation() { + return (List) joinColumns; + } + + @Override + public String getTableName() { + return buildFQTableName(jpaJoinTable.schema(), jpaJoinTable.name()); + } + + List getLeftJoinColumns() throws ODataJPAModelException { + return buildJoinColumns(sourceType); + } + + private List buildJoinColumns(final IntermediateStructuredType contextType) + throws ODataJPAModelException { + + final List result = new ArrayList<>(); + for (JoinColumn column : jpaJoinTable.joinColumns()) { + if (column.referencedColumnName() == null || column.referencedColumnName().isEmpty()) { + if (jpaJoinTable.joinColumns().length > 1) + throw new ODataJPAModelException(NOT_SUPPORTED_NO_IMPLICIT_COLUMNS, getInternalName()); + else if (!(contextType instanceof IntermediateEntityType)) + throw new ODataJPAModelException(NOT_SUPPORTED_NO_IMPLICIT_COLUMNS_COMPEX, contextType.getInternalName()); + else { + result.add(new IntermediateJoinColumn( + ((IntermediateProperty) ((IntermediateEntityType) contextType).getKey().get(0)) + .getDBFieldName(), column.name())); + } + } else { + result.add(new IntermediateJoinColumn(column.referencedColumnName(), column.name())); + } + } + return result; + } + } +} diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateComplexType.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateComplexType.java index 7738c9bbf..65fc4a27f 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateComplexType.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateComplexType.java @@ -8,6 +8,7 @@ import org.apache.olingo.commons.api.edm.provider.CsdlNavigationProperty; import org.apache.olingo.commons.api.edm.provider.CsdlProperty; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEdmNameBuilder; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; /** @@ -27,10 +28,10 @@ * */ final class IntermediateComplexType extends IntermediateStructuredType { - private CsdlComplexType edmComplexType; + // private CsdlComplexType edmComplexType; IntermediateComplexType(final JPAEdmNameBuilder nameBuilder, final EmbeddableType jpaEmbeddable, - final IntermediateSchema schema) throws ODataJPAModelException { + final IntermediateSchema schema) { super(nameBuilder, jpaEmbeddable, schema); this.setExternalName(nameBuilder.buildComplexTypeName(jpaEmbeddable)); @@ -39,17 +40,18 @@ final class IntermediateComplexType extends IntermediateStructuredType { @SuppressWarnings("unchecked") @Override - protected void lazyBuildEdmItem() throws ODataJPAModelException { - if (edmComplexType == null) { + protected synchronized void lazyBuildEdmItem() throws ODataJPAModelException { + if (edmStructuralType == null) { buildPropertyList(); buildNaviPropertyList(); - edmComplexType = new CsdlComplexType(); + addTransientProperties(); + edmStructuralType = new CsdlComplexType(); - edmComplexType.setName(this.getExternalName()); - edmComplexType.setProperties((List) extractEdmModelElements(declaredPropertiesList)); - edmComplexType.setNavigationProperties((List) extractEdmModelElements( + edmStructuralType.setName(this.getExternalName()); + edmStructuralType.setProperties((List) extractEdmModelElements(declaredPropertiesList)); + edmStructuralType.setNavigationProperties((List) extractEdmModelElements( declaredNaviPropertiesList)); - edmComplexType.setBaseType(determineBaseType()); + edmStructuralType.setBaseType(determineBaseType()); // TODO Abstract // edmComplexType.setAbstract(isAbstract) // TODO OpenType @@ -63,8 +65,10 @@ protected void lazyBuildEdmItem() throws ODataJPAModelException { @Override CsdlComplexType getEdmItem() throws ODataJPAModelException { - lazyBuildEdmItem(); - return edmComplexType; + if (edmStructuralType == null) { + lazyBuildEdmItem(); + } + return (CsdlComplexType) edmStructuralType; } } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateDataBaseFunction.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateDataBaseFunction.java index 09723555e..ef66694eb 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateDataBaseFunction.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateDataBaseFunction.java @@ -14,6 +14,7 @@ import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmFunctionType; import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmParameter; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPADataBaseFunction; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEdmNameBuilder; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAOperationResultParameter; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAParameter; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; @@ -22,8 +23,9 @@ class IntermediateDataBaseFunction extends IntermediateFunction implements JPADataBaseFunction { private final Class jpaDefiningPOJO; - IntermediateDataBaseFunction(JPAEdmNameBuilder nameBuilder, EdmFunction jpaFunction, Class definingPOJO, - IntermediateSchema schema) throws ODataJPAModelException { + IntermediateDataBaseFunction(final JPAEdmNameBuilder nameBuilder, final EdmFunction jpaFunction, + final Class definingPOJO, final IntermediateSchema schema) { + super(nameBuilder, jpaFunction, schema, IntNameBuilder.buildFunctionName(jpaFunction)); this.setExternalName(jpaFunction.name()); this.jpaDefiningPOJO = definingPOJO; @@ -41,7 +43,7 @@ public EdmFunctionType getFunctionType() { @Override public List getParameter() { - final List parameterList = new ArrayList(); + final List parameterList = new ArrayList<>(); for (final EdmParameter jpaParameter : jpaFunction.parameter()) { parameterList.add(new IntermediatFunctionParameter(jpaParameter)); } @@ -51,7 +53,7 @@ public List getParameter() { @Override public JPAParameter getParameter(String internalName) { for (JPAParameter parameter : getParameter()) { - if (parameter.getInternalName() == internalName) + if (parameter.getInternalName().equals(internalName)) return parameter; } return null; @@ -59,7 +61,9 @@ public JPAParameter getParameter(String internalName) { @Override public JPAOperationResultParameter getResultParameter() { - return new IntermediatOperationResultParameter(this, jpaFunction.returnType()); + return new IntermediatOperationResultParameter(this, jpaFunction.returnType(), + jpaFunction.returnType().type().equals(Object.class) ? schema.getEntityType(jpaDefiningPOJO).getTypeClass() + : jpaFunction.returnType().type()); } @Override @@ -69,14 +73,23 @@ public CsdlReturnType getReturnType() { @Override protected List determineEdmInputParameter() throws ODataJPAModelException { - - final List edmInputParameterList = new ArrayList(); - for (final EdmParameter jpaParameter : jpaFunction.parameter()) { + int noParameterToSkip = 0; + final List edmInputParameterList = new ArrayList<>(); + if (jpaFunction.isBound()) { + noParameterToSkip = ((IntermediateEntityType) schema.getEntityType(this.jpaDefiningPOJO)).getKey().size(); + final CsdlParameter edmInputParameter = new CsdlParameter(); + final IntermediateStructuredType et = schema.getEntityType(jpaDefiningPOJO); + edmInputParameter.setName("Key"); + edmInputParameter.setType(buildFQN(et.getEdmItem().getName())); + edmInputParameter.setNullable(false); + edmInputParameterList.add(edmInputParameter); + } + for (int i = noParameterToSkip; i < jpaFunction.parameter().length; i++) { + final EdmParameter jpaParameter = jpaFunction.parameter()[i]; final CsdlParameter edmInputParameter = new CsdlParameter(); edmInputParameter.setName(jpaParameter.name()); - edmInputParameter.setType(JPATypeConvertor.convertToEdmSimpleType(jpaParameter.type()).getFullQualifiedName()); - + edmInputParameter.setType(determineParameterType(null, jpaParameter)); edmInputParameter.setNullable(false); edmInputParameter.setCollection(jpaParameter.isCollection()); if (jpaParameter.maxLength() >= 0) @@ -100,25 +113,7 @@ protected List determineEdmInputParameter() throws ODataJPAModelE protected CsdlReturnType determineEdmResultType(final ReturnType returnType) throws ODataJPAModelException { final CsdlReturnType edmResultType = new CsdlReturnType(); - FullQualifiedName fqn; - if (returnType.type() == Object.class) { - final IntermediateStructuredType et = schema.getEntityType(jpaDefiningPOJO); - fqn = nameBuilder.buildFQN(et.getEdmItem().getName()); - this.setIgnore(et.ignore()); // If the result type shall be ignored, ignore also a function that returns it - } else { - final IntermediateStructuredType st = schema.getStructuredType(returnType.type()); - if (st != null) { - fqn = nameBuilder.buildFQN(st.getEdmItem().getName()); - this.setIgnore(st.ignore()); // If the result type shall be ignored, ignore also a function that returns it - } else { - EdmPrimitiveTypeKind pt = JPATypeConvertor.convertToEdmSimpleType(returnType.type()); - if (pt != null) - fqn = pt.getFullQualifiedName(); - else - throw new ODataJPAModelException(MessageKeys.FUNC_RETURN_TYPE_UNKNOWN); - } - } - edmResultType.setType(fqn); + edmResultType.setType(determineReturnType(returnType)); edmResultType.setCollection(returnType.isCollection()); edmResultType.setNullable(returnType.isNullable()); if (returnType.maxLength() >= 0) @@ -134,4 +129,47 @@ protected CsdlReturnType determineEdmResultType(final ReturnType returnType) thr } return edmResultType; } + + @Override + protected FullQualifiedName determineParameterType(final Class type, final EdmParameter definedParameter) + throws ODataJPAModelException { + + final EdmPrimitiveTypeKind edmType = JPATypeConvertor.convertToEdmSimpleType(definedParameter.type()); + if (edmType != null) + return edmType.getFullQualifiedName(); + else { + final IntermediateEnumerationType enumType = schema.getEnumerationType(definedParameter.type()); + if (enumType != null) { + return enumType.getExternalFQN(); + } else { + throw new ODataJPAModelException(ODataJPAModelException.MessageKeys.FUNC_CONV_ERROR); + } + } + } + + private FullQualifiedName determineReturnType(final ReturnType returnType) throws ODataJPAModelException { + + if (returnType.type() == Object.class) { + final IntermediateStructuredType et = schema.getEntityType(jpaDefiningPOJO); + this.setIgnore(et.ignore()); // If the result type shall be ignored, ignore also a function that returns it + return buildFQN(et.getEdmItem().getName()); + } else { + final IntermediateStructuredType st = schema.getStructuredType(returnType.type()); + if (st != null) { + this.setIgnore(st.ignore()); // If the result type shall be ignored, ignore also a function that returns it + return buildFQN(st.getEdmItem().getName()); + } else { + final IntermediateEnumerationType enumType = schema.getEnumerationType(returnType.type()); + if (enumType != null) { + return enumType.getExternalFQN(); + } else { + EdmPrimitiveTypeKind pt = JPATypeConvertor.convertToEdmSimpleType(returnType.type()); + if (pt != null) + return pt.getFullQualifiedName(); + else + throw new ODataJPAModelException(MessageKeys.FUNC_RETURN_TYPE_UNKNOWN); + } + } + } + } } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateDescriptionProperty.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateDescriptionProperty.java index 180613f61..6c2361c1f 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateDescriptionProperty.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateDescriptionProperty.java @@ -5,37 +5,85 @@ import java.lang.reflect.Member; import java.lang.reflect.ParameterizedType; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Optional; +import javax.persistence.JoinColumn; +import javax.persistence.JoinColumns; import javax.persistence.metamodel.Attribute; import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmDescriptionAssoziation; import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmDescriptionAssoziation.valueAssignment; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAAssociationAttribute; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAAssociationPath; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAAttribute; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPADescriptionAttribute; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEdmNameBuilder; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAElement; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAJoinTable; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAOnConditionItem; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAPath; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAStructuredType; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException.MessageKeys; -final class IntermediateDescriptionProperty extends IntermediateProperty implements JPADescriptionAttribute { - private IntermediateProperty descriptionProperty; - private String languageAttribute; +final class IntermediateDescriptionProperty extends IntermediateSimpleProperty implements JPADescriptionAttribute, + JPAAssociationAttribute { + private IntermediateSimpleProperty descriptionProperty; private String localeAttribute; + private final IntermediateStructuredType sourceType; private JPAStructuredType targetEntity; private HashMap fixedValues; private JPAPath localFieldPath; + private Optional assoziationPath; IntermediateDescriptionProperty(final JPAEdmNameBuilder nameBuilder, final Attribute jpaAttribute, - final IntermediateSchema schema) throws ODataJPAModelException { + final IntermediateStructuredType parent, final IntermediateSchema schema) throws ODataJPAModelException { super(nameBuilder, jpaAttribute, schema); + this.sourceType = parent; + this.assoziationPath = Optional.empty(); } @Override - protected void lazyBuildEdmItem() throws ODataJPAModelException { + public JPAAttribute getDescriptionAttribute() { + return descriptionProperty; + } + + @Override + public Map getFixedValueAssignment() { + return fixedValues; + } + + @Override + public JPAPath getLocaleFieldName() { + return localFieldPath; + } + + /** + * @return Type of description attribute + */ + @Override + public Class getType() { + return descriptionProperty.getType(); + } + + @Override + public boolean isAssociation() { + return true; + } + + @Override + public boolean isLocationJoin() { + return !localeAttribute.isEmpty(); + } + + @Override + protected synchronized void lazyBuildEdmItem() throws ODataJPAModelException { Member jpaMember = jpaAttribute.getJavaMember(); + String languageAttribute; if (this.edmProperty == null) { super.lazyBuildEdmItem(); @@ -51,19 +99,18 @@ protected void lazyBuildEdmItem() throws ODataJPAModelException { targetEntity = schema.getEntityType((Class) jpaTargetEntityType.getActualTypeArguments()[0]); else targetEntity = schema.getEntityType(jpaAttribute.getJavaType()); - } else + } else { targetEntity = schema.getEntityType(jpaAttribute.getJavaType()); - - descriptionProperty = (IntermediateProperty) targetEntity.getAttribute(assozation - .descriptionAttribute()); - if (descriptionProperty == null) - // The attribute %2$s has not been found at entity %1$s - throw new ODataJPAModelException(MessageKeys.INVALID_DESCIPTION_PROPERTY, targetEntity.getInternalName(), - assozation.descriptionAttribute()); + } + descriptionProperty = (IntermediateSimpleProperty) targetEntity.getAttribute(assozation + .descriptionAttribute()).orElseThrow(() -> + // The attribute %2$s has not been found at entity %1$s + new ODataJPAModelException(MessageKeys.INVALID_DESCIPTION_PROPERTY, targetEntity.getInternalName(), + assozation.descriptionAttribute())); languageAttribute = assozation.languageAttribute(); localeAttribute = assozation.localeAttribute(); - if (languageAttribute.isEmpty() && localeAttribute.isEmpty() || + if (emptyString(languageAttribute) && emptyString(localeAttribute) || !languageAttribute.isEmpty() && !localeAttribute.isEmpty()) throw new ODataJPAModelException(ODataJPAModelException.MessageKeys.DESCRIPTION_LOCALE_FIELD_MISSING, targetEntity.getInternalName(), this.internalName); @@ -77,74 +124,196 @@ protected void lazyBuildEdmItem() throws ODataJPAModelException { fixedValues = convertFixedValues(assozation.valueAssignments()); localFieldPath = convertAttributeToPath(!languageAttribute.isEmpty() ? languageAttribute : localeAttribute); - } else + } else { throw new ODataJPAModelException(ODataJPAModelException.MessageKeys.DESCRIPTION_ANNOTATION_MISSING, - targetEntity.getInternalName(), this.internalName); + sourceType.getInternalName(), this.internalName); + } } } } - @Override - public boolean isAssociation() { - return true; + private JPAPath convertAttributeToPath(final String attribute) throws ODataJPAModelException { + final String[] pathItems = attribute.split(JPAPath.PATH_SEPERATOR); + if (pathItems.length > 1) { + final List targetPath = new ArrayList<>(); + IntermediateSimpleProperty nextHop = (IntermediateSimpleProperty) targetEntity.getAttribute(pathItems[0]) + .orElseThrow(() -> new ODataJPAModelException(MessageKeys.PATH_ELEMENT_NOT_FOUND, pathItems[0], attribute)); + targetPath.add(nextHop); + for (int i = 1; i < pathItems.length; i++) { + if (nextHop.isComplex()) { + nextHop = (IntermediateSimpleProperty) nextHop.getStructuredType().getAttribute(pathItems[i]) + .orElseThrow(() -> new ODataJPAModelException(MessageKeys.PATH_ELEMENT_NOT_FOUND, pathItems[0], + attribute)); + targetPath.add(nextHop); + } + } + return new JPAPathImpl(nextHop.getExternalName(), nextHop.getDBFieldName(), targetPath); + } else { + final IntermediateSimpleProperty p = (IntermediateSimpleProperty) targetEntity.getAttribute(attribute) + .orElseThrow(() -> new ODataJPAModelException(MessageKeys.PATH_ELEMENT_NOT_FOUND, pathItems[0], attribute)); + return new JPAPathImpl(p.getExternalName(), p.getDBFieldName(), p); + } } - @Override - public boolean isLocationJoin() { - if (!localeAttribute.isEmpty()) - return true; - return false; + private HashMap convertFixedValues(final valueAssignment[] valueAssignments) + throws ODataJPAModelException { + final HashMap result = new HashMap<>(); + for (final EdmDescriptionAssoziation.valueAssignment value : valueAssignments) { + result.put(convertAttributeToPath(value.attribute()), value.value()); + } + return result; } @Override - public JPAAttribute getDescriptionAttribute() { - return descriptionProperty; + public JPAAssociationAttribute asAssociationAttribute() { + return this; } @Override - public JPAPath getLocaleFieldName() { - return localFieldPath; + public JPAStructuredType getTargetEntity() throws ODataJPAModelException { + return targetEntity; } @Override - public Class getType() { - return descriptionProperty.getType(); + public JPAAssociationAttribute getPartner() { + return null; } @Override - public HashMap getFixedValueAssignment() { - return fixedValues; + public JPAAssociationPath getPath() throws ODataJPAModelException { + return assoziationPath.orElseGet(() -> { + assoziationPath = Optional.of(new AssoziationPath()); + return assoziationPath.get(); + }); } - private HashMap convertFixedValues(final valueAssignment[] valueAssignments) - throws ODataJPAModelException { - final HashMap result = new HashMap(); - for (final EdmDescriptionAssoziation.valueAssignment value : valueAssignments) { - result.put(convertAttributeToPath(value.attribute()), value.value()); + private class AssoziationPath implements JPAAssociationPath { + private List joinColumns = null; + + @Override + public String getAlias() { + return null; } - return result; - } - private JPAPath convertAttributeToPath(final String attribute) throws ODataJPAModelException { - final String[] pathItems = attribute.split(JPAPath.PATH_SEPERATOR); - if (pathItems.length > 1) { - final List targetPath = new ArrayList(); - IntermediateProperty nextHop = (IntermediateProperty) targetEntity.getAttribute(pathItems[0]); - if (nextHop == null) - throw new ODataJPAModelException(MessageKeys.PATH_ELEMENT_NOT_FOUND, pathItems[0], attribute); - targetPath.add(nextHop); - for (int i = 1; i < pathItems.length; i++) { - if (nextHop.isComplex()) { - nextHop = (IntermediateProperty) nextHop.getStructuredType().getAttribute(pathItems[i]); - if (nextHop == null) - throw new ODataJPAModelException(MessageKeys.PATH_ELEMENT_NOT_FOUND, pathItems[0], attribute); - targetPath.add(nextHop); + @Override + public List getJoinColumnsList() throws ODataJPAModelException { + if (joinColumns == null) + joinColumns = buildJoinColumnsFromAnnotations(true, (AnnotatedElement) jpaAttribute.getJavaMember()); + final List result = new ArrayList<>(); + for (final IntermediateJoinColumn column : this.joinColumns) { + result.add(new JPAOnConditionItemImpl( + sourceType.getPathByDBField(column.getReferencedColumnName()), + ((IntermediateStructuredType) targetEntity).getPathByDBField(column.getName()))); + } + return result; + } + + @Override + public List getLeftColumnsList() throws ODataJPAModelException { + return Collections.emptyList(); + } + + @Override + public List getRightColumnsList() throws ODataJPAModelException { + return Collections.emptyList(); + } + + @Override + public JPAAssociationAttribute getLeaf() { + return null; + } + + @Override + public List getPath() { + return Collections.emptyList(); + } + + @Override + public JPAStructuredType getTargetType() { + return targetEntity; + } + + @Override + public JPAStructuredType getSourceType() { + return sourceType; + } + + @Override + public boolean isCollection() { + return false; + } + + @Override + public JPAAssociationAttribute getPartner() { + return null; + } + + @Override + public JPAJoinTable getJoinTable() { + return null; + } + + @Override + public List getInverseLeftJoinColumnsList() throws ODataJPAModelException { + return Collections.emptyList(); + } + + private List buildJoinColumnsFromAnnotations(final boolean isSourceOne, + final AnnotatedElement annotatedElement) throws ODataJPAModelException { + + int implicitColumns = 0; + final List result = new ArrayList<>(); + final JoinColumn[] columns = annotatedElement.getAnnotation(JoinColumns.class) != null ? annotatedElement + .getAnnotation(JoinColumns.class).value() : null; + + if (columns != null) { + for (final JoinColumn column : columns) { + final IntermediateJoinColumn intermediateColumn = new IntermediateJoinColumn(column); + final String refColumnName = intermediateColumn.getReferencedColumnName(); + final String name = intermediateColumn.getName(); + if (refColumnName == null || refColumnName.isEmpty() || name == null || name.isEmpty()) { + implicitColumns += 1; + if (implicitColumns > 1) + throw new ODataJPAModelException(ODataJPAModelException.MessageKeys.NOT_SUPPORTED_NO_IMPLICIT_COLUMNS, + getInternalName()); + fillMissingName(isSourceOne, intermediateColumn); + } + result.add(intermediateColumn); + } + } else { + final JoinColumn column = annotatedElement.getAnnotation(JoinColumn.class); + if (column != null) { + final IntermediateJoinColumn intermediateColumn = new IntermediateJoinColumn(column); + fillMissingName(isSourceOne, intermediateColumn); + result.add(intermediateColumn); } } - return new JPAPathImpl(nextHop.getExternalName(), nextHop.getDBFieldName(), targetPath); - } else { - final IntermediateProperty p = (IntermediateProperty) targetEntity.getAttribute(attribute); - return new JPAPathImpl(p.getExternalName(), p.getDBFieldName(), p); + return result; + } + + private void fillMissingName(final boolean isSourceOne, final IntermediateJoinColumn intermediateColumn) + throws ODataJPAModelException { + + final String refColumnName = intermediateColumn.getReferencedColumnName(); + final String name = intermediateColumn.getName(); + + if (isSourceOne && (emptyString(refColumnName))) + intermediateColumn.setReferencedColumnName(((IntermediateSimpleProperty) ((IntermediateEntityType) sourceType) + .getKey().get(0)).getDBFieldName()); + else if (isSourceOne && (emptyString(name))) + intermediateColumn.setReferencedColumnName(((IntermediateSimpleProperty) ((IntermediateEntityType) targetEntity) + .getKey().get(0)).getDBFieldName()); + else if (!isSourceOne && (emptyString(refColumnName))) + intermediateColumn.setReferencedColumnName(((IntermediateSimpleProperty) ((IntermediateEntityType) targetEntity) + .getKey().get(0)).getDBFieldName()); + else if (!isSourceOne && (emptyString(name))) + intermediateColumn.setReferencedColumnName(((IntermediateSimpleProperty) ((IntermediateEntityType) sourceType) + .getKey().get(0)).getDBFieldName()); + } + + @Override + public boolean hasJoinTable() { + return false; } } } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateEmbeddedIdProperty.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateEmbeddedIdProperty.java index 6baf7d587..f43712c48 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateEmbeddedIdProperty.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateEmbeddedIdProperty.java @@ -1,22 +1,20 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; +import static com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException.MessageKeys.TRANSIENT_KEY_NOT_SUPPORTED; + +import java.lang.reflect.AnnotatedElement; + import javax.persistence.metamodel.Attribute; +import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmTransient; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEdmNameBuilder; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; -final class IntermediateEmbeddedIdProperty extends IntermediateProperty { - private final Attribute embeddable; - - IntermediateEmbeddedIdProperty(final JPAEdmNameBuilder nameBuilder, final Attribute jpaAttribute, - final IntermediateSchema schema, final Attribute embeddable) throws ODataJPAModelException { - super(nameBuilder, jpaAttribute, schema); - this.embeddable = embeddable; - } +final class IntermediateEmbeddedIdProperty extends IntermediateSimpleProperty { IntermediateEmbeddedIdProperty(final JPAEdmNameBuilder nameBuilder, final Attribute jpaAttribute, final IntermediateSchema schema) throws ODataJPAModelException { super(nameBuilder, jpaAttribute, schema); - this.embeddable = null; } @Override @@ -24,7 +22,13 @@ public boolean isKey() { return true; } - Attribute getEmbeddable() { - return embeddable; + @Override + void determineTransient() throws ODataJPAModelException { + final EdmTransient jpaTransient = ((AnnotatedElement) this.jpaAttribute.getJavaMember()) + .getAnnotation(EdmTransient.class); + if (jpaTransient != null) { + throw new ODataJPAModelException(TRANSIENT_KEY_NOT_SUPPORTED, + jpaAttribute.getJavaMember().getDeclaringClass().getName()); + } } } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateEntityContainer.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateEntityContainer.java index d3696a732..4467584a8 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateEntityContainer.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateEntityContainer.java @@ -4,6 +4,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import org.apache.olingo.commons.api.edm.provider.CsdlAction; import org.apache.olingo.commons.api.edm.provider.CsdlActionImport; @@ -14,6 +15,7 @@ import org.apache.olingo.commons.api.edm.provider.CsdlFunctionImport; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAAction; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEdmNameBuilder; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEntitySet; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEntityType; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAFunction; @@ -29,17 +31,16 @@ */ //TODO How to handle multiple schemas final class IntermediateEntityContainer extends IntermediateModelElement implements IntermediateEntityContainerAccess { - final private Map schemaList; - final private Map entitySetListInternalKey; + private final Map schemaList; + private final Map entitySetListInternalKey; private CsdlEntityContainer edmContainer; - IntermediateEntityContainer(final JPAEdmNameBuilder nameBuilder, final Map schemaList) - throws ODataJPAModelException { + IntermediateEntityContainer(final JPAEdmNameBuilder nameBuilder, final Map schemaList) { super(nameBuilder, nameBuilder.buildContainerName()); this.schemaList = schemaList; this.setExternalName(nameBuilder.buildContainerName()); - this.entitySetListInternalKey = new HashMap(); + this.entitySetListInternalKey = new HashMap<>(); } @Override @@ -48,7 +49,7 @@ public void addAnnotations(List annotations) { } @Override - protected void lazyBuildEdmItem() throws ODataJPAModelException { + protected synchronized void lazyBuildEdmItem() throws ODataJPAModelException { if (edmContainer == null) { postProcessor.processEntityContainer(this); edmContainer = new CsdlEntityContainer(); @@ -63,12 +64,16 @@ protected void lazyBuildEdmItem() throws ODataJPAModelException { @Override CsdlEntityContainer getEdmItem() throws ODataJPAModelException { - lazyBuildEdmItem(); + if (edmContainer == null) { + lazyBuildEdmItem(); + } return edmContainer; } IntermediateEntitySet getEntitySet(final String edmEntitySetName) throws ODataJPAModelException { - lazyBuildEdmItem(); + if (edmContainer == null) { + lazyBuildEdmItem(); + } return (IntermediateEntitySet) findModelElementByEdmItem(edmEntitySetName, entitySetListInternalKey); } @@ -80,11 +85,12 @@ IntermediateEntitySet getEntitySet(final String edmEntitySetName) throws ODataJP * @throws ODataJPAModelException */ JPAEntitySet getEntitySet(final JPAEntityType entityType) throws ODataJPAModelException { - lazyBuildEdmItem(); - for (final String internalName : entitySetListInternalKey.keySet()) { - final IntermediateEntitySet modelElement = entitySetListInternalKey.get(internalName); - if (modelElement.getEntityType().getExternalFQN().equals(entityType.getExternalFQN())) { - return modelElement; + if (edmContainer == null) { + lazyBuildEdmItem(); + } + for (final Entry entitySet : entitySetListInternalKey.entrySet()) { + if (entitySet.getValue().getEntityType().getExternalFQN().equals(entityType.getExternalFQN())) { + return entitySet.getValue(); } } return null; @@ -99,10 +105,8 @@ JPAEntitySet getEntitySet(final JPAEntityType entityType) throws ODataJPAModelEx */ @SuppressWarnings("unchecked") private List buildEntitySets() throws ODataJPAModelException { - for (final String namespace : schemaList.keySet()) { - // Build Entity Sets - final IntermediateSchema schema = schemaList.get(namespace); - for (final IntermediateEntityType et : schema.getEntityTypes()) { + for (final Entry schema : schemaList.entrySet()) { + for (final IntermediateEntityType et : schema.getValue().getEntityTypes()) { if (!et.ignore() || et.asEntitySet()) { final IntermediateEntitySet es = new IntermediateEntitySet(nameBuilder, et); entitySetListInternalKey.put(es.internalName, es); @@ -123,7 +127,7 @@ private List buildEntitySets() throws ODataJPAModelException { private CsdlFunctionImport buildFunctionImport(final CsdlFunction edmFu) { final CsdlFunctionImport edmFuImport = new CsdlFunctionImport(); edmFuImport.setName(edmFu.getName()); - edmFuImport.setFunction(nameBuilder.buildFQN(edmFu.getName())); + edmFuImport.setFunction(buildFQN(edmFu.getName())); edmFuImport.setIncludeInServiceDocument(true); // edmFuImport.setEntitySet(entitySet) @@ -131,16 +135,16 @@ private CsdlFunctionImport buildFunctionImport(final CsdlFunction edmFu) { } private List buildFunctionImports() throws ODataJPAModelException { - final List edmFunctionImports = new ArrayList(); + final List edmFunctionImports = new ArrayList<>(); - for (final String namespace : schemaList.keySet()) { + for (final Entry namespace : schemaList.entrySet()) { // Build Entity Sets - final IntermediateSchema schema = schemaList.get(namespace); + final IntermediateSchema schema = namespace.getValue(); final List functions = schema.getFunctions(); if (functions != null) { for (final JPAFunction jpaFu : functions) { - if (((IntermediateFunction) jpaFu).isBound() == false && ((IntermediateFunction) jpaFu).hasImport()) + if (!((IntermediateFunction) jpaFu).isBound() && ((IntermediateFunction) jpaFu).hasImport()) edmFunctionImports.add(buildFunctionImport(((IntermediateFunction) jpaFu).getEdmItem())); } } @@ -149,11 +153,11 @@ private List buildFunctionImports() throws ODataJPAModelExce } private List buildActionImports() throws ODataJPAModelException { - final List edmActionImports = new ArrayList(); + final List edmActionImports = new ArrayList<>(); - for (final String namespace : schemaList.keySet()) { + for (final Entry namespace : schemaList.entrySet()) { // Build Entity Sets - final IntermediateSchema schema = schemaList.get(namespace); + final IntermediateSchema schema = namespace.getValue(); final List actions = schema.getActions(); if (actions != null) { @@ -178,7 +182,7 @@ private List buildActionImports() throws ODataJPAModelExceptio private CsdlActionImport buildActionImport(CsdlAction edmAc) { final CsdlActionImport edmAcImport = new CsdlActionImport(); edmAcImport.setName(edmAc.getName()); - edmAcImport.setAction(nameBuilder.buildFQN(edmAc.getName())); + edmAcImport.setAction(buildFQN(edmAc.getName())); // edmAcImport.setEntitySet(entitySet) return edmAcImport; } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateEntitySet.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateEntitySet.java index 59f2b1fff..4f87f44b7 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateEntitySet.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateEntitySet.java @@ -10,6 +10,7 @@ import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAAssociationAttribute; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAAssociationPath; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEdmNameBuilder; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEntitySet; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEntityType; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; @@ -62,14 +63,14 @@ public void addAnnotations(List annotations) { } @Override - protected void lazyBuildEdmItem() throws ODataJPAModelException { + protected synchronized void lazyBuildEdmItem() throws ODataJPAModelException { if (edmEntitySet == null) { postProcessor.processEntitySet(this); edmEntitySet = new CsdlEntitySet(); final CsdlEntityType edmEt = ((IntermediateEntityType) getODataEntityType()).getEdmItem(); edmEntitySet.setName(getExternalName()); - edmEntitySet.setType(nameBuilder.buildFQN(edmEt.getName())); + edmEntitySet.setType(buildFQN(edmEt.getName())); // Create navigation Property Binding // V4: An entity set or a singleton SHOULD contain an edm:NavigationPropertyBinding element for each navigation @@ -81,7 +82,7 @@ protected void lazyBuildEdmItem() throws ODataJPAModelException { } private List determinePropertyBinding() throws ODataJPAModelException { - final List navPropBindingList = new ArrayList(); + final List navPropBindingList = new ArrayList<>(); final List naviPropertyList = entityType.getAssociationPathList(); if (naviPropertyList != null && !naviPropertyList.isEmpty()) { // http://docs.oasis-open.org/odata/odata/v4.0/errata02/os/complete/part3-csdl/odata-v4.0-errata02-os-part3-csdl-complete.html#_Toc406398035 @@ -101,7 +102,9 @@ private List determinePropertyBinding() throws OD @Override CsdlEntitySet getEdmItem() throws ODataJPAModelException { // New test EdmItem with ODataEntityType - lazyBuildEdmItem(); + if (edmEntitySet == null) { + lazyBuildEdmItem(); + } return edmEntitySet; } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateEntityType.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateEntityType.java index 222a34526..95a3b7c74 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateEntityType.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateEntityType.java @@ -1,17 +1,26 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import javax.annotation.Nonnull; +import javax.persistence.IdClass; import javax.persistence.Table; +import javax.persistence.metamodel.EmbeddableType; import javax.persistence.metamodel.EntityType; import javax.persistence.metamodel.IdentifiableType; +import javax.persistence.metamodel.Type; +import org.apache.olingo.commons.api.edm.provider.CsdlAbstractEdmItem; import org.apache.olingo.commons.api.edm.provider.CsdlAnnotation; import org.apache.olingo.commons.api.edm.provider.CsdlEntityType; import org.apache.olingo.commons.api.edm.provider.CsdlNavigationProperty; @@ -19,10 +28,12 @@ import org.apache.olingo.commons.api.edm.provider.CsdlPropertyRef; import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmAsEntitySet; -import com.sap.olingo.jpa.metadata.core.edm.mapper.annotation.AppliesTo; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAAttribute; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPACollectionAttribute; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEdmNameBuilder; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEntityType; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAPath; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAStructuredType; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediateEntityTypeAccess; @@ -35,15 +46,15 @@ */ final class IntermediateEntityType extends IntermediateStructuredType implements JPAEntityType, IntermediateEntityTypeAccess { - private CsdlEntityType edmEntityType; - private boolean hasEtag; + private Optional etagPath; + private List keyAttributes; private final boolean asEntitySet; - IntermediateEntityType(final JPAEdmNameBuilder nameBuilder, final EntityType et, final IntermediateSchema schema) - throws ODataJPAModelException { + IntermediateEntityType(final JPAEdmNameBuilder nameBuilder, final EntityType et, final IntermediateSchema schema) { super(nameBuilder, et, schema); this.setExternalName(nameBuilder.buildEntityTypeName(et)); asEntitySet = determineAsEntitySet(); + etagPath = Optional.empty(); } @Override @@ -52,9 +63,36 @@ public void addAnnotations(List annotations) { } + @Override + public Optional getAttribute(final String internalName) throws ODataJPAModelException { + if (edmStructuralType == null) { + lazyBuildEdmItem(); + } + final Optional a = super.getAttribute(internalName); + if (a.isPresent()) + return a; + return getKey(internalName); + } + + @Override + public JPACollectionAttribute getCollectionAttribute(final String externalName) throws ODataJPAModelException { + final JPAPath path = getPath(externalName); + if (path != null && path.getLeaf() instanceof JPACollectionAttribute) + return (JPACollectionAttribute) path.getLeaf(); + return null; + } + + @Override + public Optional getDeclaredAttribute(@Nonnull final String internalName) throws ODataJPAModelException { + final Optional a = super.getDeclaredAttribute(internalName); + if (a.isPresent()) + return a; + return getKey(internalName); + } + @Override public String getContentType() throws ODataJPAModelException { - final IntermediateProperty stream = getStreamProperty(); + final IntermediateSimpleProperty stream = getStreamProperty(); return stream.getContentType(); } @@ -68,58 +106,83 @@ public JPAPath getContentTypeAttributePath() throws ODataJPAModelException { return getPathByDBField(getProperty(propertyInternalName).getDBFieldName()); } + @Override + public JPAPath getEtagPath() throws ODataJPAModelException { + if (hasEtag() && etagPath.isPresent()) + return etagPath.get(); + return null; + } + @Override public List getKey() throws ODataJPAModelException { - lazyBuildEdmItem(); - final List key = new ArrayList(); - - for (final String internalName : this.declaredPropertiesList.keySet()) { - final JPAAttribute attribute = this.declaredPropertiesList.get(internalName); - if (attribute.isKey()) { - if (attribute.isComplex()) { - key.addAll(((IntermediateEmbeddedIdProperty) attribute).getStructuredType().getAttributes()); - } else - key.add(attribute); - } + if (edmStructuralType == null) { + lazyBuildEdmItem(); } - final IntermediateStructuredType baseType = getBaseType(); - if (baseType != null) { - key.addAll(((IntermediateEntityType) baseType).getKey()); + if (keyAttributes == null) { + final List intermediateKey = new ArrayList<>(); // Cycle break + final Field[] keyFields = this.getTypeClass().getDeclaredFields(); + for (int i = keyFields.length - 1; i >= 0; i--) { + final JPAAttribute attribute = this.declaredPropertiesList.get(keyFields[i].getName()); + if (attribute != null && attribute.isKey()) { + if (attribute.isComplex()) { + intermediateKey.addAll(buildEmbeddedIdKey(attribute)); + } else { + intermediateKey.add(attribute); + } + } + } + final IntermediateStructuredType baseType = getBaseType(); + if (baseType != null) { + intermediateKey.addAll(((IntermediateEntityType) baseType).getKey()); + } + keyAttributes = Collections.unmodifiableList(intermediateKey); } - return key; + return keyAttributes; } @Override public List getKeyPath() throws ODataJPAModelException { - lazyBuildEdmItem(); - - final List result = new ArrayList(); - for (final String internalName : this.declaredPropertiesList.keySet()) { - final JPAAttribute attribute = this.declaredPropertiesList.get(internalName); + if (edmStructuralType == null) { + lazyBuildEdmItem(); + } + final List result = new ArrayList<>(); + for (final Entry property : this.declaredPropertiesList.entrySet()) { + final JPAAttribute attribute = property.getValue(); if (attribute instanceof IntermediateEmbeddedIdProperty) { result.add(intermediatePathMap.get(attribute.getExternalName())); - } else if (attribute.isKey()) + } else if (attribute.isKey()) { result.add(resolvedPathMap.get(attribute.getExternalName())); + } } final IntermediateStructuredType baseType = getBaseType(); if (baseType != null) { result.addAll(((IntermediateEntityType) baseType).getKeyPath()); } - return result; + return Collections.unmodifiableList(result); } @Override public Class getKeyType() { - if (jpaManagedType instanceof IdentifiableType) - return ((IdentifiableType) jpaManagedType).getIdType().getJavaType(); - else + if (jpaManagedType instanceof IdentifiableType) { + Class idClass = null; + final Type idType = ((IdentifiableType) jpaManagedType).getIdType(); + + if (idType == null) + // Hibernate does not return an IdType in case of compound key that do not use + // EmbeddableId. So fallback to hand made evaluation + idClass = jpaManagedType.getJavaType().getAnnotation(IdClass.class).value(); + else + idClass = idType.getJavaType(); + return idClass; + } else { return null; + } } @Override public List getSearchablePath() throws ODataJPAModelException { final List allPath = getPathList(); - final List searchablePath = new ArrayList(); + final List searchablePath = new ArrayList<>(); for (final JPAPath p : allPath) { if (p.getLeaf().isSearchable()) searchablePath.add(p); @@ -139,22 +202,35 @@ public String getTableName() { if (a != null) t = a.getAnnotation(Table.class); + final IntermediateStructuredType baseType = getBaseType(); + if (t == null && baseType != null) + return ((IntermediateEntityType) baseType).getTableName(); + return (t == null) ? jpaManagedType.getJavaType().getSimpleName().toUpperCase(Locale.ENGLISH) + : buildFQTableName(t.schema(), t.name()); + } - return (t == null) ? jpaManagedType.getJavaType().getName().toUpperCase(Locale.ENGLISH) - : t.name(); + @Override + public boolean hasCompoundKey() { + final Type idType = ((IdentifiableType) jpaManagedType).getIdType(); + return jpaManagedType.getJavaType().getAnnotation(IdClass.class) != null + || idType instanceof EmbeddableType; } @Override public boolean hasEtag() throws ODataJPAModelException { - lazyBuildEdmItem(); - return hasEtag; + if (edmStructuralType == null) { + lazyBuildEdmItem(); + } + return etagPath.isPresent(); } @Override public boolean hasStream() throws ODataJPAModelException { - lazyBuildEdmItem(); + if (edmStructuralType == null) { + lazyBuildEdmItem(); + } return this.determineHasStream(); - }; + } @Override public boolean ignore() { @@ -168,9 +244,9 @@ public boolean isAbstract() { @Override public List searchChildPath(final JPAPath selectItemPath) { - final List result = new ArrayList(); - for (final String pathName : this.resolvedPathMap.keySet()) { - final JPAPath p = resolvedPathMap.get(pathName); + final List result = new ArrayList<>(); + for (final Entry path : this.resolvedPathMap.entrySet()) { + final JPAPath p = path.getValue(); if (!p.ignore() && p.getAlias().startsWith(selectItemPath.getAlias())) result.add(p); } @@ -179,18 +255,21 @@ public List searchChildPath(final JPAPath selectItemPath) { @SuppressWarnings("unchecked") @Override - protected List extractEdmModelElements(final Map mappingBuffer) throws ODataJPAModelException { - final List extractionTarget = new ArrayList(); - for (final String externalName : mappingBuffer.keySet()) { - if (!((IntermediateModelElement) mappingBuffer.get(externalName)).ignore() + protected List extractEdmModelElements( + final Map mappingBuffer) + throws ODataJPAModelException { + + final List extractionTarget = new ArrayList<>(); + for (final Entry element : mappingBuffer.entrySet()) { + if (!element.getValue().ignore() // Skip Streams - && !(mappingBuffer.get(externalName) instanceof IntermediateProperty && - ((IntermediateProperty) mappingBuffer.get(externalName)).isStream())) { - if (mappingBuffer.get(externalName) instanceof IntermediateEmbeddedIdProperty) { + && !(element.getValue() instanceof IntermediateSimpleProperty && + ((IntermediateSimpleProperty) element.getValue()).isStream())) { + if (element.getValue() instanceof IntermediateEmbeddedIdProperty) { extractionTarget.addAll((Collection) resolveEmbeddedId( - (IntermediateEmbeddedIdProperty) mappingBuffer.get(externalName))); + (IntermediateEmbeddedIdProperty) element.getValue())); } else { - extractionTarget.add((T) ((IntermediateModelElement) mappingBuffer.get(externalName)).getEdmItem()); + extractionTarget.add((T) element.getValue().getEdmItem()); } } } @@ -199,23 +278,25 @@ protected List extractEdmModelElements(final Map mappingBuffer @SuppressWarnings("unchecked") @Override - protected void lazyBuildEdmItem() throws ODataJPAModelException { - if (edmEntityType == null) { + protected synchronized void lazyBuildEdmItem() throws ODataJPAModelException { + if (edmStructuralType == null) { buildPropertyList(); buildNaviPropertyList(); + addTransientProperties(); postProcessor.processEntityType(this); - edmEntityType = new CsdlEntityType(); - edmEntityType.setName(getExternalName()); - edmEntityType.setProperties((List) extractEdmModelElements(declaredPropertiesList)); - edmEntityType.setNavigationProperties((List) extractEdmModelElements( + edmStructuralType = new CsdlEntityType(); + edmStructuralType.setName(getExternalName()); + edmStructuralType.setProperties((List) extractEdmModelElements(declaredPropertiesList)); + edmStructuralType.setNavigationProperties((List) extractEdmModelElements( declaredNaviPropertiesList)); - edmEntityType.setKey(extractEdmKeyElements(declaredPropertiesList)); - edmEntityType.setAbstract(determineAbstract()); - edmEntityType.setBaseType(determineBaseType()); - edmEntityType.setHasStream(determineHasStream()); - edmEntityType.setAnnotations(determineAnnotations()); + ((CsdlEntityType) edmStructuralType).setKey(extractEdmKeyElements(declaredPropertiesList)); + edmStructuralType.setAbstract(determineAbstract()); + edmStructuralType.setBaseType(determineBaseType()); + ((CsdlEntityType) edmStructuralType).setHasStream(determineHasStream()); + edmStructuralType.setAnnotations(determineAnnotations()); determineHasEtag(); + checkPropertyConsistancy(); // TODO determine OpenType } } @@ -224,22 +305,26 @@ boolean asEntitySet() { return asEntitySet; } + boolean dbEquals(final String dbCatalog, final String dbSchema, final String dbTableName) { + final AnnotatedElement a = jpaManagedType.getJavaType(); + Table t = null; + if (a != null) + t = a.getAnnotation(Table.class); + if (t == null) + return (dbCatalog == null || dbCatalog.isEmpty()) + && (dbSchema == null || dbSchema.isEmpty()) + && dbTableName.equals(getTableName()); + else + return dbCatalog.equals(t.catalog()) + && dbSchema.equals(t.schema()) + && dbTableName.equals(t.name()); + } + boolean determineAbstract() { final int modifiers = jpaManagedType.getJavaType().getModifiers(); return Modifier.isAbstract(modifiers); } - private void determineHasEtag() throws ODataJPAModelException { - for (final String internalName : this.declaredPropertiesList.keySet()) { - if (declaredPropertiesList.get(internalName).isEtag()) { - hasEtag = true; - return; - } - } - if (getBaseType() != null && getBaseType() instanceof IntermediateEntityType) - hasEtag = ((IntermediateEntityType) getBaseType()).hasEtag(); - } - /** * Creates the key of an entity. In case the POJO is declared with an embedded ID the key fields get resolved, so that * they occur as separate properties within the metadata document @@ -251,22 +336,21 @@ private void determineHasEtag() throws ODataJPAModelException { List extractEdmKeyElements(final Map propertyList) throws ODataJPAModelException { // TODO setAlias - final List keyList = new ArrayList(); - for (final String internalName : propertyList.keySet()) { - if (propertyList.get(internalName).isKey()) { - if (propertyList.get(internalName).isComplex()) { - final List idAttributes = ((IntermediateComplexType) propertyList.get(internalName) - .getStructuredType()) - .getAttributes(); + final List keyList = new ArrayList<>(); + for (final Entry property : propertyList.entrySet()) { + if (property.getValue().isKey()) { + if (property.getValue().isComplex()) { + final List idAttributes = ((IntermediateComplexType) property.getValue() + .getStructuredType()).getAttributes(); for (final JPAAttribute idAttribute : idAttributes) { - final CsdlPropertyRef key = new CsdlPropertyRef(); - key.setName(idAttribute.getExternalName()); - keyList.add(key); + final CsdlPropertyRef keyElement = new CsdlPropertyRef(); + keyElement.setName(idAttribute.getExternalName()); + keyList.add(keyElement); } } else { - final CsdlPropertyRef key = new CsdlPropertyRef(); - key.setName(propertyList.get(internalName).getExternalName()); - keyList.add(key); + final CsdlPropertyRef keyElement = new CsdlPropertyRef(); + keyElement.setName(property.getValue().getExternalName()); + keyList.add(keyElement); } } } @@ -275,25 +359,56 @@ List extractEdmKeyElements(final Map buildEmbeddedIdKey(final JPAAttribute attribute) throws ODataJPAModelException { + + final JPAStructuredType id = ((IntermediateEmbeddedIdProperty) attribute).getStructuredType(); + final List keyElements = new ArrayList<>(id.getTypeClass().getDeclaredFields().length); + final Field[] keyFields = id.getTypeClass().getDeclaredFields(); + for (int i = keyFields.length - 1; i >= 0; i--) { + id.getAttribute(keyFields[i].getName()).ifPresent(keyElements::add); + } + return keyElements; } private List determineAnnotations() throws ODataJPAModelException { - getAnnotations(edmAnnotations, this.jpaManagedType.getJavaType(), internalName, AppliesTo.ENTITY_TYPE); + getAnnotations(edmAnnotations, this.jpaManagedType.getJavaType(), internalName); return edmAnnotations; } private boolean determineAsEntitySet() { - final EdmAsEntitySet jpaAsEntitySet = ((AnnotatedElement) this.jpaManagedType.getJavaType()).getAnnotation( - EdmAsEntitySet.class); - if (jpaAsEntitySet != null) { - return true; - } else - return false; + + final EdmAsEntitySet jpaAsEntitySet = this.jpaManagedType.getJavaType().getAnnotation(EdmAsEntitySet.class); + return jpaAsEntitySet != null; } - private List resolveEmbeddedId(final IntermediateEmbeddedIdProperty embeddedId) throws ODataJPAModelException { + private void determineHasEtag() throws ODataJPAModelException { + for (final Entry property : this.declaredPropertiesList.entrySet()) { + if (property.getValue().isEtag()) { + etagPath = Optional.of(getPath(property.getValue().getExternalName(), false)); + } + } + if (getBaseType() instanceof IntermediateEntityType) + etagPath = Optional.ofNullable(((IntermediateEntityType) getBaseType()).getEtagPath()); + } + + private Optional getKey(final String internalName) throws ODataJPAModelException { + if (internalName == null) + return Optional.empty(); + for (JPAAttribute attribute : getKey()) { + if (internalName.equals(attribute.getInternalName())) + return Optional.of(attribute); + } + return Optional.empty(); + } + + private List resolveEmbeddedId(final IntermediateEmbeddedIdProperty embeddedId) + throws ODataJPAModelException { return ((IntermediateComplexType) embeddedId.getStructuredType()).getEdmItem().getProperties(); } } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateEnumerationType.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateEnumerationType.java index f3739d009..3d1189875 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateEnumerationType.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateEnumerationType.java @@ -1,59 +1,209 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; +import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import javax.persistence.AttributeConverter; + +import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind; +import org.apache.olingo.commons.api.edm.FullQualifiedName; import org.apache.olingo.commons.api.edm.provider.CsdlEnumMember; import org.apache.olingo.commons.api.edm.provider.CsdlEnumType; +import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmEnumeration; +import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmEnumeration.DummyConverter; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEdmNameBuilder; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEnumerationAttribute; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; +import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException.MessageKeys; -class IntermediateEnumerationType extends IntermediateModelElement { +class IntermediateEnumerationType extends IntermediateModelElement implements JPAEnumerationAttribute { private CsdlEnumType edmEnumType; private Class javaEnum; + private EdmEnumeration annotation; + private List javaMembers; - IntermediateEnumerationType(JPAEdmNameBuilder nameBuilder, Class javaEnum) { + IntermediateEnumerationType(final JPAEdmNameBuilder nameBuilder, final Class> javaEnum) { super(nameBuilder, javaEnum.getSimpleName()); - assert javaEnum.isEnum(); + this.setExternalName(nameBuilder.buildEnumerationTypeName(javaEnum)); this.javaEnum = javaEnum; } @Override - protected void lazyBuildEdmItem() throws ODataJPAModelException { + public Object convert(List values) throws ODataJPAModelException { + if (values == null || values.isEmpty()) + return null; + if (annotation.converter() == EdmEnumeration.DummyConverter.class) + return enumOf(values.get(0)); + else { + final Enum[] array = getArray(javaEnum, values.size(), null); + for (int i = 0; i < values.size(); i++) { + array[i] = enumOf(values.get(i)); + } + return array; + } + } + + @SuppressWarnings("unchecked") + @Override + public > T enumOf(final String value) throws ODataJPAModelException { + if (edmEnumType == null) { + lazyBuildEdmItem(); + } + for (Object member : javaMembers) + if (((T) member).name().equals(value)) + return (T) member; + return null; + } + + @Override + @SuppressWarnings("unchecked") + public > E enumOf(final T value) throws ODataJPAModelException { + if (edmEnumType == null) { + lazyBuildEdmItem(); + } + if (annotation.converter() != DummyConverter.class) { + try { + final AttributeConverter[], T> converter = (AttributeConverter[], T>) annotation.converter() + .newInstance(); + return (E) (converter.convertToEntityAttribute(value)[0]); + } catch (InstantiationException | IllegalAccessException e) { + throw new ODataJPAModelException(e); + } + } else { + for (Object member : javaMembers) + if (((Enum) member).ordinal() == (Integer) value) + return (E) member; + } + return null; + } + + @Override + public boolean isFlags() throws ODataJPAModelException { + if (edmEnumType == null) { + lazyBuildEdmItem(); + } + return edmEnumType.isFlags(); + } + + @SuppressWarnings("unchecked") + @Override + public T valueOf(final String value) throws ODataJPAModelException { + try { + final AttributeConverter[], ? extends Number> converter = + (AttributeConverter[], ? extends Number>) annotation.converter().newInstance(); + final Enum[] array = getArray(javaEnum, 1, enumOf(value)); + return (T) converter.convertToDatabaseColumn(array); + } catch (InstantiationException | IllegalAccessException e) { + throw new ODataJPAModelException(e); + } + } + + @SuppressWarnings("unchecked") + @Override + public T valueOf(final List values) throws ODataJPAModelException { + if (values == null || values.isEmpty()) + return null; + if (annotation.converter() == EdmEnumeration.DummyConverter.class) + return valueOf(values.get(0)); + else { + try { + final AttributeConverter[], T> converter = (AttributeConverter[], T>) annotation.converter() + .newInstance(); + return converter.convertToDatabaseColumn((Enum[]) convert(values)); + } catch (InstantiationException | IllegalAccessException e) { + throw new ODataJPAModelException(e); + } + + } + } + + @Override + protected synchronized void lazyBuildEdmItem() throws ODataJPAModelException { if (edmEnumType == null) { + annotation = getAnnotation(); edmEnumType = new CsdlEnumType(); -// edmEnumType.setFlags(isFlags); + edmEnumType.setFlags(determineIsFlag()); edmEnumType.setMembers(buildMembers()); -// edmEnumType.setName(name); -// edmEnumType.setUnderlyingType(underlyingType); + edmEnumType.setName(getExternalName()); + edmEnumType.setUnderlyingType(determineUnderlyingType()); } } @Override CsdlEnumType getEdmItem() throws ODataJPAModelException { - lazyBuildEdmItem(); + if (edmEnumType == null) { + lazyBuildEdmItem(); + } return edmEnumType; } - private List buildMembers() { - List members = new ArrayList(); + private List buildMembers() throws ODataJPAModelException { + final List members = new ArrayList<>(); - final List javaMembers = Arrays.asList(javaEnum.getEnumConstants()); + javaMembers = Arrays.asList(javaEnum.getEnumConstants()); - for (final Object o : javaMembers) { - if (o instanceof Enum) { - final Enum e = (Enum) o; + for (final Object constants : javaMembers) { + if (constants instanceof Enum) { + final Enum e = (Enum) constants; CsdlEnumMember member = new CsdlEnumMember(); - - e.name(); member.setName(e.name()); - member.setValue(Integer.valueOf(((ODataEnum) e).getValue() == null ? e.ordinal() : ((ODataEnum) e).getValue()) - .toString()); + Number value = valueOf(e.toString()); + if (determineIsFlag() && value.longValue() < 0L) + // An Enumeration that is marked as Flag must not have a negative value: '%1$s - %2$s'. + throw new ODataJPAModelException(MessageKeys.ENUMERATION_NO_NEGATIVE_VALUE, e.name(), javaEnum + .getName()); + member.setValue(String.valueOf(value)); + members.add(member); } } return members; } + private boolean determineIsFlag() { + return annotation.isFlags(); + } + + private FullQualifiedName determineUnderlyingType() throws ODataJPAModelException { + if (javaEnum.getEnumConstants().length == 0) + return EdmPrimitiveTypeKind.Int32.getFullQualifiedName(); + + final T value = valueOf(javaEnum.getEnumConstants()[0].toString()); + final EdmPrimitiveTypeKind type = JPATypeConvertor.convertToEdmSimpleType(value.getClass()); + if (isValidType(type)) + return type.getFullQualifiedName(); + // Enumeration '%1$s' has the unsupported type '%2$s'. + throw new ODataJPAModelException(MessageKeys.ENUMERATION_UNSUPPORTED_TYPE, javaEnum.getName(), type + .getFullQualifiedName().getFullQualifiedNameAsString()); + + } + + private EdmEnumeration getAnnotation() throws ODataJPAModelException { + final EdmEnumeration enumAnnotation = javaEnum.getAnnotation(EdmEnumeration.class); + if (enumAnnotation == null) + // Annotation EdmEnumeration is missing for Enum %1$s. + throw new ODataJPAModelException(ODataJPAModelException.MessageKeys.ENUMERATION_ANNOTATION_MISSING, javaEnum + .getName()); + return enumAnnotation; + } + + @SuppressWarnings("unchecked") + private > E[] getArray(Class javaEnum, int size, Enum e) { + E[] arr = (E[]) Array.newInstance(javaEnum, size); + arr[0] = (E) e; + return arr; + } + + private boolean isValidType(EdmPrimitiveTypeKind type) { + // "Edm.Byte, Edm.SByte, Edm.Int16, Edm.Int32, or Edm.Int64." + return type == EdmPrimitiveTypeKind.Byte + || type == EdmPrimitiveTypeKind.Int16 + || type == EdmPrimitiveTypeKind.Int32 + || type == EdmPrimitiveTypeKind.Int64 + || type == EdmPrimitiveTypeKind.SByte; + } + } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateFunction.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateFunction.java index de66a04f2..f9816f403 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateFunction.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateFunction.java @@ -11,6 +11,7 @@ import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmFunction; import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmFunction.ReturnType; import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmParameter; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEdmNameBuilder; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAFunction; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAParameter; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; @@ -34,7 +35,7 @@ abstract class IntermediateFunction extends IntermediateOperation implements JPA protected final IntermediateSchema schema; IntermediateFunction(final JPAEdmNameBuilder nameBuilder, final EdmFunction jpaFunction, - final IntermediateSchema schema, final String internalName) throws ODataJPAModelException { + final IntermediateSchema schema, final String internalName) { super(nameBuilder, internalName); this.jpaFunction = jpaFunction; @@ -42,7 +43,7 @@ abstract class IntermediateFunction extends IntermediateOperation implements JPA } @Override - protected void lazyBuildEdmItem() throws ODataJPAModelException { + protected synchronized void lazyBuildEdmItem() throws ODataJPAModelException { if (edmFunction == null) { edmFunction = new CsdlFunction(); edmFunction.setName(getExternalName()); @@ -51,6 +52,15 @@ protected void lazyBuildEdmItem() throws ODataJPAModelException { edmFunction.setBound(jpaFunction.isBound()); // TODO edmFunction.setComposable(isComposable) edmFunction.setComposable(false); + /* + * Bound actions and functions that return an entity or a collection of entities MAY specify an entity set path if + * the entity set of the returned entities depends on the entity set of the binding parameter value. + * The entity set path consists of a series of segments joined together with forward slashes. + * The first segment of the entity set path MUST be the name of the binding parameter. The remaining segments of + * the entity set path MUST represent navigation segments or type casts. + * A navigation segment names the simple identifier of the navigation property to be traversed. A type-cast + * segment names the qualified name of the entity type that should be returned from the type cast. + */ // TODO edmFunction.setEntitySetPath(entitySetPath) for bound functions } @@ -58,7 +68,9 @@ protected void lazyBuildEdmItem() throws ODataJPAModelException { @Override CsdlFunction getEdmItem() throws ODataJPAModelException { - lazyBuildEdmItem(); + if (edmFunction == null) { + lazyBuildEdmItem(); + } return edmFunction; } @@ -72,7 +84,7 @@ boolean hasImport() { } @Override - boolean isBound() throws ODataJPAModelException { + public boolean isBound() throws ODataJPAModelException { return getEdmItem().isBound(); } @@ -80,6 +92,9 @@ boolean isBound() throws ODataJPAModelException { protected abstract CsdlReturnType determineEdmResultType(final ReturnType returnType) throws ODataJPAModelException; + protected abstract FullQualifiedName determineParameterType(final Class type, + final EdmParameter definedParameter) throws ODataJPAModelException; + protected class IntermediatFunctionParameter implements JPAParameter { private final EdmParameter jpaParameter; private final String internalName; @@ -93,7 +108,7 @@ protected class IntermediatFunctionParameter implements JPAParameter { this.type = jpaParameter.type(); } - public IntermediatFunctionParameter(EdmParameter jpaParameter, String externalName, + IntermediatFunctionParameter(EdmParameter jpaParameter, String externalName, String internalName, Class type) { this.jpaParameter = jpaParameter; this.internalName = internalName; @@ -133,7 +148,7 @@ public Integer getScale() { @Override public FullQualifiedName getTypeFQN() throws ODataJPAModelException { - return JPATypeConvertor.convertToEdmSimpleType(jpaParameter.type()).getFullQualifiedName(); + return determineParameterType(type, jpaParameter); } @Override diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateFunctionFactory.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateFunctionFactory.java index 0ac939d04..cd0434d05 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateFunctionFactory.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateFunctionFactory.java @@ -11,6 +11,7 @@ import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmFunction; import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmFunctions; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEdmNameBuilder; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.ODataFunction; @@ -27,17 +28,17 @@ final class IntermediateFunctionFactory extends IntermediateOperationFactory { Map create(final JPAEdmNameBuilder nameBuilder, final EntityType jpaEntityType, final IntermediateSchema schema) throws ODataJPAModelException { - final Map funcList = new HashMap(); + final Map funcList = new HashMap<>(); if (jpaEntityType.getJavaType() instanceof AnnotatedElement) { - final EdmFunctions jpaStoredProcedureList = ((AnnotatedElement) jpaEntityType.getJavaType()) + final EdmFunctions jpaStoredProcedureList = jpaEntityType.getJavaType() .getAnnotation(EdmFunctions.class); if (jpaStoredProcedureList != null) { for (final EdmFunction jpaStoredProcedure : jpaStoredProcedureList.value()) { putFunction(nameBuilder, jpaEntityType, schema, funcList, jpaStoredProcedure); } } else { - final EdmFunction jpaStoredProcedure = ((AnnotatedElement) jpaEntityType.getJavaType()) + final EdmFunction jpaStoredProcedure = jpaEntityType.getJavaType() .getAnnotation(EdmFunction.class); if (jpaStoredProcedure != null) putFunction(nameBuilder, jpaEntityType, schema, funcList, jpaStoredProcedure); diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateJavaAction.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateJavaAction.java index 5726614e0..32938ce73 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateJavaAction.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateJavaAction.java @@ -17,6 +17,7 @@ import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmFunction.ReturnType; import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmParameter; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAAction; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEdmNameBuilder; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAOperationResultParameter; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAParameter; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; @@ -56,7 +57,7 @@ public Method getMethod() { public List getParameter() throws ODataJPAModelException { if (parameterList == null) { - parameterList = new ArrayList(); + parameterList = new ArrayList<>(); Class[] types = javaAction.getParameterTypes(); Parameter[] declairedParameters = javaAction.getParameters(); for (int i = 0; i < declairedParameters.length; i++) { @@ -75,14 +76,16 @@ public List getParameter() throws ODataJPAModelException { types[i]); parameterList.add(parameter); } - } return parameterList; } @Override - public JPAParameter getParameter(Parameter declairedParameter) { - // TODO Auto-generated method stub + public JPAParameter getParameter(Parameter declairedParameter) throws ODataJPAModelException { + for (JPAParameter param : getParameter()) { + if (param.getInternalName().equals(declairedParameter.getName())) + return param; + } return null; } @@ -98,52 +101,62 @@ public CsdlReturnType getReturnType() { } protected List determineEdmInputParameter() throws ODataJPAModelException { - final List parameterList = new ArrayList(); + final List parameters = new ArrayList<>(); final List jpaParameterList = getParameter(); - int bindingPosition = 0; + final BindingPosition bindingPosition = new BindingPosition(); + for (int i = 0; i < jpaParameterList.size(); i++) { final JPAParameter jpaParameter = jpaParameterList.get(i); final CsdlParameter parameter = new CsdlParameter(); parameter.setName(jpaParameter.getName()); - final EdmPrimitiveTypeKind edmType = JPATypeConvertor.convertToEdmSimpleType(jpaParameter.getType()); - if (!jpaAction.isBound()) { - if (edmType == null) - throw new ODataJPAModelException(ODataJPAModelException.MessageKeys.ACTION_PARAM_ONLY_PRIMITIVE, - javaAction.getDeclaringClass().getName(), javaAction.getName(), jpaParameter.getInternalName()); - - parameter.setType(edmType.getFullQualifiedName()); - } else if (edmType == null) { - final IntermediateStructuredType structuredType = schema.getEntityType(jpaParameter.getType()); - if (structuredType != null) { - if (bindingPosition == 0) - bindingPosition = i + 1; - parameter.setType(structuredType.getExternalFQN()); - } else - // The type of %1$s of action of method %2$s of class %1$s could not be converted - throw new ODataJPAModelException(ODataJPAModelException.MessageKeys.ACTION_PARAM_ONLY_PRIMITIVE, - jpaParameter.getInternalName(), javaAction.getName(), javaAction.getDeclaringClass().getName()); - } + parameter.setType(determineParameterType(bindingPosition, i, jpaParameter)); parameter.setPrecision(nullIfNotSet(jpaParameter.getPrecision())); parameter.setScale(nullIfNotSet(jpaParameter.getScale())); parameter.setMaxLength(nullIfNotSet(jpaParameter.getMaxLength())); parameter.setSrid(jpaParameter.getSrid()); - parameterList.add(parameter); + parameters.add(parameter); } - if (jpaAction.isBound() && bindingPosition != 1) + if (jpaAction.isBound() && bindingPosition.getPos() != 1) // Binding parameter not found within in interface of method %1$s of class %2$s. Binding parameter must be the // first parameter. throw new ODataJPAModelException(ODataJPAModelException.MessageKeys.ACTION_PARAM_BINGING_NOT_FOUND, javaAction.getName(), javaAction.getDeclaringClass().getName()); - return parameterList; + return parameters; + } + + private FullQualifiedName determineParameterType(final BindingPosition bindingPosition, final int i, + final JPAParameter jpaParameter) throws ODataJPAModelException { + + final EdmPrimitiveTypeKind edmType = JPATypeConvertor.convertToEdmSimpleType(jpaParameter.getType()); + if (edmType != null) + return edmType.getFullQualifiedName(); + final IntermediateEnumerationType enumType = schema.getEnumerationType(jpaParameter.getType()); + if (enumType != null) { + return enumType.getExternalFQN(); + } else { + final IntermediateStructuredType structuredType = schema.getEntityType(jpaParameter.getType()); + if (structuredType != null) { + if (bindingPosition.getPos() == 0) + bindingPosition.setPos(i + 1); + return structuredType.getExternalFQN(); + } else { + // The type of %1$s of action of method %2$s of class %1$s could not be converted + throw new ODataJPAModelException(ODataJPAModelException.MessageKeys.ACTION_PARAM_ONLY_PRIMITIVE, + jpaParameter.getInternalName(), javaAction.getName(), javaAction.getDeclaringClass().getName()); + } + } } @Override protected boolean hasImport() { + // 13.5 Element edm:ActionImport: + // The edm:ActionImport element allows exposing an unbound action as a top-level element in an entity container. + // Action imports are never advertised in the service document. return !jpaAction.isBound(); } @Override - protected void lazyBuildEdmItem() throws ODataJPAModelException { + protected synchronized void lazyBuildEdmItem() throws ODataJPAModelException { if (edmAction == null) { edmAction = new CsdlAction(); // edmAction.setAnnotations(annotations); @@ -157,7 +170,9 @@ protected void lazyBuildEdmItem() throws ODataJPAModelException { @Override CsdlAction getEdmItem() throws ODataJPAModelException { - lazyBuildEdmItem(); + if (edmAction == null) { + lazyBuildEdmItem(); + } return edmAction; } @@ -180,10 +195,12 @@ private CsdlReturnType determineEdmResultType(final ReturnType definedReturnType throw new ODataJPAModelException(MessageKeys.ACTION_RETURN_TYPE_EXP, javaOperation.getName(), javaOperation .getName()); edmResultType.setCollection(true); - edmResultType.setType(determineReturnType(definedReturnType, definedReturnType.type(), javaOperation)); + edmResultType.setType(IntermediateOperationHelper.determineReturnType(definedReturnType, definedReturnType.type(), + schema, javaOperation.getName())); } else { edmResultType.setCollection(false); - edmResultType.setType(determineReturnType(definedReturnType, declairedReturnType, javaOperation)); + edmResultType.setType(IntermediateOperationHelper.determineReturnType(definedReturnType, declairedReturnType, + schema, javaOperation.getName())); } edmResultType.setNullable(definedReturnType.isNullable()); edmResultType.setPrecision(nullIfNotSet(definedReturnType.precision())); @@ -197,21 +214,6 @@ private CsdlReturnType determineEdmResultType(final ReturnType definedReturnType return edmResultType; } - private FullQualifiedName determineReturnType(final ReturnType definedReturnType, final Class declairedReturnType, - final Method javaOperation) throws ODataJPAModelException { - - final IntermediateStructuredType structuredType = schema.getStructuredType(declairedReturnType); - if (structuredType != null) - return structuredType.getExternalFQN(); - else { - final EdmPrimitiveTypeKind edmType = JPATypeConvertor.convertToEdmSimpleType(declairedReturnType); - if (edmType == null) - throw new ODataJPAModelException(MessageKeys.FUNC_RETURN_TYPE_INVALID, definedReturnType.type().getName(), - declairedReturnType.getName(), javaOperation.getName()); - return edmType.getFullQualifiedName(); - } - } - private Integer nullIfNotSet(Integer number) { if (number != null && number > -1) return number; @@ -230,4 +232,17 @@ private String setEntitySetPath() throws ODataJPAModelException { javaAction.getName(), javaAction.getDeclaringClass().getName()); return jpaAction.entitySetPath(); } + + private static class BindingPosition { + private Integer pos = 0; + + Integer getPos() { + return pos; + } + + void setPos(Integer pos) { + this.pos = pos; + } + + } } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateJavaFunction.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateJavaFunction.java index 37d5d1291..fb2f88576 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateJavaFunction.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateJavaFunction.java @@ -17,6 +17,7 @@ import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmFunction.ReturnType; import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmFunctionType; import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmParameter; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEdmNameBuilder; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAJavaFunction; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAOperationResultParameter; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAParameter; @@ -28,12 +29,16 @@ class IntermediateJavaFunction extends IntermediateFunction implements JPAJavaFu private final Constructor javaConstructor; private List parameterList; - IntermediateJavaFunction(JPAEdmNameBuilder nameBuilder, EdmFunction jpaFunction, Method javaFunction, - IntermediateSchema schema) throws ODataJPAModelException { + IntermediateJavaFunction(final JPAEdmNameBuilder nameBuilder, final EdmFunction jpaFunction, + final Method javaFunction, final IntermediateSchema schema) throws ODataJPAModelException { + super(nameBuilder, jpaFunction, schema, IntNameBuilder.buildFunctionName(jpaFunction).isEmpty() ? javaFunction.getName() : IntNameBuilder .buildFunctionName(jpaFunction)); - this.setExternalName(nameBuilder.buildOperationName(internalName)); + + this.setExternalName(jpaFunction.name().isEmpty() + ? nameBuilder.buildOperationName(internalName) + : jpaFunction.name()); this.javaFunction = javaFunction; this.javaConstructor = IntermediateOperationHelper.determineConstructor(javaFunction); } @@ -56,7 +61,7 @@ public Method getMethod() { @Override public List getParameter() throws ODataJPAModelException { if (parameterList == null) { - parameterList = new ArrayList(); + parameterList = new ArrayList<>(); Class[] types = javaFunction.getParameterTypes(); Parameter[] declairedParameters = javaFunction.getParameters(); for (int i = 0; i < declairedParameters.length; i++) { @@ -71,7 +76,6 @@ public List getParameter() throws ODataJPAModelException { .buildPropertyName(definedParameter.name()), declairedParameter.getName(), types[i]); parameterList.add(parameter); } - } return parameterList; } @@ -79,7 +83,7 @@ public List getParameter() throws ODataJPAModelException { @Override public JPAParameter getParameter(String internalName) throws ODataJPAModelException { for (JPAParameter parameter : getParameter()) { - if (parameter.getInternalName() == internalName) + if (parameter.getInternalName().equals(internalName)) return parameter; } return null; @@ -98,19 +102,15 @@ public CsdlReturnType getReturnType() { @Override protected List determineEdmInputParameter() throws ODataJPAModelException { - List parameterList = new ArrayList(); + List parameters = new ArrayList<>(); for (Parameter declairedParameter : Arrays.asList(javaFunction.getParameters())) { CsdlParameter parameter = new CsdlParameter(); EdmParameter definedParameter = declairedParameter.getAnnotation(EdmParameter.class); parameter.setName(nameBuilder.buildPropertyName(definedParameter.name())); - EdmPrimitiveTypeKind edmType = JPATypeConvertor.convertToEdmSimpleType(declairedParameter.getType()); - if (edmType == null) - throw new ODataJPAModelException(ODataJPAModelException.MessageKeys.FUNC_PARAM_ONLY_PRIMITIVE, javaFunction - .getDeclaringClass().getName(), javaFunction.getName(), definedParameter.name()); - parameter.setType(edmType.getFullQualifiedName()); - parameterList.add(parameter); + parameter.setType(determineParameterType(declairedParameter.getType(), definedParameter)); + parameters.add(parameter); } - return parameterList; + return parameters; } // TODO handle multiple schemas @@ -124,7 +124,8 @@ protected CsdlReturnType determineEdmResultType(final ReturnType definedReturnTy // Type parameter expected for %1$s throw new ODataJPAModelException(MessageKeys.FUNC_RETURN_TYPE_EXP, javaFunction.getName()); edmResultType.setCollection(true); - edmResultType.setType(determineReturnType(definedReturnType, definedReturnType.type())); + edmResultType.setType(IntermediateOperationHelper.determineReturnType(definedReturnType, definedReturnType.type(), + schema, javaFunction.getName())); } else { if (definedReturnType.type() != Object.class && !definedReturnType.type().getCanonicalName().equals(declairedReturnType.getCanonicalName())) @@ -133,7 +134,8 @@ protected CsdlReturnType determineEdmResultType(final ReturnType definedReturnTy declairedReturnType.getName(), javaFunction.getName()); edmResultType.setCollection(false); - edmResultType.setType(determineReturnType(definedReturnType, declairedReturnType)); + edmResultType.setType(IntermediateOperationHelper.determineReturnType(definedReturnType, declairedReturnType, + schema, javaFunction.getName())); } edmResultType.setNullable(definedReturnType.isNullable()); @@ -163,18 +165,19 @@ boolean hasImport() { return true; } - private FullQualifiedName determineReturnType(final ReturnType definedReturnType, final Class declairedReturnType) - throws ODataJPAModelException { - - IntermediateStructuredType structuredType = schema.getStructuredType(declairedReturnType); - if (structuredType != null) - return structuredType.getExternalFQN(); - else { - final EdmPrimitiveTypeKind edmType = JPATypeConvertor.convertToEdmSimpleType(declairedReturnType); - if (edmType == null) - throw new ODataJPAModelException(MessageKeys.FUNC_RETURN_TYPE_INVALID, definedReturnType.type().getName(), - declairedReturnType.getName(), javaFunction.getName()); + @Override + protected FullQualifiedName determineParameterType(final Class type, + final EdmParameter definedParameter) throws ODataJPAModelException { + final EdmPrimitiveTypeKind edmType = JPATypeConvertor.convertToEdmSimpleType(type); + if (edmType != null) return edmType.getFullQualifiedName(); + else { + final IntermediateEnumerationType enumType = schema.getEnumerationType(type); + if (enumType != null) { + return enumType.getExternalFQN(); + } else + throw new ODataJPAModelException(ODataJPAModelException.MessageKeys.FUNC_PARAM_ONLY_PRIMITIVE, javaFunction + .getDeclaringClass().getName(), javaFunction.getName(), definedParameter.name()); } } } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateJoinColumn.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateJoinColumn.java index 204488a05..6788a0a1e 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateJoinColumn.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateJoinColumn.java @@ -2,18 +2,25 @@ import javax.persistence.JoinColumn; -final class IntermediateJoinColumn { - private final JoinColumn jpaJoinColumn; +import com.sap.olingo.jpa.metadata.api.JPAJoinColumn; + +final class IntermediateJoinColumn implements JPAJoinColumn { private String name; private String referencedColumnName; public IntermediateJoinColumn(final JoinColumn jpaJoinColumn) { super(); - this.jpaJoinColumn = jpaJoinColumn; this.name = jpaJoinColumn.name(); this.referencedColumnName = jpaJoinColumn.referencedColumnName(); } + public IntermediateJoinColumn(final String name, final String referencedColumnName) { + super(); + this.name = name; + this.referencedColumnName = referencedColumnName; + } + + @Override public String getName() { return name; } @@ -22,6 +29,7 @@ public void setName(final String name) { this.name = name; } + @Override public String getReferencedColumnName() { return referencedColumnName; } @@ -30,7 +38,4 @@ public void setReferencedColumnName(final String referencedColumnName) { this.referencedColumnName = referencedColumnName; } - public JoinColumn getJpaJoinColumn() { - return jpaJoinColumn; - } } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateJoinTable.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateJoinTable.java new file mode 100644 index 000000000..8ee93335b --- /dev/null +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateJoinTable.java @@ -0,0 +1,191 @@ +package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; + +import java.util.ArrayList; +import java.util.List; + +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; + +import com.sap.olingo.jpa.metadata.api.JPAJoinColumn; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEntityType; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAJoinTable; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAOnConditionItem; +import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; + +class IntermediateJoinTable implements JPAJoinTable { + private final IntermediateNavigationProperty intermediateProperty; + private final JoinTable jpaJoinTable; + private final IntermediateStructuredType sourceType; + private List joinColumns = null; + private List inverseJoinColumns = null; + private JPAEntityType jpaEntityType; + + IntermediateJoinTable(final IntermediateNavigationProperty intermediateProperty, final JoinTable jpaJoinTable, + final IntermediateSchema schema) { + super(); + this.intermediateProperty = intermediateProperty; + this.jpaJoinTable = jpaJoinTable; + this.sourceType = intermediateProperty.getSourceType(); + this.jpaEntityType = schema.getEntityType(jpaJoinTable.catalog(), jpaJoinTable.schema(), jpaJoinTable.name()); + } + + private IntermediateJoinTable(final IntermediateJoinTable intermediateJoinTable, + final IntermediateNavigationProperty mappedBy) throws ODataJPAModelException { + + this.jpaJoinTable = intermediateJoinTable.jpaJoinTable; + this.sourceType = intermediateJoinTable.getTargetType(); + this.jpaEntityType = intermediateJoinTable.jpaEntityType; + this.intermediateProperty = mappedBy; + this.joinColumns = intermediateJoinTable.buildInverseJoinColumns(); + this.inverseJoinColumns = intermediateJoinTable.buildJoinColumns(); + } + + @Override + public String getAlias(String dbFieldName) { + for (IntermediateJoinColumn column : joinColumns) { + if (column.getName().equals(dbFieldName)) + return column.getReferencedColumnName(); + } + return null; + } + + @Override + public JPAEntityType getEntityType() { + return jpaEntityType; + } + + @Override + public String getInverseAlias(String dbFieldName) { + try { + buildInverseJoinColumns(); + } catch (ODataJPAModelException e) { + throw new IllegalArgumentException(e); + } + for (IntermediateJoinColumn column : inverseJoinColumns) { + if (column.getName().equals(dbFieldName)) + return column.getReferencedColumnName(); + } + return null; + } + + @Override + public List getInversJoinColumns() throws ODataJPAModelException { + assert jpaEntityType != null; + buildInverseJoinColumns(); + final IntermediateStructuredType targetType = (IntermediateStructuredType) intermediateProperty.getTargetEntity(); + final List result = new ArrayList<>(); + for (IntermediateJoinColumn column : inverseJoinColumns) { + result.add(new JPAOnConditionItemImpl( + ((IntermediateEntityType) jpaEntityType).getPathByDBField(column.getReferencedColumnName()), + targetType.getPathByDBField(column.getName()))); + + } + return result; + } + + @Override + public List getJoinColumns() throws ODataJPAModelException { + assert jpaEntityType != null; + final List result = new ArrayList<>(); + for (IntermediateJoinColumn column : joinColumns) { + result.add(new JPAOnConditionItemImpl( + sourceType.getPathByDBField(column.getName()), + ((IntermediateEntityType) jpaEntityType).getPathByDBField(column.getReferencedColumnName()))); + } + return result; + } + + @SuppressWarnings("unchecked") + @Override + public List getRawInversJoinInformation() throws ODataJPAModelException { + buildInverseJoinColumns(); + // For criteria builder the columns get switched + final List invertedColumns = new ArrayList<>(inverseJoinColumns.size()); + for (final IntermediateJoinColumn column : inverseJoinColumns) { + invertedColumns.add((T) new IntermediateJoinColumn(column.getReferencedColumnName(), column.getName())); + } + return invertedColumns; + } + + @SuppressWarnings("unchecked") + @Override + public List getRawJoinInformation() { + return (List) joinColumns; + } + + /** + * Returns the name of database table + * @return + */ + @Override + public String getTableName() { + return buildFQTableName(jpaJoinTable.schema(), jpaJoinTable.name()); + } + + protected final String buildFQTableName(final String schema, final String table) { + final StringBuilder fqt = new StringBuilder(); + if (schema != null && !schema.isEmpty()) { + fqt.append(schema); + fqt.append("."); + } + fqt.append(table); + return fqt.toString(); + } + + IntermediateJoinTable asMapped(final IntermediateNavigationProperty mappedBy) throws ODataJPAModelException { + return new IntermediateJoinTable(this, mappedBy); + } + + List buildInverseJoinColumns() + throws ODataJPAModelException { + + if (inverseJoinColumns == null) { + inverseJoinColumns = new ArrayList<>(jpaJoinTable.inverseJoinColumns().length); + for (JoinColumn column : jpaJoinTable.inverseJoinColumns()) { + if (column.referencedColumnName() == null || column.referencedColumnName().isEmpty()) { + if (jpaJoinTable.joinColumns().length > 1) + throw new ODataJPAModelException(ODataJPAModelException.MessageKeys.NOT_SUPPORTED_NO_IMPLICIT_COLUMNS, + intermediateProperty.getInternalName()); + else + inverseJoinColumns.add(new IntermediateJoinColumn( + ((IntermediateProperty) ((IntermediateEntityType) getTargetType()).getKey().get(0)).getDBFieldName(), + column.name())); + } else { + inverseJoinColumns.add(new IntermediateJoinColumn(column.referencedColumnName(), column.name())); + } + } + } + return inverseJoinColumns; + } + + List buildJoinColumns() throws ODataJPAModelException { + if (joinColumns == null) { + joinColumns = new ArrayList<>(jpaJoinTable.inverseJoinColumns().length); + + for (JoinColumn column : jpaJoinTable.joinColumns()) { + if (column.referencedColumnName() == null || column.referencedColumnName().isEmpty()) { + if (jpaJoinTable.joinColumns().length > 1) + throw new ODataJPAModelException(ODataJPAModelException.MessageKeys.NOT_SUPPORTED_NO_IMPLICIT_COLUMNS, + intermediateProperty.getInternalName()); + else if (!(intermediateProperty.getSourceType() instanceof IntermediateEntityType)) + throw new ODataJPAModelException( + ODataJPAModelException.MessageKeys.NOT_SUPPORTED_NO_IMPLICIT_COLUMNS_COMPEX, + intermediateProperty.getInternalName()); + else { + joinColumns.add(new IntermediateJoinColumn( + ((IntermediateProperty) ((IntermediateEntityType) intermediateProperty.getSourceType()).getKey().get(0)) + .getDBFieldName(), column.name())); + } + } else { + joinColumns.add(new IntermediateJoinColumn(column.referencedColumnName(), column.name())); + } + } + } + return joinColumns; + } + + private IntermediateStructuredType getTargetType() throws ODataJPAModelException { + return (IntermediateStructuredType) intermediateProperty.getTargetEntity(); + } + +} \ No newline at end of file diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateModelElement.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateModelElement.java index 2fc964873..0bed63975 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateModelElement.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateModelElement.java @@ -3,8 +3,10 @@ import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Member; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import org.apache.olingo.commons.api.edm.FullQualifiedName; import org.apache.olingo.commons.api.edm.provider.CsdlAbstractEdmItem; @@ -15,6 +17,7 @@ import com.sap.olingo.jpa.metadata.api.JPAEdmMetadataPostProcessor; import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmAnnotation; import com.sap.olingo.jpa.metadata.core.edm.mapper.annotation.AppliesTo; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEdmNameBuilder; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediateModelItemAccess; @@ -24,7 +27,7 @@ abstract class IntermediateModelElement implements IntermediateModelItemAccess { protected static final JPANameBuilder IntNameBuilder = new JPANameBuilder(); protected final JPAEdmNameBuilder nameBuilder; protected final String internalName; - final protected List edmAnnotations; + protected final List edmAnnotations; private boolean toBeIgnored; private String externalName; @@ -36,7 +39,7 @@ public IntermediateModelElement(final JPAEdmNameBuilder nameBuilder, final Strin super(); this.nameBuilder = nameBuilder; this.internalName = internalName; - this.edmAnnotations = new ArrayList(); + this.edmAnnotations = new ArrayList<>(); } @Override @@ -46,7 +49,7 @@ public String getExternalName() { @Override public FullQualifiedName getExternalFQN() { - return nameBuilder.buildFQN(getExternalName()); + return buildFQN(getExternalName()); } @Override @@ -88,33 +91,38 @@ public void setIgnore(final boolean ignore) { protected abstract void lazyBuildEdmItem() throws ODataJPAModelException; @SuppressWarnings("unchecked") - protected List extractEdmModelElements(final Map mappingBuffer) throws ODataJPAModelException { - final List extractionTarget = new ArrayList(); - for (final String externalName : mappingBuffer.keySet()) { - if (!((IntermediateModelElement) mappingBuffer.get(externalName)).toBeIgnored) { - final IntermediateModelElement func = (IntermediateModelElement) mappingBuffer.get(externalName); - final CsdlAbstractEdmItem edmFunc = func.getEdmItem(); - if (!func.ignore()) - extractionTarget.add((T) edmFunc); + protected List extractEdmModelElements( + final Map mappingBuffer) + throws ODataJPAModelException { + final List extractionTarget = new ArrayList<>(); + + for (final Entry bufferItem : mappingBuffer.entrySet()) { + + if (!((IntermediateModelElement) bufferItem.getValue()).toBeIgnored) { // NOSONAR + final IntermediateModelElement element = bufferItem.getValue(); + final CsdlAbstractEdmItem edmItem = element.getEdmItem(); + if (!element.ignore()) + extractionTarget.add((T) edmItem); } } - return returnNullIfEmpty(extractionTarget); + return extractionTarget; } protected IntermediateModelElement findModelElementByEdmItem(final String edmEntityItemName, - final Map buffer) throws ODataJPAModelException { - for (final String internalName : buffer.keySet()) { - final IntermediateModelElement modelElement = (IntermediateModelElement) buffer.get(internalName); + final Map buffer) { + + for (final Entry bufferItem : buffer.entrySet()) { + final IntermediateModelElement modelElement = (IntermediateModelElement) bufferItem.getValue(); + if (edmEntityItemName.equals(modelElement.getExternalName())) { return modelElement; } } return null; - } protected List returnNullIfEmpty(final List list) { - return list == null || list.isEmpty() ? null : list; + return list == null ? Collections.emptyList() : list; } abstract CsdlAbstractEdmItem getEdmItem() throws ODataJPAModelException; @@ -129,28 +137,43 @@ protected List returnNullIfEmpty(final List list) { * @param property * @throws ODataJPAModelException */ - protected void getAnnotations(List edmAnnotations, Member member, String internalName, - AppliesTo property) throws ODataJPAModelException { + protected void getAnnotations(final List edmAnnotations, final Member member, + final String internalName, final AppliesTo property) throws ODataJPAModelException { if (member instanceof AnnotatedElement) { extractAnnotations(edmAnnotations, (AnnotatedElement) member, internalName); } } - protected void getAnnotations(List edmAnnotations, Class clazz, String internalName, - AppliesTo property) throws ODataJPAModelException { + protected void getAnnotations(List edmAnnotations, Class clazz, String internalName) + throws ODataJPAModelException { if (clazz instanceof AnnotatedElement) { extractAnnotations(edmAnnotations, clazz, internalName); } } + /** + * @param t + * @return + */ + protected final String buildFQTableName(final String schema, final String name) { + final StringBuilder fqt = new StringBuilder(); + if (schema != null && !schema.isEmpty()) { + fqt.append(schema); + fqt.append("."); + } + fqt.append(name); + return fqt.toString(); + } + private void extractAnnotations(List edmAnnotations, AnnotatedElement element, String internalName) throws ODataJPAModelException { final EdmAnnotation jpaAnnotation = element.getAnnotation(EdmAnnotation.class); if (jpaAnnotation != null) { - CsdlAnnotation edmAnnotation = new CsdlAnnotation(); + final CsdlAnnotation edmAnnotation = new CsdlAnnotation(); + final String qualifier = jpaAnnotation.qualifier(); edmAnnotation.setTerm(jpaAnnotation.term()); - edmAnnotation.setQualifier(jpaAnnotation.qualifier()); + edmAnnotation.setQualifier(qualifier.isEmpty() ? null : qualifier); if (!(jpaAnnotation.constantExpression().type() == ConstantExpressionType.Int && jpaAnnotation.constantExpression().value().equals("default")) && !(jpaAnnotation.dynamicExpression().path().isEmpty())) { @@ -170,25 +193,48 @@ private void extractAnnotations(List edmAnnotations, AnnotatedEl * * @return */ - protected Class boxPrimitive(Class javaType) { + protected Class boxPrimitive(Class javaType) {// NOSONAR - if (javaType.getName().equals("int")) + if (javaType == int.class || javaType == Integer.class) return Integer.class; - else if (javaType.getName().equals("long")) + else if (javaType == long.class || javaType == Long.class) return Long.class; - else if (javaType.getName().equals("boolean")) + else if (javaType == boolean.class || javaType == Boolean.class) return Boolean.class; - else if (javaType.getName().equals("byte")) + else if (javaType == byte.class || javaType == Byte.class) return Byte.class; - else if (javaType.getName().equals("char")) + else if (javaType == char.class || javaType == Character.class) return Character.class; - else if (javaType.getName().equals("float")) + else if (javaType == float.class || javaType == Float.class) return Float.class; - else if (javaType.getName().equals("short")) + else if (javaType == short.class || javaType == Short.class) return Short.class; - else if (javaType.getName().equals("double")) + else if (javaType == double.class || javaType == Double.class) return Double.class; return null; } + + /** + * + * @param name + * @return + */ + protected final FullQualifiedName buildFQN(final String name) { + return new FullQualifiedName(nameBuilder.getNamespace(), name); + } + + @Override + public String toString() { + return "IntermediateModelElement [internalName=" + internalName + ", externalName=" + + externalName + ", toBeIgnored=" + toBeIgnored + "]"; + } + + /** + * @param value + * @return true if string value is null or empty + */ + protected final boolean emptyString(final String value) { + return value == null || value.isEmpty(); + } } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateNavigationProperty.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateNavigationProperty.java index 022b05897..2c77c0c07 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateNavigationProperty.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateNavigationProperty.java @@ -1,14 +1,19 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Constructor; import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; import javax.persistence.AssociationOverride; import javax.persistence.AttributeConverter; import javax.persistence.CascadeType; import javax.persistence.JoinColumn; import javax.persistence.JoinColumns; +import javax.persistence.ManyToMany; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import javax.persistence.OneToOne; @@ -24,10 +29,17 @@ import org.apache.olingo.commons.api.edm.provider.CsdlReferentialConstraint; import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmIgnore; +import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmProtectedBy; +import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmTransientPropertyCalculator; +import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmVisibleFor; import com.sap.olingo.jpa.metadata.core.edm.mapper.annotation.AppliesTo; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAAssociationAttribute; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAAssociationPath; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEdmNameBuilder; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAJoinTable; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAStructuredType; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; +import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException.MessageKeys; import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediateNavigationPropertyAccess; /** @@ -49,8 +61,9 @@ final class IntermediateNavigationProperty extends IntermediateModelElement impl private final IntermediateStructuredType sourceType; private IntermediateStructuredType targetType; private JPAAssociationAttribute partner; + private IntermediateJoinTable joinTable; private final IntermediateSchema schema; - private final List joinColumns = new ArrayList(); + private final List joinColumns = new ArrayList<>(); IntermediateNavigationProperty(final JPAEdmNameBuilder nameBuilder, final IntermediateStructuredType parent, final Attribute jpaAttribute, final IntermediateSchema schema) throws ODataJPAModelException { @@ -68,7 +81,7 @@ public void addAnnotations(List annotations) { } @Override - public AttributeConverter getConverter() { + public AttributeConverter getConverter() { return null; } @@ -77,19 +90,48 @@ public EdmPrimitiveTypeKind getEdmType() { return null; } + public JPAJoinTable getJoinTable() { + return joinTable; + } + + @Override + public JPAAssociationAttribute getPartner() { + return partner; + } + + @Override + public JPAAssociationPath getPath() throws ODataJPAModelException { + return getStructuredType().getAssociationPath(getExternalName()); + } + @Override public CsdlNavigationProperty getProperty() throws ODataJPAModelException { return getEdmItem(); } @Override - public JPAStructuredType getStructuredType() { - return null; + public Set getProtectionClaimNames() { + return new HashSet<>(0); + } + + @Override + public List getProtectionPath(String claimName) throws ODataJPAModelException { + return new ArrayList<>(0); + } + + @Override + public JPAStructuredType getStructuredType() throws ODataJPAModelException { + if (edmNaviProperty == null) { + lazyBuildEdmItem(); + } + return sourceType; } @Override public JPAStructuredType getTargetEntity() throws ODataJPAModelException { - lazyBuildEdmItem(); + if (edmNaviProperty == null) { + lazyBuildEdmItem(); + } return targetType; } @@ -98,6 +140,11 @@ public Class getType() { return jpaAttribute.getJavaType(); } + @Override + public boolean hasProtection() { + return false; + } + @Override public boolean isAssociation() { return true; @@ -108,11 +155,31 @@ public boolean isCollection() { return jpaAttribute.isCollection(); } + @Override + public boolean isTransient() { + return false; + } + + @Override + public > Constructor getCalculatorConstructor() { + return null; + } + @Override public boolean isComplex() { return false; } + @Override + public boolean isEnum() { + return false; + } + + @Override + public boolean isEtag() { + return false; + } + @Override public boolean isKey() { return false; @@ -129,141 +196,163 @@ public void setOnDelete(final CsdlOnDelete onDelete) { } @Override - protected void lazyBuildEdmItem() throws ODataJPAModelException { + protected synchronized void lazyBuildEdmItem() throws ODataJPAModelException { if (edmNaviProperty == null) { String mappedBy = null; boolean isSourceOne = false; edmNaviProperty = new CsdlNavigationProperty(); edmNaviProperty.setName(getExternalName()); - edmNaviProperty.setType(nameBuilder.buildFQN(targetType.getExternalName())); + edmNaviProperty.setType(buildFQN(targetType.getExternalName())); edmNaviProperty.setCollection(jpaAttribute.isCollection()); // Optional --> ReleationAnnotation if (jpaAttribute.getJavaMember() instanceof AnnotatedElement) { final AnnotatedElement annotatedElement = (AnnotatedElement) jpaAttribute.getJavaMember(); switch (jpaAttribute.getPersistentAttributeType()) { - case ONE_TO_MANY: - final OneToMany cardinalityOtM = annotatedElement.getAnnotation(OneToMany.class); - mappedBy = cardinalityOtM.mappedBy(); - isSourceOne = true; - edmNaviProperty.setOnDelete(edmOnDelete != null ? edmOnDelete : setJPAOnDelete(cardinalityOtM.cascade())); - break; - case ONE_TO_ONE: - final OneToOne cardinalityOtO = annotatedElement.getAnnotation(OneToOne.class); - edmNaviProperty.setNullable(cardinalityOtO.optional()); - mappedBy = cardinalityOtO.mappedBy(); - isSourceOne = true; - edmNaviProperty.setOnDelete(edmOnDelete != null ? edmOnDelete : setJPAOnDelete(cardinalityOtO.cascade())); - break; - case MANY_TO_ONE: - final ManyToOne cardinalityMtO = annotatedElement.getAnnotation(ManyToOne.class); - edmNaviProperty.setNullable(cardinalityMtO.optional()); - edmNaviProperty.setOnDelete(edmOnDelete != null ? edmOnDelete : setJPAOnDelete(cardinalityMtO.cascade())); - break; - default: - break; - } - - int implicitColumns = 0; - final JoinColumns columns = annotatedElement.getAnnotation(JoinColumns.class); - if (columns != null) { - for (final JoinColumn column : columns.value()) { - final IntermediateJoinColumn intermediateColumn = new IntermediateJoinColumn(column); - final String refColumnName = intermediateColumn.getReferencedColumnName(); - final String name = intermediateColumn.getName(); - if (refColumnName == null || refColumnName.isEmpty() || name == null || name.isEmpty()) { - implicitColumns += 1; - if (implicitColumns > 1) - throw new ODataJPAModelException(ODataJPAModelException.MessageKeys.NOT_SUPPORTED_NO_IMPLICIT_COLUMNS, - getInternalName()); - fillMissingName(isSourceOne, intermediateColumn); - } - joinColumns.add(intermediateColumn); - } + case ONE_TO_MANY: + final OneToMany cardinalityOtM = annotatedElement.getAnnotation(OneToMany.class); + mappedBy = cardinalityOtM.mappedBy(); + isSourceOne = true; + edmNaviProperty.setOnDelete(edmOnDelete != null ? edmOnDelete : setJPAOnDelete(cardinalityOtM.cascade())); + break; + case ONE_TO_ONE: + final OneToOne cardinalityOtO = annotatedElement.getAnnotation(OneToOne.class); + edmNaviProperty.setNullable(cardinalityOtO.optional()); + mappedBy = cardinalityOtO.mappedBy(); + isSourceOne = true; + edmNaviProperty.setOnDelete(edmOnDelete != null ? edmOnDelete : setJPAOnDelete(cardinalityOtO.cascade())); + break; + case MANY_TO_ONE: + final ManyToOne cardinalityMtO = annotatedElement.getAnnotation(ManyToOne.class); + edmNaviProperty.setNullable(cardinalityMtO.optional()); + edmNaviProperty.setOnDelete(edmOnDelete != null ? edmOnDelete : setJPAOnDelete(cardinalityMtO.cascade())); + break; + case MANY_TO_MANY: + final ManyToMany cardinalityMtM = annotatedElement.getAnnotation(ManyToMany.class); + mappedBy = cardinalityMtM.mappedBy(); + edmNaviProperty.setOnDelete(edmOnDelete != null ? edmOnDelete : setJPAOnDelete(cardinalityMtM.cascade())); + break; + default: + break; } - else { - final JoinColumn column = annotatedElement.getAnnotation(JoinColumn.class); - if (column != null) { - final IntermediateJoinColumn intermediateColumn = new IntermediateJoinColumn(column); - fillMissingName(isSourceOne, intermediateColumn); - joinColumns.add(intermediateColumn); - - } else if (mappedBy != null && !mappedBy.isEmpty()) { - joinColumns.addAll(targetType.getJoinColumns(sourceType, mappedBy)); - for (final IntermediateJoinColumn intermediateColumn : joinColumns) { - final String refColumnName = intermediateColumn.getReferencedColumnName(); - if (refColumnName == null || refColumnName.isEmpty()) { - implicitColumns += 1; - if (implicitColumns > 1) - throw new ODataJPAModelException(ODataJPAModelException.MessageKeys.NOT_SUPPORTED_NO_IMPLICIT_COLUMNS, - getInternalName()); - intermediateColumn.setReferencedColumnName(((IntermediateProperty) ((IntermediateEntityType) sourceType) - .getKey().get(0)).getDBFieldName()); - } - } - } - } // Determine referential constraint + buildJoinColumns(mappedBy, isSourceOne, annotatedElement); determienReferentialConstraints(annotatedElement); } - // TODO determine ContainsTarget - - if (sourceType instanceof IntermediateEntityType) { - // Partner Attribute must not be defined at Complex Types. - // JPA bi-directional associations are defined at both sides, e.g. - // at the BusinessPartner and at the Roles. JPA only defines the - // "mappedBy" at the Parent. - if (mappedBy != null && !mappedBy.isEmpty()) { - partner = targetType.getAssociation(mappedBy); - edmNaviProperty.setPartner(partner.getExternalName()); - } else { - partner = targetType.getCorrespondingAssiciation(sourceType, getInternalName()); - if (partner != null) { - if (((IntermediateNavigationProperty) partner).isMapped()) - edmNaviProperty.setPartner(partner.getExternalName()); - } - } - } - + determinePartner(mappedBy); } } @Override CsdlNavigationProperty getEdmItem() throws ODataJPAModelException { - lazyBuildEdmItem(); + if (edmNaviProperty == null) { + lazyBuildEdmItem(); + } return edmNaviProperty; } - PersistentAttributeType getJoinCardinality() throws ODataJPAModelException { + PersistentAttributeType getJoinCardinality() { return jpaAttribute.getPersistentAttributeType(); } List getJoinColumns() throws ODataJPAModelException { - lazyBuildEdmItem(); + if (edmNaviProperty == null) { + lazyBuildEdmItem(); + } return joinColumns; } - @Override - public JPAAssociationAttribute getPartner() { - return partner; + IntermediateStructuredType getSourceType() { + return sourceType; } boolean isMapped() { if (jpaAttribute.getPersistentAttributeType() == PersistentAttributeType.ONE_TO_ONE) { final AnnotatedElement annotatedElement = (AnnotatedElement) jpaAttribute.getJavaMember(); final OneToOne cardinalityOtO = annotatedElement.getAnnotation(OneToOne.class); - return cardinalityOtO.mappedBy() != null && !cardinalityOtO.mappedBy().isEmpty() ? true : false; + return cardinalityOtO.mappedBy() != null && !cardinalityOtO.mappedBy().isEmpty(); } if (jpaAttribute.getPersistentAttributeType() == PersistentAttributeType.ONE_TO_MANY) { final AnnotatedElement annotatedElement = (AnnotatedElement) jpaAttribute.getJavaMember(); final OneToMany cardinalityOtM = annotatedElement.getAnnotation(OneToMany.class); - return cardinalityOtM.mappedBy() != null && !cardinalityOtM.mappedBy().isEmpty() ? true : false; + return cardinalityOtM.mappedBy() != null && !cardinalityOtM.mappedBy().isEmpty(); } return false; } + private void buildJoinColumns(final String mappedBy, final boolean isSourceOne, + final AnnotatedElement annotatedElement) throws ODataJPAModelException { + + if (mappedBy != null && !mappedBy.isEmpty()) { + // Get + joinTable = ((IntermediateJoinTable) ((IntermediateNavigationProperty) targetType.getAssociation( + mappedBy)).getJoinTable()); + // + joinColumns.addAll(joinTable == null ? buildJoinColumnsMapped(mappedBy) : joinTable + .buildInverseJoinColumns()); + // + joinTable = joinTable == null ? null : joinTable.asMapped(this); + } else { + joinColumns.addAll(joinTable == null ? buildJoinColumnsFromAnnotations(isSourceOne, annotatedElement) : joinTable + .buildJoinColumns()); + } + } + + private List buildJoinColumnsFromAnnotations(final boolean isSourceOne, + final AnnotatedElement annotatedElement) throws ODataJPAModelException { + + int implicitColumns = 0; + final List result = new ArrayList<>(); + final JoinColumn[] columns = annotatedElement.getAnnotation(JoinColumns.class) != null ? annotatedElement + .getAnnotation(JoinColumns.class).value() : null; + + if (columns != null) { + for (final JoinColumn column : columns) { + final IntermediateJoinColumn intermediateColumn = new IntermediateJoinColumn(column); + final String refColumnName = intermediateColumn.getReferencedColumnName(); + final String name = intermediateColumn.getName(); + if (refColumnName == null || refColumnName.isEmpty() || name == null || name.isEmpty()) { + implicitColumns += 1; + if (implicitColumns > 1) + throw new ODataJPAModelException(ODataJPAModelException.MessageKeys.NOT_SUPPORTED_NO_IMPLICIT_COLUMNS, + getInternalName()); + fillMissingName(isSourceOne, intermediateColumn); + } + result.add(intermediateColumn); + } + } else { + final JoinColumn column = annotatedElement.getAnnotation(JoinColumn.class); + if (column != null) { + final IntermediateJoinColumn intermediateColumn = new IntermediateJoinColumn(column); + fillMissingName(isSourceOne, intermediateColumn); + result.add(intermediateColumn); + + } + } + return result; + } + + private List buildJoinColumnsMapped(final String mappedBy) throws ODataJPAModelException { + + int implicitColumns = 0; + final List result = new ArrayList<>(); + result.addAll(targetType.getJoinColumns(mappedBy)); + for (final IntermediateJoinColumn intermediateColumn : result) { + final String refColumnName = intermediateColumn.getReferencedColumnName(); + if (refColumnName == null || refColumnName.isEmpty()) { + implicitColumns += 1; + if (implicitColumns > 1) + throw new ODataJPAModelException(ODataJPAModelException.MessageKeys.NOT_SUPPORTED_NO_IMPLICIT_COLUMNS, + getInternalName()); + intermediateColumn.setReferencedColumnName(((IntermediateProperty) ((IntermediateEntityType) sourceType) + .getKey().get(0)).getDBFieldName()); + } + } + return result; + } + private void buildNaviProperty() throws ODataJPAModelException { this.setExternalName(nameBuilder.buildNaviPropertyName(jpaAttribute)); Class targetClass = null; @@ -278,6 +367,9 @@ private void buildNaviProperty() throws ODataJPAModelException { if (jpaIgnore != null) { this.setIgnore(true); } + final javax.persistence.JoinTable jpaJoinTable = ((AnnotatedElement) this.jpaAttribute.getJavaMember()) + .getAnnotation(javax.persistence.JoinTable.class); + joinTable = jpaJoinTable != null ? new IntermediateJoinTable(this, jpaJoinTable, schema) : null; } targetType = schema.getEntityType(targetClass); @@ -286,14 +378,32 @@ private void buildNaviProperty() throws ODataJPAModelException { jpaAttribute.getName(), sourceType.internalName); postProcessor.processNavigationProperty(this, jpaAttribute.getDeclaringType().getJavaType() .getCanonicalName()); - // Process annotations after post processing, as external name it could have been changed + // Process annotations after post processing, as external name could have been changed getAnnotations(edmAnnotations, this.jpaAttribute.getJavaMember(), internalName, AppliesTo.NAVIGATION_PROPERTY); + checkConsistancy(); + } + + private void checkConsistancy() throws ODataJPAModelException { + final EdmProtectedBy jpaProtectedBy = ((AnnotatedElement) this.jpaAttribute.getJavaMember()) + .getAnnotation(EdmProtectedBy.class); + if (jpaProtectedBy != null) { + // Navigation Properties do not support EdmProtectedBy + throw new ODataJPAModelException(MessageKeys.NOT_SUPPORTED_PROTECTED_NAVIGATION, this.sourceType.getTypeClass() + .getCanonicalName(), this.internalName); + } + final EdmVisibleFor jpaFieldGroups = ((AnnotatedElement) this.jpaAttribute.getJavaMember()) + .getAnnotation(EdmVisibleFor.class); + if (jpaFieldGroups != null) { + throw new ODataJPAModelException(MessageKeys.NOT_SUPPORTED_NAVIGATION_PART_OF_GROUP, + this.sourceType.getTypeClass().getCanonicalName(), this.internalName); + } } private void determienReferentialConstraints(final AnnotatedElement annotatedElement) throws ODataJPAModelException { final AssociationOverride overwrite = annotatedElement.getAnnotation(AssociationOverride.class); - if (overwrite != null) return; + if (overwrite != null || joinTable != null) + return; final List constraints = edmNaviProperty.getReferentialConstraints(); for (final IntermediateJoinColumn intermediateColumn : joinColumns) { @@ -321,9 +431,29 @@ private void determienReferentialConstraints(final AnnotatedElement annotatedEle throw new ODataJPAModelException(ODataJPAModelException.MessageKeys.REFERENCED_PROPERTY_NOT_FOUND, getInternalName(), intermediateColumn.getName(), targetType.getExternalName()); - } else + } else { throw new ODataJPAModelException(ODataJPAModelException.MessageKeys.REFERENCED_PROPERTY_NOT_FOUND, getInternalName(), intermediateColumn.getReferencedColumnName(), sourceType.getExternalName()); + } + } + } + } + + private void determinePartner(String mappedBy) throws ODataJPAModelException { + if (sourceType instanceof IntermediateEntityType) { + // Partner Attribute must not be defined at Complex Types. + // JPA bi-directional associations are defined at both sides, e.g. + // at the BusinessPartner and at the Roles. JPA only defines the + // "mappedBy" at the Parent. + if (mappedBy != null && !mappedBy.isEmpty()) { + partner = targetType.getAssociation(mappedBy); + edmNaviProperty.setPartner(partner.getExternalName()); + } else { + partner = targetType.getCorrespondingAssiciation(sourceType, getInternalName()); + if (partner != null + && ((IntermediateNavigationProperty) partner).isMapped()) { + edmNaviProperty.setPartner(partner.getExternalName()); + } } } } @@ -335,16 +465,16 @@ private void fillMissingName(final boolean isSourceOne, final IntermediateJoinCo final String name = intermediateColumn.getName(); if (isSourceOne && (refColumnName == null || refColumnName.isEmpty())) - intermediateColumn.setReferencedColumnName(((IntermediateProperty) ((IntermediateEntityType) sourceType) + intermediateColumn.setReferencedColumnName(((IntermediateSimpleProperty) ((IntermediateEntityType) sourceType) .getKey().get(0)).getDBFieldName()); else if (isSourceOne && (name == null || name.isEmpty())) - intermediateColumn.setReferencedColumnName(((IntermediateProperty) ((IntermediateEntityType) targetType) + intermediateColumn.setReferencedColumnName(((IntermediateSimpleProperty) ((IntermediateEntityType) targetType) .getKey().get(0)).getDBFieldName()); else if (!isSourceOne && (refColumnName == null || refColumnName.isEmpty())) - intermediateColumn.setReferencedColumnName(((IntermediateProperty) ((IntermediateEntityType) targetType) + intermediateColumn.setReferencedColumnName(((IntermediateSimpleProperty) ((IntermediateEntityType) targetType) .getKey().get(0)).getDBFieldName()); else if (!isSourceOne && (name == null || name.isEmpty())) - intermediateColumn.setReferencedColumnName(((IntermediateProperty) ((IntermediateEntityType) sourceType) + intermediateColumn.setReferencedColumnName(((IntermediateSimpleProperty) ((IntermediateEntityType) sourceType) .getKey().get(0)).getDBFieldName()); } @@ -358,4 +488,9 @@ private CsdlOnDelete setJPAOnDelete(final CascadeType[] cascades) { } return null; } + + @Override + public List getRequiredProperties() { + return Collections.emptyList(); + } } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateOperation.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateOperation.java index dd3c8975a..f11500b3f 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateOperation.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateOperation.java @@ -1,5 +1,6 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEdmNameBuilder; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; abstract class IntermediateOperation extends IntermediateModelElement { diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateOperationFactory.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateOperationFactory.java index 8ddef37a0..7da4d50c5 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateOperationFactory.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateOperationFactory.java @@ -9,6 +9,7 @@ import org.reflections.Reflections; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEdmNameBuilder; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.ODataOperation; @@ -26,7 +27,7 @@ abstract IntermediateOperation createOperation(final JPAEdmNameBuilder nameBuild final Class annotation) throws ODataJPAModelException { - final Map funcList = new HashMap(); + final Map funcList = new HashMap<>(); if (reflections != null) { @SuppressWarnings("unchecked") final Set> operationClasses = diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateOperationHelper.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateOperationHelper.java index 160c471df..01a1acba5 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateOperationHelper.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateOperationHelper.java @@ -3,12 +3,19 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Parameter; +import java.sql.Blob; +import java.sql.Clob; import java.util.Arrays; import java.util.Collection; import javax.persistence.EntityManager; +import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind; +import org.apache.olingo.commons.api.edm.FullQualifiedName; + +import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmFunction.ReturnType; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; +import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException.MessageKeys; public class IntermediateOperationHelper { @@ -16,7 +23,7 @@ private IntermediateOperationHelper() { // Must not create instances } - static Constructor determineConstructor(Method javaFunction) throws ODataJPAModelException { + static Constructor determineConstructor(final Method javaFunction) throws ODataJPAModelException { Constructor result = null; Constructor[] constructors = javaFunction.getDeclaringClass().getConstructors(); for (Constructor constructor : Arrays.asList(constructors)) { @@ -41,4 +48,28 @@ static boolean isCollection(Class declairedReturnType) { } return false; } + + static FullQualifiedName determineReturnType(final ReturnType definedReturnType, final Class declairedReturnType, + final IntermediateSchema schema, final String operationName) throws ODataJPAModelException { + + IntermediateStructuredType structuredType = schema.getStructuredType(declairedReturnType); + if (structuredType != null) + return structuredType.getExternalFQN(); + else { + final IntermediateEnumerationType enumType = schema.getEnumerationType(declairedReturnType); + if (enumType != null) { + return enumType.getExternalFQN(); + } else if (declairedReturnType.equals(Blob.class) || declairedReturnType.equals(Clob.class)) { + // The return type '%1$s' used at method '%3$s' is not supported + throw new ODataJPAModelException(MessageKeys.FUNC_RETURN_NOT_SUPPORTED, declairedReturnType.getName(), + operationName); + } else { + final EdmPrimitiveTypeKind edmType = JPATypeConvertor.convertToEdmSimpleType(declairedReturnType); + if (edmType == null) + throw new ODataJPAModelException(MessageKeys.FUNC_RETURN_TYPE_INVALID, definedReturnType.type().getName(), + declairedReturnType.getName(), operationName); + return edmType.getFullQualifiedName(); + } + } + } } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateOperationParameter.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateOperationParameter.java index a93da6bdb..208c47ab9 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateOperationParameter.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateOperationParameter.java @@ -5,6 +5,7 @@ import org.apache.olingo.commons.api.edm.provider.CsdlAbstractEdmItem; import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmParameter; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEdmNameBuilder; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAParameter; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; @@ -13,13 +14,6 @@ class IntermediateOperationParameter extends IntermediateModelElement implements private final String externalName; private final Class type; - IntermediateOperationParameter(final JPAEdmNameBuilder nameBuilder, final EdmParameter jpaParameter) { - super(nameBuilder, jpaParameter.parameterName()); - this.jpaParameter = jpaParameter; - this.externalName = jpaParameter.name(); - this.type = jpaParameter.type(); - } - IntermediateOperationParameter(final JPAEdmNameBuilder nameBuilder, final EdmParameter jpaParameter, final String externalName, final String internalName, final Class type) { super(nameBuilder, internalName); @@ -64,7 +58,9 @@ public FullQualifiedName getTypeFQN() throws ODataJPAModelException { } @Override - protected void lazyBuildEdmItem() throws ODataJPAModelException {} + protected void lazyBuildEdmItem() throws ODataJPAModelException { + // No build needed, as IntermediateOperationParameter is a facade for EdmParameter annotation + } @Override CsdlAbstractEdmItem getEdmItem() throws ODataJPAModelException { @@ -77,7 +73,8 @@ public SRID getSrid() { final SRID srid = SRID.valueOf(jpaParameter.srid().srid()); srid.setDimension(jpaParameter.srid().dimension()); return srid; - } else + } else { return null; + } } } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateProperty.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateProperty.java index d1a82f535..2a8c327a2 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateProperty.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateProperty.java @@ -1,23 +1,35 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; +import static com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException.MessageKeys.COMPLEX_PROPERTY_MISSING_PROTECTION_PATH; +import static com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException.MessageKeys.TRANSIENT_CALCULATOR_TOO_MANY_CONSTRUCTORS; +import static com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException.MessageKeys.TRANSIENT_KEY_NOT_SUPPORTED; + import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Parameter; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; import javax.persistence.AttributeConverter; import javax.persistence.Column; import javax.persistence.Convert; +import javax.persistence.EntityManager; import javax.persistence.Lob; -import javax.persistence.Version; import javax.persistence.metamodel.Attribute; import javax.persistence.metamodel.Attribute.PersistentAttributeType; -import javax.persistence.metamodel.SingularAttribute; +import javax.persistence.metamodel.ManagedType; +import javax.persistence.metamodel.Type.PersistenceType; import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind; +import org.apache.olingo.commons.api.edm.FullQualifiedName; import org.apache.olingo.commons.api.edm.geo.SRID; import org.apache.olingo.commons.api.edm.provider.CsdlAnnotation; import org.apache.olingo.commons.api.edm.provider.CsdlMapping; @@ -25,56 +37,110 @@ import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmGeospatial; import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmIgnore; -import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmMediaStream; +import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmProtectedBy; +import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmProtections; import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmSearchable; +import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmTransient; +import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmTransientPropertyCalculator; +import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmVisibleFor; import com.sap.olingo.jpa.metadata.core.edm.mapper.annotation.AppliesTo; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAAttribute; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEdmNameBuilder; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAPath; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAStructuredType; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; +import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException.MessageKeys; import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediatePropertyAccess; /** - * A Property is described on the one hand by its Name and Type and on the other - * hand by its Property Facets. The type is a qualified name of either a - * primitive type, a complex type or a enumeration type. Primitive types are - * mapped by {@link JPATypeConvertor}. - * - *

- * For details about Property metadata see: OData Version 4.0 Part 3 - 6 Structural Property - * - * + * Properties can be classified by two different aspects: + *

    + *
  1. If they are complex, so are structured, or primitive
  2. + *
  3. If they are a collection of instances or if they are simple and can have up to one instance
  4. + *
+ * So properties maybe e.g. a complex collection property or a simple primitive property * @author Oliver Grande * */ -class IntermediateProperty extends IntermediateModelElement implements IntermediatePropertyAccess, JPAAttribute { - private static final String DB_FIELD_NAME_PATTERN = "\"&1\""; +abstract class IntermediateProperty extends IntermediateModelElement implements IntermediatePropertyAccess, + JPAAttribute { + private static final String DB_FIELD_NAME_PATTERN = "\"&1\""; protected final Attribute jpaAttribute; protected final IntermediateSchema schema; protected CsdlProperty edmProperty; - private IntermediateStructuredType type; - private AttributeConverter valueConverter; - private String dbFieldName; - private boolean searchable; - private boolean isVersion; - private EdmMediaStream streamInfo; - private Class dbType; - private Class entityType; - - IntermediateProperty(final JPAEdmNameBuilder nameBuilder, final Attribute jpaAttribute, + protected IntermediateStructuredType type; + protected AttributeConverter valueConverter; + protected String dbFieldName; + protected Class dbType; + protected Class entityType; + protected final ManagedType managedType; + protected boolean isVersion; + protected boolean searchable; + private final Map externalProtectedPathNames; + private List fieldGroups; + protected List requiredAttributes; + private Constructor> transientCalculatorConstructor; + + public IntermediateProperty(final JPAEdmNameBuilder nameBuilder, final Attribute jpaAttribute, final IntermediateSchema schema) throws ODataJPAModelException { - super(nameBuilder, IntNameBuilder.buildAttributeName(jpaAttribute)); this.jpaAttribute = jpaAttribute; this.schema = schema; + this.managedType = jpaAttribute.getDeclaringType(); + this.externalProtectedPathNames = new HashMap<>(1); buildProperty(nameBuilder); } @Override - public AttributeConverter getConverter() { - return valueConverter; + public void addAnnotations(List annotations) { + edmAnnotations.addAll(annotations); + } + + @SuppressWarnings("unchecked") + @Override + public > Constructor getCalculatorConstructor() + throws ODataJPAModelException { + if (this.edmProperty == null) { + lazyBuildEdmItem(); + } + return (Constructor) transientCalculatorConstructor; + } + + @SuppressWarnings("unchecked") + @Override + public AttributeConverter getConverter() { + return (AttributeConverter) valueConverter; + } + + @Override + public EdmPrimitiveTypeKind getEdmType() throws ODataJPAModelException { + return JPATypeConvertor.convertToEdmSimpleType(entityType); + } + + @Override + public CsdlProperty getProperty() throws ODataJPAModelException { + return getEdmItem(); + } + + @Override + public Set getProtectionClaimNames() { + return externalProtectedPathNames.keySet(); + } + + @Override + public List getProtectionPath(final String claimName) throws ODataJPAModelException { + if (externalProtectedPathNames.containsKey(claimName)) + return externalProtectedPathNames.get(claimName).getPath(); + return new ArrayList<>(0); + } + + /** + * @return + */ + @Override + public List getRequiredProperties() { + return requiredAttributes; } @Override @@ -91,93 +157,100 @@ public Class getType() { } @Override - public boolean isComplex() { - return jpaAttribute.getPersistentAttributeType() == PersistentAttributeType.EMBEDDED ? true : false; + public boolean hasProtection() { + return !externalProtectedPathNames.isEmpty(); + } + + @Override + public boolean isEnum() { + return schema.getEnumerationType(entityType) != null; + } + + @Override + public boolean isEtag() { + return isVersion; } @Override - public boolean isKey() { - if (jpaAttribute instanceof SingularAttribute) - return ((SingularAttribute) jpaAttribute).isId(); + public boolean isSearchable() { + return searchable; + } + + @Override + public boolean isTransient() { + return requiredAttributes != null; + } + + protected void buildProperty(final JPAEdmNameBuilder nameBuilder) throws ODataJPAModelException { + // Set element specific attributes of super type + this.setExternalName(nameBuilder.buildPropertyName(internalName)); + entityType = dbType = determineEntityType(); + + if (this.jpaAttribute.getJavaMember() instanceof AnnotatedElement) { + determineIgnore(); + determineStructuredType(); + determineInternalTypesFromConverter(); + determineDBFieldName(); + determineTransient(); + determineSearchable(); + determineStreamInfo(); + determineIsVersion(); + determineProtection(); + determineFieldGroups(); + checkConsistancy(); + } + postProcessor.processProperty(this, jpaAttribute.getDeclaringType().getJavaType().getCanonicalName()); + // Process annotations after post processing, as external name it could + // have been changed + getAnnotations(edmAnnotations, this.jpaAttribute.getJavaMember(), internalName, AppliesTo.PROPERTY); + } + + protected FullQualifiedName determineTypeByPersistanceType(Enum persistanceType) throws ODataJPAModelException { + if (persistanceType == PersistentAttributeType.BASIC || persistanceType == PersistenceType.BASIC) { + final IntermediateModelElement odataType = getODataPrimitiveType(); + if (odataType == null) + return getSimpleType(); + else + return odataType.getExternalFQN(); + } + if (persistanceType == PersistentAttributeType.EMBEDDED || persistanceType == PersistenceType.EMBEDDABLE) + return buildFQN(type.getExternalName()); else - return false; + return EdmPrimitiveTypeKind.Boolean.getFullQualifiedName(); } - boolean isStream() { - return streamInfo == null ? false : streamInfo.stream(); + protected String getDBFieldName() { + return dbFieldName; + } + + @Override + protected CsdlProperty getEdmItem() throws ODataJPAModelException { + if (this.edmProperty == null) { + lazyBuildEdmItem(); + } + return edmProperty; } @Override - protected void lazyBuildEdmItem() throws ODataJPAModelException { + protected synchronized void lazyBuildEdmItem() throws ODataJPAModelException { if (edmProperty == null) { edmProperty = new CsdlProperty(); edmProperty.setName(this.getExternalName()); - + edmProperty.setType(determineType()); + setFacet(); edmProperty.setMapping(createMapper()); - - if (jpaAttribute.getPersistentAttributeType() == PersistentAttributeType.BASIC) - if (valueConverter != null) { - edmProperty.setType(JPATypeConvertor.convertToEdmSimpleType(dbType, jpaAttribute) - .getFullQualifiedName()); - } else - edmProperty.setType(JPATypeConvertor.convertToEdmSimpleType(entityType, jpaAttribute) - .getFullQualifiedName()); - if (jpaAttribute.getPersistentAttributeType() == PersistentAttributeType.EMBEDDED) - edmProperty.setType(nameBuilder.buildFQN(type.getExternalName())); - - if (jpaAttribute.getJavaMember() instanceof AnnotatedElement) { - ((AnnotatedElement) jpaAttribute.getJavaMember()).getAnnotations(); - final Column jpaColumn = ((AnnotatedElement) jpaAttribute.getJavaMember()).getAnnotation(Column.class); - if (jpaColumn != null) { - edmProperty.setNullable(jpaColumn.nullable()); - edmProperty.setSrid(getSRID()); - edmProperty.setDefaultValue(getDeafultValue()); - // TODO Attribute Unicode - if (edmProperty.getTypeAsFQNObject().equals(EdmPrimitiveTypeKind.String.getFullQualifiedName()) - || edmProperty.getTypeAsFQNObject() - .equals(EdmPrimitiveTypeKind.Binary.getFullQualifiedName())) { - if (jpaColumn.length() > 0) - edmProperty.setMaxLength(jpaColumn.length()); - if (isLob()) - edmProperty.setMaxLength(null); - } else if (edmProperty.getType() - .equals(EdmPrimitiveTypeKind.Decimal.getFullQualifiedName().toString()) - || edmProperty.getType() - .equals(EdmPrimitiveTypeKind.DateTimeOffset.getFullQualifiedName().toString()) - || edmProperty.getType() - .equals(EdmPrimitiveTypeKind.TimeOfDay.getFullQualifiedName().toString())) { - // For a decimal property the value of this attribute - // specifies the maximum number of digits allowed in the - // properties value; it MUST be a positive integer. If - // no value is specified, the decimal property has - // unspecified precision. - // For a temporal property the value of this attribute - // specifies the number of decimal places allowed in the - // seconds portion of the property's value; it MUST be a - // non-negative integer between zero and twelve. If no - // value is specified, the temporal property has a - // precision of zero. - // is key - if (jpaColumn.precision() > 0) - edmProperty.setPrecision(jpaColumn.precision()); - else if (edmProperty.getType().equals(EdmPrimitiveTypeKind.DateTimeOffset.getFullQualifiedName().toString()) - && jpaColumn.precision() == 0) - throw new ODataJPAModelException(ODataJPAModelException.MessageKeys.PROPERTY_MISSING_PRECISION, - jpaAttribute.getName()); - if (edmProperty.getType().equals(EdmPrimitiveTypeKind.Decimal.getFullQualifiedName().toString()) - && jpaColumn.scale() > 0) - edmProperty.setScale(jpaColumn.scale()); - } - } - } - if (edmProperty != null) { - edmProperty.setAnnotations(edmAnnotations); - } + edmProperty.setAnnotations(edmAnnotations); } } - private CsdlMapping createMapper() { - if (!isLob()) { + /** + * Check consistency of provided attribute e.g. check id attribute was annotated with unsupported annotations + * @throws ODataJPAModelException + */ + abstract void checkConsistancy() throws ODataJPAModelException; + + CsdlMapping createMapper() { + if (!isLob() && !(getConverter() == null && isEnum())) { CsdlMapping mapping = new CsdlMapping(); mapping.setInternalName(this.getExternalName()); mapping.setMappedJavaClass(dbType); @@ -186,7 +259,64 @@ private CsdlMapping createMapper() { return null; } - private SRID getSRID() { + abstract Class determineEntityType(); + + abstract void determineIsVersion(); + + void determineProtection() throws ODataJPAModelException { + final EdmProtections jpaProtectinons = ((AnnotatedElement) this.jpaAttribute.getJavaMember()) + .getAnnotation(EdmProtections.class); + if (jpaProtectinons != null) { + for (final EdmProtectedBy jpaProtectedBy : jpaProtectinons.value()) { + determineOneProtection(jpaProtectedBy); + } + } else { + final EdmProtectedBy jpaProtectedBy = ((AnnotatedElement) this.jpaAttribute.getJavaMember()) + .getAnnotation(EdmProtectedBy.class); + if (jpaProtectedBy != null) { + determineOneProtection(jpaProtectedBy); + } + } + } + + void determineSearchable() { + final EdmSearchable jpaSearchable = ((AnnotatedElement) this.jpaAttribute.getJavaMember()) + .getAnnotation(EdmSearchable.class); + if (jpaSearchable != null) + searchable = true; + } + + abstract void determineStreamInfo() throws ODataJPAModelException; + + abstract void determineStructuredType(); + + abstract FullQualifiedName determineType() throws ODataJPAModelException; + + abstract String getDeafultValue() throws ODataJPAModelException; + + /** + * @return + */ + List getGroups() { + return fieldGroups; + } + + IntermediateModelElement getODataPrimitiveType() { + return schema.getEnumerationType(entityType); + } + + FullQualifiedName getSimpleType() throws ODataJPAModelException { + Class javaType = null; + if (valueConverter != null) { + javaType = dbType; + } else { + javaType = entityType; + } + return JPATypeConvertor.convertToEdmSimpleType(javaType, jpaAttribute) + .getFullQualifiedName(); + } + + SRID getSRID() { SRID result = null; if (jpaAttribute.getJavaMember() instanceof AnnotatedElement) { final AnnotatedElement annotatedElement = (AnnotatedElement) jpaAttribute.getJavaMember(); @@ -203,166 +333,208 @@ private SRID getSRID() { return result; } - private String getDeafultValue() throws ODataJPAModelException { - String valueString = null; - if (jpaAttribute.getJavaMember() instanceof Field - && jpaAttribute.getPersistentAttributeType() == PersistentAttributeType.BASIC) { - // It is not possible to get the default value directly from the - // Field, - // only from an instance field.get(Object obj).toString(); - try { - final Field field = (Field) jpaAttribute.getJavaMember(); - final Constructor constructor = jpaAttribute.getDeclaringType().getJavaType().getConstructor(); - final Object pojo = constructor.newInstance(); - field.setAccessible(true); - final Object value = field.get(pojo); - if (value != null) - valueString = value.toString(); - } catch (NoSuchMethodException e) { - throw new ODataJPAModelException(ODataJPAModelException.MessageKeys.PROPERTY_DEFAULT_ERROR, e, - jpaAttribute.getName()); - } catch (InstantiationException e) { - // Class could not be instantiated e.g. abstract class like - // Business Partner=> default could not be determined - // and will be ignored - } catch (IllegalAccessException e) { - throw new ODataJPAModelException(ODataJPAModelException.MessageKeys.PROPERTY_DEFAULT_ERROR, e, - jpaAttribute.getName()); - } catch (IllegalArgumentException e) { - throw new ODataJPAModelException(ODataJPAModelException.MessageKeys.PROPERTY_DEFAULT_ERROR, e, - jpaAttribute.getName()); - } catch (InvocationTargetException e) { - throw new ODataJPAModelException(ODataJPAModelException.MessageKeys.PROPERTY_DEFAULT_ERROR, e, - jpaAttribute.getName()); - } - } - return valueString; + boolean isPartOfGroup() { + return !fieldGroups.isEmpty(); } - @Override - CsdlProperty getEdmItem() throws ODataJPAModelException { - lazyBuildEdmItem(); - return edmProperty; + abstract boolean isStream(); + + /** + * Determines if wildcards are supported. In case a complex type is annotated this depends on the type of the target + * attribute. To prevent deed locks during metadata generation the determination is done late. + * @param + * @param claimName + * @param clazz + * @return + */ + boolean protectionWithWildcard(final String claimName, final Class clazz) { + if (externalProtectedPathNames.containsKey(claimName)) + return externalProtectedPathNames.get(claimName).supportsWildcards(clazz); + return true; } - private void buildProperty(final JPAEdmNameBuilder nameBuilder) throws ODataJPAModelException { - // Set element specific attributes of super type - this.setExternalName(nameBuilder.buildPropertyName(internalName)); - entityType = dbType = jpaAttribute.getJavaType(); - - if (this.jpaAttribute.getJavaMember() instanceof AnnotatedElement) { - final EdmIgnore jpaIgnore = ((AnnotatedElement) this.jpaAttribute.getJavaMember()) - .getAnnotation(EdmIgnore.class); - if (jpaIgnore != null) { - this.setIgnore(true); - } - if (jpaAttribute.getPersistentAttributeType() == PersistentAttributeType.EMBEDDED) - type = schema.getStructuredType(jpaAttribute); - else - type = null; - - final Convert jpaConverter = ((AnnotatedElement) this.jpaAttribute.getJavaMember()) - .getAnnotation(Convert.class); - if (jpaConverter != null) { - try { - Type[] convType = jpaConverter.converter().getGenericInterfaces(); - Type[] types = ((ParameterizedType) convType[0]).getActualTypeArguments(); - entityType = (Class) types[0]; - dbType = (Class) types[1]; - if (!JPATypeConvertor.isSupportedByOlingo(entityType)) - valueConverter = (AttributeConverter) jpaConverter.converter().newInstance(); - } catch (InstantiationException e) { - throw new ODataJPAModelException( - ODataJPAModelException.MessageKeys.TYPE_MAPPER_COULD_NOT_INSANTIATE, e); - } catch (IllegalAccessException e) { - throw new ODataJPAModelException( - ODataJPAModelException.MessageKeys.TYPE_MAPPER_COULD_NOT_INSANTIATE, e); - } - } else { - entityType = dbType = jpaAttribute.getJavaType(); - } - - final Column jpaColunnDetails = ((AnnotatedElement) this.jpaAttribute.getJavaMember()) - .getAnnotation(Column.class); - if (jpaColunnDetails != null) { - // TODO allow default name - dbFieldName = jpaColunnDetails.name(); - if (dbFieldName.isEmpty()) { - final StringBuffer s = new StringBuffer(DB_FIELD_NAME_PATTERN); - s.replace(1, 3, internalName); - dbFieldName = s.toString(); + void setFacet() throws ODataJPAModelException { + if (jpaAttribute.getJavaMember() instanceof AnnotatedElement) { + final Column jpaColumn = ((AnnotatedElement) jpaAttribute.getJavaMember()).getAnnotation(Column.class); + if (jpaColumn != null) { + edmProperty.setNullable(jpaColumn.nullable()); + edmProperty.setSrid(getSRID()); + edmProperty.setDefaultValue(getDeafultValue()); + // TODO Attribute Unicode + if (edmProperty.getTypeAsFQNObject().equals(EdmPrimitiveTypeKind.String.getFullQualifiedName()) + || edmProperty.getTypeAsFQNObject().equals(EdmPrimitiveTypeKind.Binary.getFullQualifiedName())) { + if (jpaColumn.length() > 0) + edmProperty.setMaxLength(jpaColumn.length()); + if (isLob()) + edmProperty.setMaxLength(null); + } else if (edmProperty.getType() + .equals(EdmPrimitiveTypeKind.Decimal.getFullQualifiedName().toString()) + || edmProperty.getType() + .equals(EdmPrimitiveTypeKind.DateTimeOffset.getFullQualifiedName().toString()) + || edmProperty.getType() + .equals(EdmPrimitiveTypeKind.TimeOfDay.getFullQualifiedName().toString())) { + // For a decimal property the value of this attribute specifies the maximum number of digits allowed in the + // properties value; it MUST be a positive integer. If no value is specified, the decimal property has + // unspecified precision. For a temporal property the value of this attribute specifies the number of decimal + // places allowed in the seconds portion of the property's value; it MUST be a non-negative integer between + // zero and twelve. If no value is specified, the temporal property has a precision of zero. + if (jpaColumn.precision() > 0) + edmProperty.setPrecision(jpaColumn.precision()); + else if (edmProperty.getType().equals(EdmPrimitiveTypeKind.DateTimeOffset.getFullQualifiedName().toString()) + && jpaColumn.precision() == 0) + throw new ODataJPAModelException(ODataJPAModelException.MessageKeys.PROPERTY_MISSING_PRECISION, + jpaAttribute.getName()); + if (edmProperty.getType().equals(EdmPrimitiveTypeKind.Decimal.getFullQualifiedName().toString()) + && jpaColumn.scale() > 0) + edmProperty.setScale(jpaColumn.scale()); } - } else - dbFieldName = internalName; - // TODO @Transient -> e.g. Calculated fields like formated name - final EdmSearchable jpaSearchable = ((AnnotatedElement) this.jpaAttribute.getJavaMember()) - .getAnnotation(EdmSearchable.class); - if (jpaSearchable != null) - searchable = true; - - streamInfo = ((AnnotatedElement) jpaAttribute.getJavaMember()).getAnnotation(EdmMediaStream.class); - if (streamInfo != null) { - if ((streamInfo.contentType() == null || streamInfo.contentType().isEmpty()) - && (streamInfo.contentTypeAttribute() == null || streamInfo.contentTypeAttribute().isEmpty())) - throw new ODataJPAModelException(ODataJPAModelException.MessageKeys.ANNOTATION_STREAM_INCOMPLETE, - internalName); - } - final Version jpaVersion = ((AnnotatedElement) this.jpaAttribute.getJavaMember()) - .getAnnotation(Version.class); - if (jpaVersion != null) { - isVersion = true; } } - postProcessor.processProperty(this, jpaAttribute.getDeclaringType().getJavaType().getCanonicalName()); - // Process annotations after post processing, as external name it could - // have been changed - getAnnotations(edmAnnotations, this.jpaAttribute.getJavaMember(), internalName, AppliesTo.PROPERTY); } - @Override - public boolean isAssociation() { - return false; + /** + * Converts an internal path into an external path + * @param internalPath + * @return + */ + private String convertPath(final String internalPath) { + + String[] pathSegments = internalPath.split(JPAPath.PATH_SEPERATOR); + StringBuilder externalPath = new StringBuilder(); + for (final String segement : pathSegments) { + externalPath.append(nameBuilder.buildPropertyName(segement)); + externalPath.append(JPAPath.PATH_SEPERATOR); + } + externalPath.deleteCharAt(externalPath.length() - 1); + + return externalPath.toString(); } - String getDBFieldName() { - return dbFieldName; + /** + * @param calculator + * @return + * @throws ODataJPAModelException + */ + @SuppressWarnings("unchecked") + private Constructor> determineCalculatorConstructor( + Class> calculator) throws ODataJPAModelException { + + if (calculator.getConstructors().length > 1) + throw new ODataJPAModelException(TRANSIENT_CALCULATOR_TOO_MANY_CONSTRUCTORS, + calculator.getName(), jpaAttribute.getName(), + jpaAttribute.getJavaMember().getDeclaringClass().getName()); + final Constructor c = calculator.getConstructors()[0]; + if (c.getParameters() != null) { + for (final Parameter p : c.getParameters()) { + if (!(p.getType().isAssignableFrom(EntityManager.class) + || p.getType().isAssignableFrom(Map.class))) + throw new ODataJPAModelException(MessageKeys.TRANSIENT_CALCULATOR_WRONG_PARAMETER, + calculator.getName(), jpaAttribute.getName(), + jpaAttribute.getJavaMember().getDeclaringClass().getName()); + } + } + return (Constructor>) c; } - @Override - public EdmPrimitiveTypeKind getEdmType() throws ODataJPAModelException { - return JPATypeConvertor.convertToEdmSimpleType(jpaAttribute.getJavaType()); + private void determineDBFieldName() { + final Column jpaColunnDetails = ((AnnotatedElement) this.jpaAttribute.getJavaMember()) + .getAnnotation(Column.class); + if (jpaColunnDetails != null) { + // TODO allow default name + dbFieldName = jpaColunnDetails.name(); + if (dbFieldName.isEmpty()) { + final StringBuilder s = new StringBuilder(DB_FIELD_NAME_PATTERN); + s.replace(1, 3, internalName); + dbFieldName = s.toString(); + } + } else { + dbFieldName = internalName; + } } - @Override - public CsdlProperty getProperty() throws ODataJPAModelException { - return getEdmItem(); + /** + * + */ + private void determineFieldGroups() { + final EdmVisibleFor jpaFieldGroups = ((AnnotatedElement) this.jpaAttribute.getJavaMember()) + .getAnnotation(EdmVisibleFor.class); + if (jpaFieldGroups != null) + fieldGroups = Arrays.stream(jpaFieldGroups.value()).collect(Collectors.toList()); + else + fieldGroups = new ArrayList<>(0); } - @Override - public boolean isSearchable() { - return searchable; + private void determineIgnore() { + final EdmIgnore jpaIgnore = ((AnnotatedElement) this.jpaAttribute.getJavaMember()) + .getAnnotation(EdmIgnore.class); + if (jpaIgnore != null) { + this.setIgnore(true); + } } - String getContentType() { - return streamInfo.contentType(); + private void determineInternalTypesFromConverter() throws ODataJPAModelException { + final Convert jpaConverter = ((AnnotatedElement) this.jpaAttribute.getJavaMember()) + .getAnnotation(Convert.class); + if (jpaConverter != null) { + try { + Type[] convType = jpaConverter.converter().getGenericInterfaces(); + Type[] types = ((ParameterizedType) convType[0]).getActualTypeArguments(); + entityType = (Class) types[0]; + dbType = (Class) types[1]; + if (!JPATypeConvertor.isSupportedByOlingo(entityType)) + valueConverter = (AttributeConverter) jpaConverter.converter().newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + throw new ODataJPAModelException( + ODataJPAModelException.MessageKeys.TYPE_MAPPER_COULD_NOT_INSANTIATE, e); + } + } } - String getContentTypeProperty() { - return streamInfo.contentTypeAttribute(); + private void determineOneProtection(final EdmProtectedBy jpaProtectedBy) throws ODataJPAModelException { + + List externalNames; + final String protectionClaimName = jpaProtectedBy.name(); + if (externalProtectedPathNames.containsKey(protectionClaimName)) + externalNames = externalProtectedPathNames.get(protectionClaimName).getPath(); + else + externalNames = new ArrayList<>(2); + if (jpaAttribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.EMBEDDED) { + String internalProtectedPath = jpaProtectedBy.path(); + if (internalProtectedPath.length() == 0) { + throw new ODataJPAModelException(COMPLEX_PROPERTY_MISSING_PROTECTION_PATH, this.managedType.getJavaType() + .getCanonicalName(), this.internalName); + } + externalNames.add(getExternalName() + JPAPath.PATH_SEPERATOR + convertPath(jpaProtectedBy.path())); + } else { + externalNames.add(getExternalName()); + } + externalProtectedPathNames.put(protectionClaimName, new JPAProtectionInfo(externalNames, jpaProtectedBy + .wildcardSupported())); } - @Override - public boolean isEtag() { - return isVersion; + private List determineRequiredAttributesTransient(final EdmTransient jpaTransient) { + return jpaTransient.requiredAttributes() == null ? Collections.emptyList() : Arrays.asList( + jpaTransient.requiredAttributes()); } - @Override - public void addAnnotations(List annotations) { - edmAnnotations.addAll(annotations); + /** + * @throws ODataJPAModelException + * + */ + void determineTransient() throws ODataJPAModelException { + final EdmTransient jpaTransient = ((AnnotatedElement) this.jpaAttribute.getJavaMember()) + .getAnnotation(EdmTransient.class); + if (jpaTransient != null) { + if (isKey()) + throw new ODataJPAModelException(TRANSIENT_KEY_NOT_SUPPORTED, + jpaAttribute.getJavaMember().getDeclaringClass().getName()); + requiredAttributes = determineRequiredAttributesTransient(jpaTransient); + transientCalculatorConstructor = determineCalculatorConstructor(jpaTransient.calculator()); + } } private boolean isLob() { - if (jpaAttribute != null) { + if (jpaAttribute != null && jpaAttribute.getJavaMember() instanceof AnnotatedElement) { final AnnotatedElement annotatedElement = (AnnotatedElement) jpaAttribute.getJavaMember(); if (annotatedElement != null && annotatedElement.getAnnotation(Lob.class) != null) { return true; @@ -370,4 +542,4 @@ private boolean isLob() { } return false; } -} +} \ No newline at end of file diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateReferences.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateReferences.java index 7f8079bff..fbaa3d402 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateReferences.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateReferences.java @@ -15,19 +15,17 @@ import org.apache.olingo.commons.api.edmx.EdmxReference; import org.apache.olingo.commons.api.edmx.EdmxReferenceInclude; -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.databind.JsonMappingException; import com.sap.olingo.jpa.metadata.core.edm.mapper.annotation.SchemaReader; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException.MessageKeys; import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediateReferenceList; final class IntermediateReferences implements IntermediateReferenceList { - final List references = new ArrayList(); - final List edmxReferences = new ArrayList(); - final Map> terms = new HashMap>(); - final Map schemas = new HashMap(); - final Map aliasDirectory = new HashMap(); + final List references = new ArrayList<>(); + List edmxReferences = new ArrayList<>(); + final Map> terms = new HashMap<>(); + final Map schemas = new HashMap<>(); + final Map aliasDirectory = new HashMap<>(); @Override public IntermediateReferenceAccess addReference(final String uri) throws ODataJPAModelException { @@ -47,13 +45,7 @@ public IntermediateReferenceAccess addReference(final String uri, final String p try { Map newSchemas = new SchemaReader().getSchemas(path); schemas.putAll(newSchemas); - extractTerms(newSchemas); - } catch (JsonParseException e) { - // Parsing of %1$s failed with message %2$s - throw new ODataJPAModelException(MessageKeys.ANNOTATION_PARSE_ERROR, e, path, e.getMessage()); - } catch (JsonMappingException e) { - // Parsing of %1$s failed with message %2$s - throw new ODataJPAModelException(MessageKeys.ANNOTATION_PARSE_ERROR, e, path, e.getMessage()); + extractTerms(); } catch (IOException e) { // Parsing of %1$s failed with message %2$s throw new ODataJPAModelException(MessageKeys.ANNOTATION_PARSE_ERROR, e, path, e.getMessage()); @@ -63,9 +55,9 @@ public IntermediateReferenceAccess addReference(final String uri, final String p return reference; } - private void extractTerms(Map newSchemas) { + private void extractTerms() { for (Entry schema : schemas.entrySet()) { - Map schemaTerms = new HashMap(); + Map schemaTerms = new HashMap<>(); for (CsdlTerm term : schema.getValue().getTerms()) { schemaTerms.put(term.getName(), term); } @@ -83,12 +75,14 @@ public CsdlTerm getTerm(FullQualifiedName termName) { } } } + if (schema == null) + return null; return schema.get(termName.getName()); } public List getSchemas() { - List result = new ArrayList(); + List result = new ArrayList<>(); for (Entry schema : schemas.entrySet()) { result.add(schema.getValue()); } @@ -97,7 +91,7 @@ public List getSchemas() { List getEdmReferences() { if (references.size() != edmxReferences.size()) { - edmxReferences.removeAll(edmxReferences); + edmxReferences = new ArrayList<>(references.size()); for (IntermediateReference r : references) { edmxReferences.add(r.getEdmReference()); } @@ -106,10 +100,10 @@ List getEdmReferences() { } private class IntermediateReference implements IntermediateReferenceList.IntermediateReferenceAccess { - final private URI uri; - final private String path; + private final URI uri; + private final String path; final EdmxReference edmxReference; - final private List includes = new ArrayList(); + private final List includes = new ArrayList<>(); public IntermediateReference(final URI uri, final String path) { super(); diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateSchema.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateSchema.java index 5b7c3bb64..3ea0454f0 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateSchema.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateSchema.java @@ -10,16 +10,22 @@ import javax.persistence.metamodel.EmbeddableType; import javax.persistence.metamodel.EntityType; import javax.persistence.metamodel.Metamodel; +import javax.persistence.metamodel.PluralAttribute; +import org.apache.olingo.commons.api.edm.EdmEnumType; import org.apache.olingo.commons.api.edm.provider.CsdlAction; import org.apache.olingo.commons.api.edm.provider.CsdlComplexType; import org.apache.olingo.commons.api.edm.provider.CsdlEntityType; +import org.apache.olingo.commons.api.edm.provider.CsdlEnumType; import org.apache.olingo.commons.api.edm.provider.CsdlFunction; import org.apache.olingo.commons.api.edm.provider.CsdlSchema; import org.reflections.Reflections; +import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmEnumeration; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAAction; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEdmNameBuilder; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEntityType; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEnumerationAttribute; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAFunction; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAStructuredType; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; @@ -38,6 +44,7 @@ final class IntermediateSchema extends IntermediateModelElement { private final Map entityTypeListInternalKey; private final Map functionListInternalKey; private final Map actionListInternalKey; + private final Map enumTypeListInternalKey; private IntermediateEntityContainer container; private final Reflections reflections; private CsdlSchema edmSchema; @@ -45,28 +52,50 @@ final class IntermediateSchema extends IntermediateModelElement { IntermediateSchema(final JPAEdmNameBuilder nameBuilder, final Metamodel jpaMetamodel, final Reflections reflections) throws ODataJPAModelException { - super(nameBuilder, nameBuilder.buildNamespace()); + super(nameBuilder, nameBuilder.getNamespace()); this.reflections = reflections; this.jpaMetamodel = jpaMetamodel; + this.enumTypeListInternalKey = buildEnumerationTypeList(); this.complexTypeListInternalKey = buildComplexTypeList(); this.entityTypeListInternalKey = buildEntityTypeList(); this.functionListInternalKey = buildFunctionList(); this.actionListInternalKey = buildActionList(); } + public IntermediateEnumerationType getEnumerationType(final Class enumType) { + if (enumType.isArray()) + return this.enumTypeListInternalKey.get(enumType.getComponentType().getSimpleName()); + return this.enumTypeListInternalKey.get(enumType.getSimpleName()); + } + + public JPAEnumerationAttribute getEnumerationType(final EdmEnumType type) { + for (final Entry enumeration : this.enumTypeListInternalKey.entrySet()) { + if (enumeration.getValue().getExternalFQN().equals(type.getFullQualifiedName())) + return enumeration.getValue(); + } + return null; + } + + public IntermediateEnumerationType getEnumerationType(final String externalName) { + for (final Entry enumeration : this.enumTypeListInternalKey.entrySet()) { + if (enumeration.getValue().getExternalName().equals(externalName)) + return enumeration.getValue(); + } + return null; + } + @SuppressWarnings("unchecked") @Override - protected void lazyBuildEdmItem() throws ODataJPAModelException { + protected synchronized void lazyBuildEdmItem() throws ODataJPAModelException { edmSchema = new CsdlSchema(); - edmSchema.setNamespace(nameBuilder.buildNamespace()); + edmSchema.setNamespace(nameBuilder.getNamespace()); + edmSchema.setEnumTypes((List) extractEdmModelElements(enumTypeListInternalKey)); edmSchema.setComplexTypes((List) extractEdmModelElements(complexTypeListInternalKey)); edmSchema.setEntityTypes((List) extractEdmModelElements(entityTypeListInternalKey)); edmSchema.setFunctions((List) extractEdmModelElements(functionListInternalKey)); edmSchema.setActions((List) extractEdmModelElements(actionListInternalKey)); -// edm:Action // edm:Annotations // edm:Annotation -// edm:EnumType --> Annotation @Enummerated // edm:Term // edm:TypeDefinition // MUST be the last thing that is done !!!! @@ -75,31 +104,20 @@ protected void lazyBuildEdmItem() throws ODataJPAModelException { } - @Override - CsdlSchema getEdmItem() throws ODataJPAModelException { - if (edmSchema == null) - lazyBuildEdmItem(); - return edmSchema; - } - - IntermediateStructuredType getStructuredType(final Attribute jpaAttribute) { - IntermediateStructuredType type = complexTypeListInternalKey.get(IntNameBuilder.buildStructuredTypeName(jpaAttribute - .getJavaType())); - if (type == null) - type = entityTypeListInternalKey.get(IntNameBuilder.buildStructuredTypeName(jpaAttribute.getJavaType())); - return type; - } - - IntermediateStructuredType getStructuredType(final Class targetClass) { - IntermediateStructuredType type = entityTypeListInternalKey - .get(IntNameBuilder.buildStructuredTypeName(targetClass)); - if (type == null) - type = complexTypeListInternalKey.get(IntNameBuilder.buildStructuredTypeName(targetClass)); - return type; + JPAAction getAction(final String externalName) { + for (final Entry action : actionListInternalKey.entrySet()) { + if (action.getValue().getExternalName().equals(externalName) && !action.getValue().ignore()) + return action.getValue(); + } + return null; } - IntermediateStructuredType getEntityType(final Class targetClass) { - return entityTypeListInternalKey.get(IntNameBuilder.buildStructuredTypeName(targetClass)); + List getActions() { + final ArrayList actions = new ArrayList<>(); + for (final Entry action : actionListInternalKey.entrySet()) { + actions.add(action.getValue()); + } + return actions; } IntermediateStructuredType getComplexType(final Class targetClass) { @@ -114,64 +132,98 @@ JPAStructuredType getComplexType(final String externalName) { return null; } + @Override + CsdlSchema getEdmItem() throws ODataJPAModelException { + if (edmSchema == null) + lazyBuildEdmItem(); + return edmSchema; + } + + IntermediateStructuredType getEntityType(final Class targetClass) { + return entityTypeListInternalKey.get(IntNameBuilder.buildStructuredTypeName(targetClass)); + } + JPAEntityType getEntityType(final String externalName) { - for (final String internalName : entityTypeListInternalKey.keySet()) { - if (entityTypeListInternalKey.get(internalName).getExternalName().equals(externalName)) - return entityTypeListInternalKey.get(internalName); + + for (final Entry et : entityTypeListInternalKey.entrySet()) { + if (et.getValue().getExternalName().equals(externalName)) + return et.getValue(); + } + return null; + } + + JPAEntityType getEntityType(final String dbCatalog, final String dbSchema, final String dbTableName) { + for (final Entry et : entityTypeListInternalKey.entrySet()) { + if (et.getValue().dbEquals(dbCatalog, dbSchema, dbTableName)) + return et.getValue(); } return null; } List getEntityTypes() { - final List entityTypes = new ArrayList(); - for (final String internalName : entityTypeListInternalKey.keySet()) { - entityTypes.add(entityTypeListInternalKey.get(internalName)); + final List entityTypes = new ArrayList<>(); + for (final Entry et : entityTypeListInternalKey.entrySet()) { + entityTypes.add(et.getValue()); } return entityTypes; } JPAFunction getFunction(final String externalName) { - for (final String internalName : functionListInternalKey.keySet()) { - if (functionListInternalKey.get(internalName).getExternalName().equals(externalName)) { - if (!functionListInternalKey.get(internalName).ignore()) - return functionListInternalKey.get(internalName); - } + for (final Entry func : functionListInternalKey.entrySet()) { + if (func.getValue().getExternalName().equals(externalName) + && !func.getValue().ignore()) + return func.getValue(); } return null; + } List getFunctions() { - final ArrayList functions = new ArrayList(); - for (final String internalName : functionListInternalKey.keySet()) { - functions.add(functionListInternalKey.get(internalName)); + final ArrayList functions = new ArrayList<>(); + for (final Entry func : functionListInternalKey.entrySet()) { + functions.add(func.getValue()); } return functions; } - JPAAction getAction(final String externalName) { - for (final Entry action : actionListInternalKey.entrySet()) { - if (action.getValue().getExternalName().equals(externalName)) { - if (!action.getValue().ignore()) - return action.getValue(); - } - } - return null; + IntermediateStructuredType getStructuredType(final PluralAttribute jpaAttribute) { + IntermediateStructuredType type = complexTypeListInternalKey.get(IntNameBuilder.buildStructuredTypeName(jpaAttribute + .getElementType().getJavaType())); + if (type == null) + type = entityTypeListInternalKey.get(IntNameBuilder.buildStructuredTypeName(jpaAttribute.getElementType() + .getJavaType())); + return type; } - List getActions() { - final ArrayList actions = new ArrayList(); - for (final Entry action : actionListInternalKey.entrySet()) { - actions.add(action.getValue()); - } - return actions; + IntermediateStructuredType getStructuredType(final Attribute jpaAttribute) { + IntermediateStructuredType type = complexTypeListInternalKey.get(IntNameBuilder.buildStructuredTypeName(jpaAttribute + .getJavaType())); + if (type == null) + type = entityTypeListInternalKey.get(IntNameBuilder.buildStructuredTypeName(jpaAttribute.getJavaType())); + return type; + } + + IntermediateStructuredType getStructuredType(final Class targetClass) { + IntermediateStructuredType type = entityTypeListInternalKey + .get(IntNameBuilder.buildStructuredTypeName(targetClass)); + if (type == null) + type = complexTypeListInternalKey.get(IntNameBuilder.buildStructuredTypeName(targetClass)); + return type; } void setContainer(final IntermediateEntityContainer container) { this.container = container; } + private Map buildActionList() throws ODataJPAModelException { + final HashMap actionList = new HashMap<>(); + final IntermediateActionFactory factory = new IntermediateActionFactory(); + actionList.putAll(factory.create(nameBuilder, reflections, this)); + return actionList; + } + private Map buildComplexTypeList() throws ODataJPAModelException { - final HashMap ctList = new HashMap(); + final HashMap ctList = new HashMap<>(); for (final EmbeddableType embeddable : this.jpaMetamodel.getEmbeddables()) { final IntermediateComplexType ct = new IntermediateComplexType(nameBuilder, embeddable, this); @@ -180,8 +232,8 @@ private Map buildComplexTypeList() throws OData return ctList; } - private Map buildEntityTypeList() throws ODataJPAModelException { - final HashMap etList = new HashMap(); + private Map buildEntityTypeList() { + final HashMap etList = new HashMap<>(); for (final EntityType entity : this.jpaMetamodel.getEntities()) { final IntermediateEntityType et = new IntermediateEntityType(nameBuilder, entity, this); @@ -190,8 +242,22 @@ private Map buildEntityTypeList() throws ODataJP return etList; } + private > Map buildEnumerationTypeList() { + final HashMap enumList = new HashMap<>(); + if (reflections != null) { + for (Class enumeration : reflections.getTypesAnnotatedWith(EdmEnumeration.class)) { + if (enumeration.isEnum()) { + @SuppressWarnings("unchecked") + final IntermediateEnumerationType e = new IntermediateEnumerationType(nameBuilder, (Class) enumeration); + enumList.put(e.getInternalName(), e); + } + } + } + return enumList; + } + private Map buildFunctionList() throws ODataJPAModelException { - final HashMap funcList = new HashMap(); + final HashMap funcList = new HashMap<>(); // 1. Option: Create Function from Entity Annotations final IntermediateFunctionFactory factory = new IntermediateFunctionFactory(); for (final EntityType entity : this.jpaMetamodel.getEntities()) { @@ -202,12 +268,4 @@ private Map buildFunctionList() throws ODataJPAMod funcList.putAll(factory.create(nameBuilder, reflections, this)); return funcList; } - - private Map buildActionList() throws ODataJPAModelException { - final HashMap actionList = new HashMap(); - final IntermediateActionFactory factory = new IntermediateActionFactory(); - actionList.putAll(factory.create(nameBuilder, reflections, this)); - return actionList; - } - } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateServiceDocument.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateServiceDocument.java index 7c5beb86c..3a32294d2 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateServiceDocument.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateServiceDocument.java @@ -1,16 +1,17 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; -import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import javax.persistence.metamodel.Metamodel; import org.apache.olingo.commons.api.edm.EdmAction; import org.apache.olingo.commons.api.edm.EdmBindingTarget; import org.apache.olingo.commons.api.edm.EdmComplexType; +import org.apache.olingo.commons.api.edm.EdmEnumType; import org.apache.olingo.commons.api.edm.EdmFunction; import org.apache.olingo.commons.api.edm.EdmType; import org.apache.olingo.commons.api.edm.FullQualifiedName; @@ -20,13 +21,16 @@ import org.apache.olingo.commons.api.edmx.EdmxReference; import org.reflections.Reflections; import org.reflections.scanners.SubTypesScanner; -import org.reflections.util.ClasspathHelper; +import org.reflections.scanners.TypeAnnotationsScanner; import org.reflections.util.ConfigurationBuilder; +import org.reflections.util.FilterBuilder; import com.sap.olingo.jpa.metadata.api.JPAEdmMetadataPostProcessor; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAAction; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEdmNameBuilder; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEntitySet; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEntityType; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEnumerationAttribute; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAFunction; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAServiceDocument; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAStructuredType; @@ -34,7 +38,7 @@ /** * http://docs.oasis-open.org/odata/odata/v4.0/errata02/os/complete/schemas/edmx.xsd - * A Service Document can contain of multiple schemas, but only of + * A Service Document can contain multiple schemas, but only * one Entity Container. This container is assigned to one of the * schemas. * http://services.odata.org/V4/Northwind/Northwind.svc/$metadata @@ -51,15 +55,29 @@ class IntermediateServiceDocument implements JPAServiceDocument { IntermediateServiceDocument(final String namespace, final Metamodel jpaMetamodel, final JPAEdmMetadataPostProcessor postProcessor, final String[] packageName) throws ODataJPAModelException { + this(new JPADefaultEdmNameBuilder(namespace), jpaMetamodel, postProcessor, packageName); + } + + /** + * @param customJPANameBuilder + * @param metamodel + * @param postProcessor + * @param packageName + * @throws ODataJPAModelException + */ + IntermediateServiceDocument(final JPAEdmNameBuilder nameBuilder, final Metamodel jpaMetamodel, + final JPAEdmMetadataPostProcessor postProcessor, final String[] packageName) throws ODataJPAModelException { + this.pP = postProcessor != null ? postProcessor : new DefaultEdmPostProcessor(); IntermediateModelElement.setPostProcessor(pP); this.reflections = createReflections(packageName); this.references = new IntermediateReferences(); pP.provideReferences(this.references); - this.nameBuilder = new JPAEdmNameBuilder(namespace); + this.nameBuilder = nameBuilder; this.jpaMetamodel = jpaMetamodel; - this.schemaListInternalKey = buildIntermediateSchemas(); + this.schemaListInternalKey = new HashMap<>(); + buildIntermediateSchemas(); this.container = new IntermediateEntityContainer(nameBuilder, schemaListInternalKey); setContainer(); } @@ -111,6 +129,22 @@ public JPAEntityType getEntity(final EdmType edmType) throws ODataJPAModelExcept return null; } + /* + * (non-Javadoc) + * + * @see + * com.sap.olingo.jpa.metadata.core.edm.mapper.impl.JPAServiceDocument#getEntity(java.lang.Class) + */ + @Override + public JPAEntityType getEntity(Class entityClass) throws ODataJPAModelException { + for (final Entry schema : schemaListInternalKey.entrySet()) { + final JPAEntityType et = (JPAEntityType) schema.getValue().getEntityType(entityClass); + if (et != null) + return et; + } + return null; + } + /* * (non-Javadoc) * @@ -240,41 +274,66 @@ public boolean hasMediaETag(final EdmBindingTarget entitySetOrSingleton) { return false; } - private Map buildIntermediateSchemas() throws ODataJPAModelException { - final Map schemaList = new HashMap(); + @Override + public JPAEdmNameBuilder getNameBuilder() { + return nameBuilder; + } + + private void buildIntermediateSchemas() throws ODataJPAModelException { final IntermediateSchema schema = new IntermediateSchema(nameBuilder, jpaMetamodel, reflections); - schemaList.put(schema.internalName, schema); - return schemaList; + schemaListInternalKey.put(schema.internalName, schema); } private Reflections createReflections(String... packageName) { if (packageName != null && packageName.length > 0) { ConfigurationBuilder configBuilder = new ConfigurationBuilder(); - List urls = new ArrayList(); - for (int i = 0; i < packageName.length; i++) { - urls.addAll(ClasspathHelper.forPackage(packageName[i])); - } - configBuilder.setUrls(urls); - configBuilder.setScanners(new SubTypesScanner(false)); + configBuilder.setScanners(new SubTypesScanner(false), new TypeAnnotationsScanner()); + configBuilder.forPackages(packageName); + configBuilder.filterInputsBy(new FilterBuilder().includePackage(packageName)); return new Reflections(configBuilder); - } else + } else { return null; + } } private List extractEdmSchemas() throws ODataJPAModelException { - final List schemas = new ArrayList(); - for (final String internalName : schemaListInternalKey.keySet()) { - schemas.add(schemaListInternalKey.get(internalName).getEdmItem()); + final List schemas = new ArrayList<>(); + try { + if (schemaListInternalKey.isEmpty()) + buildIntermediateSchemas(); + for (final Entry schema : schemaListInternalKey.entrySet()) { + schemas.add(schema.getValue().getEdmItem()); + } + } catch (Exception e) { + schemaListInternalKey.clear(); + throw e; } return schemas; } private void setContainer() { - for (final String externalName : schemaListInternalKey.keySet()) { - schemaListInternalKey.get(externalName).setContainer(container); - return; + + for (final Entry schema : schemaListInternalKey.entrySet()) { + schema.getValue().setContainer(container); + break; } } + @Override + public JPAEnumerationAttribute getEnumType(EdmEnumType type) { + final IntermediateSchema schema = schemaListInternalKey.get(type.getFullQualifiedName().getNamespace()); + if (schema != null) + return schema.getEnumerationType(type); + return null; + } + + @Override + public JPAEnumerationAttribute getEnumType(String fqnAsString) { + final FullQualifiedName fqn = new FullQualifiedName(fqnAsString); + final IntermediateSchema schema = schemaListInternalKey.get(fqn.getNamespace()); + if (schema != null) + return schema.getEnumerationType(fqn.getName()); + return null; + } } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateSimpleProperty.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateSimpleProperty.java new file mode 100644 index 000000000..158949bd9 --- /dev/null +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateSimpleProperty.java @@ -0,0 +1,164 @@ +package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; + +import static com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException.MessageKeys.NOT_SUPPORTED_KEY_PART_OF_GROUP; +import static com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException.MessageKeys.NOT_SUPPORTED_MANDATORY_PART_OF_GROUP; + +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; + +import javax.persistence.Column; +import javax.persistence.Version; +import javax.persistence.metamodel.Attribute; +import javax.persistence.metamodel.Attribute.PersistentAttributeType; +import javax.persistence.metamodel.SingularAttribute; + +import org.apache.olingo.commons.api.edm.FullQualifiedName; + +import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmMediaStream; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEdmNameBuilder; +import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; + +/** + * A Property is described on the one hand by its Name and Type and on the other + * hand by its Property Facets. The type is a qualified name of either a + * primitive type, a complex type or a enumeration type. Primitive types are + * mapped by {@link JPATypeConvertor}. + * + *

+ * For details about Property metadata see: OData Version 4.0 Part 3 - 6 Structural Property + * + * + * @author Oliver Grande + * + */ +class IntermediateSimpleProperty extends IntermediateProperty { + private EdmMediaStream streamInfo; + + IntermediateSimpleProperty(final JPAEdmNameBuilder nameBuilder, final Attribute jpaAttribute, + final IntermediateSchema schema) throws ODataJPAModelException { + + super(nameBuilder, jpaAttribute, schema); + } + + @Override + public boolean isAssociation() { + return false; + } + + @Override + public boolean isCollection() { + return false; + } + + @Override + public boolean isComplex() { + return jpaAttribute.getPersistentAttributeType() == PersistentAttributeType.EMBEDDED; + } + + @Override + public boolean isKey() { + if (jpaAttribute instanceof SingularAttribute) + return ((SingularAttribute) jpaAttribute).isId(); + else + return false; + } + + @Override + void checkConsistancy() throws ODataJPAModelException { + final Column jpaColumn = ((AnnotatedElement) jpaAttribute.getJavaMember()).getAnnotation(Column.class); + if (jpaColumn != null && isPartOfGroup() && !jpaColumn.nullable()) + throw new ODataJPAModelException(NOT_SUPPORTED_MANDATORY_PART_OF_GROUP, jpaAttribute.getDeclaringType() + .getJavaType().getCanonicalName(), jpaAttribute.getName()); + if (isPartOfGroup() && isKey()) + throw new ODataJPAModelException(NOT_SUPPORTED_KEY_PART_OF_GROUP, jpaAttribute.getDeclaringType() + .getJavaType().getCanonicalName(), jpaAttribute.getName()); + } + + @Override + Class determineEntityType() { + return jpaAttribute.getJavaType(); + } + + @Override + void determineIsVersion() { + final Version jpaVersion = ((AnnotatedElement) this.jpaAttribute.getJavaMember()) + .getAnnotation(Version.class); + if (jpaVersion != null) { + isVersion = true; + } + } + + @Override + void determineStreamInfo() throws ODataJPAModelException { + streamInfo = ((AnnotatedElement) jpaAttribute.getJavaMember()).getAnnotation(EdmMediaStream.class); + if (streamInfo != null && (streamInfo.contentType() == null || streamInfo.contentType().isEmpty()) + && (streamInfo.contentTypeAttribute() == null || streamInfo.contentTypeAttribute().isEmpty())) + throw new ODataJPAModelException(ODataJPAModelException.MessageKeys.ANNOTATION_STREAM_INCOMPLETE, + internalName); + } + + @Override + void determineStructuredType() { + if (jpaAttribute.getPersistentAttributeType() == PersistentAttributeType.EMBEDDED) + type = schema.getStructuredType(jpaAttribute); + else + type = null; + } + + @Override + FullQualifiedName determineType() throws ODataJPAModelException { + return determineTypeByPersistanceType(jpaAttribute.getPersistentAttributeType()); + } + + String getContentType() { + return streamInfo.contentType(); + } + + String getContentTypeProperty() { + return streamInfo.contentTypeAttribute(); + } + + @Override + String getDeafultValue() throws ODataJPAModelException { + String valueString = null; + if (jpaAttribute.getJavaMember() instanceof Field + && jpaAttribute.getPersistentAttributeType() == PersistentAttributeType.BASIC) { + // It is not possible to get the default value directly from the + // Field, only from an instance field.get(Object obj).toString(); //NOSONAR + try { + // Problem: In case of compound key, which is not referenced via @EmbeddedId Hibernate returns a field of the + // key class, whereas Eclipselink returns a field of the entity class; which can be checked via + // field.getDeclaringClass() + final Field field = (Field) jpaAttribute.getJavaMember(); + Constructor constructor; + if (!field.getDeclaringClass().equals(jpaAttribute.getDeclaringType().getJavaType())) + constructor = field.getDeclaringClass().getConstructor(); + else + constructor = jpaAttribute.getDeclaringType().getJavaType().getConstructor(); + final Object pojo = constructor.newInstance(); + field.setAccessible(true); + final Object value = field.get(pojo); + if (value != null) + valueString = value.toString(); + } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException + | InvocationTargetException e) { + throw new ODataJPAModelException(ODataJPAModelException.MessageKeys.PROPERTY_DEFAULT_ERROR, e, + jpaAttribute.getName()); + } catch (InstantiationException e) { + // Class could not be instantiated e.g. abstract class like + // Business Partner=> default could not be determined + // and will be ignored + } + } + return valueString; + } + + @Override + boolean isStream() { + return streamInfo != null && streamInfo.stream(); + } +} diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateStructuredType.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateStructuredType.java index ad1d4db30..485aa4685 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateStructuredType.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/IntermediateStructuredType.java @@ -1,34 +1,54 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; +import static com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException.MessageKeys.COMPLEX_PROPERTY_WRONG_PROTECTION_PATH; +import static com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException.MessageKeys.PROPERTY_REQUIRED_UNKNOWN; + import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.ParameterizedType; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; +import javax.annotation.Nonnull; import javax.persistence.AssociationOverride; import javax.persistence.AssociationOverrides; import javax.persistence.AttributeOverride; import javax.persistence.AttributeOverrides; +import javax.persistence.Column; +import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinColumns; import javax.persistence.OneToMany; +import javax.persistence.Version; import javax.persistence.metamodel.Attribute; import javax.persistence.metamodel.Attribute.PersistentAttributeType; import javax.persistence.metamodel.ManagedType; import javax.persistence.metamodel.PluralAttribute; import javax.persistence.metamodel.SingularAttribute; +import javax.persistence.metamodel.Type; import org.apache.olingo.commons.api.edm.FullQualifiedName; import org.apache.olingo.commons.api.edm.provider.CsdlStructuralType; +import org.apache.olingo.server.api.uri.UriResourceProperty; import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmDescriptionAssoziation; import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmIgnore; +import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmTransient; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAAssociationAttribute; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAAssociationPath; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAAttribute; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPACollectionAttribute; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEdmNameBuilder; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAElement; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAPath; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAProtectionInfo; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAStructuredType; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; @@ -37,20 +57,22 @@ abstract class IntermediateStructuredType extends IntermediateModelElement imple protected final Map declaredPropertiesList; protected final Map declaredNaviPropertiesList; protected final Map resolvedPathMap; - protected final Map intermediatePathMap; + protected final Map intermediatePathMap; protected final Map resolvedAssociationPathMap; protected final ManagedType jpaManagedType; protected final IntermediateSchema schema; + protected List protectedAttributes; + protected CsdlStructuralType edmStructuralType; IntermediateStructuredType(final JPAEdmNameBuilder nameBuilder, final ManagedType jpaManagedType, - final IntermediateSchema schema) throws ODataJPAModelException { + final IntermediateSchema schema) { super(nameBuilder, IntNameBuilder.buildStructuredTypeName(jpaManagedType.getJavaType())); - this.declaredPropertiesList = new HashMap(); - this.resolvedPathMap = new HashMap(); - this.intermediatePathMap = new HashMap(); - this.declaredNaviPropertiesList = new HashMap(); - this.resolvedAssociationPathMap = new HashMap(); + this.declaredPropertiesList = new HashMap<>(); + this.resolvedPathMap = new HashMap<>(); + this.intermediatePathMap = new HashMap<>(); + this.declaredNaviPropertiesList = new HashMap<>(); + this.resolvedAssociationPathMap = new HashMap<>(); this.jpaManagedType = jpaManagedType; this.schema = schema; determineIgnore(); @@ -75,31 +97,47 @@ public JPAAssociationPath getAssociationPath(final String externalName) throws O @Override public List getAssociationPathList() throws ODataJPAModelException { lazyBuildCompleteAssociationPathMap(); - final List associationList = new ArrayList(); + final List associationList = new ArrayList<>(); - for (final String externalName : resolvedAssociationPathMap.keySet()) { - associationList.add(resolvedAssociationPathMap.get(externalName)); + for (final Entry associationPat : resolvedAssociationPathMap.entrySet()) { + associationList.add(associationPat.getValue()); } return associationList; } @Override - public JPAAttribute getAttribute(final String internalName) throws ODataJPAModelException { - lazyBuildEdmItem(); - JPAAttribute result = declaredPropertiesList.get(internalName); - if (result == null && getBaseType() != null) + public Optional getAttribute(final String internalName) throws ODataJPAModelException { + if (edmStructuralType == null) + lazyBuildEdmItem(); + Optional result = Optional.ofNullable(declaredPropertiesList.get(internalName)); + if (!result.isPresent() && getBaseType() != null) result = getBaseType().getAttribute(internalName); - else if (result != null && ((IntermediateModelElement) result).ignore()) - return null; + else if (result.isPresent() && ((IntermediateModelElement) result.get()).ignore()) + return Optional.empty(); return result; } + @Override + public Optional getAttribute(final UriResourceProperty uriResourceItem) throws ODataJPAModelException { + if (edmStructuralType == null) + lazyBuildEdmItem(); + final String externalName = uriResourceItem.getProperty().getName(); + for (final Entry property : declaredPropertiesList.entrySet()) { + if (property.getValue().getExternalName().equals(externalName)) + return Optional.of(property.getValue()); + } + if (getBaseType() != null) + return getBaseType().getAttribute(uriResourceItem); + return Optional.empty(); + } + @Override public List getAttributes() throws ODataJPAModelException { - lazyBuildEdmItem(); - final List result = new ArrayList(); - for (final String propertyKey : declaredPropertiesList.keySet()) { - final IntermediateProperty attribute = declaredPropertiesList.get(propertyKey); + if (edmStructuralType == null) + lazyBuildEdmItem(); + final List result = new ArrayList<>(); + for (final Entry property : declaredPropertiesList.entrySet()) { + final IntermediateProperty attribute = property.getValue(); if (!attribute.ignore()) result.add(attribute); } @@ -109,53 +147,94 @@ public List getAttributes() throws ODataJPAModelException { } @Override - public JPAAssociationPath getDeclaredAssociation(final JPAAssociationPath associationPath) - throws ODataJPAModelException { + public List getCollectionAttributesPath() throws ODataJPAModelException { + lazyBuildCompletePathMap(); + final List pathList = new ArrayList<>(); + for (final Entry path : resolvedPathMap.entrySet()) { + if (!path.getValue().ignore() && path.getValue().getLeaf() instanceof JPACollectionAttribute) + pathList.add(path.getValue()); + } + for (final Entry path : intermediatePathMap.entrySet()) { + if (!path.getValue().ignore() && path.getValue().getLeaf() instanceof JPACollectionAttribute) + pathList.add(path.getValue()); + } + return pathList; + } + + @Override + public List getDeclaredAssociations() throws ODataJPAModelException { lazyBuildCompleteAssociationPathMap(); - if (resolvedAssociationPathMap.containsKey(associationPath.getAlias())) - return resolvedAssociationPathMap.get(associationPath.getAlias()); + List result = new ArrayList<>(); + for (final Entry naviProperty : declaredNaviPropertiesList.entrySet()) + result.add(naviProperty.getValue()); final IntermediateStructuredType baseType = getBaseType(); if (baseType != null) - return baseType.getDeclaredAssociation(associationPath); - return null; + result.addAll(baseType.getDeclaredAssociations()); + return result; } @Override - public JPAAssociationPath getDeclaredAssociation(final String externalName) throws ODataJPAModelException { - lazyBuildCompleteAssociationPathMap(); - for (final String internalName : declaredNaviPropertiesList.keySet()) { - if (externalName.equals(declaredNaviPropertiesList.get(internalName).getExternalName())) - return resolvedAssociationPathMap.get(externalName); + public List getDeclaredAttributes() throws ODataJPAModelException { + if (edmStructuralType == null) + lazyBuildEdmItem(); + List result = new ArrayList<>(); + for (final Entry property : declaredPropertiesList.entrySet()) { + result.add(property.getValue()); } final IntermediateStructuredType baseType = getBaseType(); if (baseType != null) - return baseType.getDeclaredAssociation(externalName); - return null; + result.addAll(baseType.getDeclaredAttributes()); + return result; + } + + @Override + public Optional getDeclaredAttribute(@Nonnull final String internalName) throws ODataJPAModelException { + if (edmStructuralType == null) + lazyBuildEdmItem(); + Optional result = Optional.ofNullable(declaredPropertiesList.get(internalName)); + if (!result.isPresent() && getBaseType() != null) + result = getBaseType().getAttribute(internalName); + return result; + } + + @Override + public List getDeclaredCollectionAttributes() throws ODataJPAModelException { + if (edmStructuralType == null) + lazyBuildEdmItem(); + List result = new ArrayList<>(); + for (final Entry property : declaredPropertiesList.entrySet()) { + if (property.getValue().isCollection()) + result.add((JPACollectionAttribute) property.getValue()); + } + final IntermediateStructuredType baseType = getBaseType(); + if (baseType != null) + result.addAll(baseType.getDeclaredCollectionAttributes()); + return result; } @Override public JPAPath getPath(final String externalName) throws ODataJPAModelException { - lazyBuildCompletePathMap(); - JPAPath targetPath = resolvedPathMap.get(externalName); - if (targetPath == null) - targetPath = intermediatePathMap.get(externalName); - if (targetPath == null || targetPath.ignore()) - return null; - return targetPath; + return getPath(externalName, true); } @Override public List getPathList() throws ODataJPAModelException { lazyBuildCompletePathMap(); - final List pathList = new ArrayList(); - for (final String externalName : resolvedPathMap.keySet()) { - if (!resolvedPathMap.get(externalName).ignore()) - pathList.add(resolvedPathMap.get(externalName)); + final List pathList = new ArrayList<>(); + for (final Entry path : resolvedPathMap.entrySet()) { + if (!path.getValue().ignore()) + pathList.add(path.getValue()); } return pathList; } + @Override + public List getProtections() throws ODataJPAModelException { + lazyBuildCompleteProtectionList(); + return protectedAttributes; + } + @Override public Class getTypeClass() { return this.jpaManagedType.getJavaType(); @@ -172,32 +251,31 @@ protected void buildNaviPropertyList() throws ODataJPAModelException { final PersistentAttributeType attributeType = jpaAttribute.getPersistentAttributeType(); switch (attributeType) { - case BASIC: - case EMBEDDED: - break; - case ONE_TO_MANY: - case ONE_TO_ONE: - case MANY_TO_MANY: - case MANY_TO_ONE: - if (jpaAttribute.getJavaMember() instanceof AnnotatedElement) { - final EdmDescriptionAssoziation jpaDescription = ((AnnotatedElement) jpaAttribute.getJavaMember()) - .getAnnotation( - EdmDescriptionAssoziation.class); - if (jpaDescription != null) { - final IntermediateDescriptionProperty descProperty = new IntermediateDescriptionProperty(nameBuilder, - jpaAttribute, schema); - declaredPropertiesList.put(descProperty.internalName, descProperty); - break; + case BASIC: + case EMBEDDED: + case ELEMENT_COLLECTION: + break; + case ONE_TO_MANY: + case ONE_TO_ONE: + case MANY_TO_MANY: + case MANY_TO_ONE: + if (jpaAttribute.getJavaMember() instanceof AnnotatedElement) { + final EdmDescriptionAssoziation jpaDescription = ((AnnotatedElement) jpaAttribute.getJavaMember()) + .getAnnotation(EdmDescriptionAssoziation.class); + if (jpaDescription != null) { + final IntermediateDescriptionProperty descProperty = new IntermediateDescriptionProperty(nameBuilder, + jpaAttribute, this, schema); + declaredPropertiesList.put(descProperty.internalName, descProperty); + break; + } } - } - final IntermediateNavigationProperty navProp = new IntermediateNavigationProperty(nameBuilder, this, - jpaAttribute, - schema); - declaredNaviPropertiesList.put(navProp.internalName, navProp); - break; - default: - throw new ODataJPAModelException(ODataJPAModelException.MessageKeys.NOT_SUPPORTED_ATTRIBUTE_TYPE, - attributeType.name()); + final IntermediateNavigationProperty navProp = new IntermediateNavigationProperty(nameBuilder, this, + jpaAttribute, schema); + declaredNaviPropertiesList.put(navProp.internalName, navProp); + break; + default: + throw new ODataJPAModelException(ODataJPAModelException.MessageKeys.NOT_SUPPORTED_ATTRIBUTE_TYPE, + attributeType.name()); } } } @@ -208,26 +286,73 @@ protected void buildPropertyList() throws ODataJPAModelException { final PersistentAttributeType attributeType = jpaAttribute.getPersistentAttributeType(); switch (attributeType) { - case BASIC: - case EMBEDDED: - if (jpaAttribute instanceof SingularAttribute - && ((SingularAttribute) jpaAttribute).isId() - && attributeType == PersistentAttributeType.EMBEDDED) { - final IntermediateProperty property = new IntermediateEmbeddedIdProperty(nameBuilder, jpaAttribute, schema); + case BASIC: + case EMBEDDED: + if (jpaAttribute instanceof SingularAttribute + && ((SingularAttribute) jpaAttribute).isId() + && attributeType == PersistentAttributeType.EMBEDDED) { + final IntermediateSimpleProperty property = new IntermediateEmbeddedIdProperty(nameBuilder, jpaAttribute, + schema); + declaredPropertiesList.put(property.internalName, property); + } else { + final IntermediateSimpleProperty property = new IntermediateSimpleProperty(nameBuilder, jpaAttribute, + schema); + declaredPropertiesList.put(property.internalName, property); + } + break; + case ELEMENT_COLLECTION: + final IntermediateCollectionProperty property = new IntermediateCollectionProperty(nameBuilder, + (PluralAttribute) jpaAttribute, schema, this); declaredPropertiesList.put(property.internalName, property); + break; + case ONE_TO_MANY: + case ONE_TO_ONE: + case MANY_TO_MANY: + case MANY_TO_ONE: + break; + default: + // Attribute Type '%1$s' as of now not supported + throw new ODataJPAModelException(ODataJPAModelException.MessageKeys.NOT_SUPPORTED_ATTRIBUTE_TYPE, + attributeType.name()); + } + } + } + + /** + * The managed type (e.g. via jpaManagedType.getDeclaredAttributes()) does not provide transient field. Therefore they + * have to be simulated + * @throws ODataJPAModelException + */ + protected void addTransientProperties() throws ODataJPAModelException { + final Field[] fields = jpaManagedType.getJavaType().getDeclaredFields(); + for (final Field jpaAttribute : fields) { + final EdmTransient t = jpaAttribute.getAnnotation(EdmTransient.class); + if (t != null) { + IntermediateProperty property = null; + if (Collection.class.isAssignableFrom(jpaAttribute.getType())) { + property = new IntermediateCollectionProperty(nameBuilder, + new TransientPluralAttribute<>(jpaManagedType, jpaAttribute, schema), schema, this); } else { - final IntermediateProperty property = new IntermediateProperty(nameBuilder, jpaAttribute, schema); - declaredPropertiesList.put(property.internalName, property); + property = new IntermediateSimpleProperty(nameBuilder, + new TransientSingularAttribute<>(jpaManagedType, jpaAttribute), schema); + + } + declaredPropertiesList.put(property.internalName, property); + } + } + } + + /** + * @throws ODataJPAModelException + * + */ + protected void checkPropertyConsistancy() throws ODataJPAModelException { + + for (final Entry property : declaredPropertiesList.entrySet()) { + if (property.getValue().isTransient()) { + for (final String internalPath : property.getValue().getRequiredProperties()) { + validateInternalPath(property.getKey(), internalPath); } - break; - case ONE_TO_MANY: - case ONE_TO_ONE: - case MANY_TO_MANY: - case MANY_TO_ONE: - break; - default: - throw new ODataJPAModelException(ODataJPAModelException.MessageKeys.NOT_SUPPORTED_ATTRIBUTE_TYPE, - attributeType.name()); } } } @@ -236,23 +361,24 @@ protected FullQualifiedName determineBaseType() throws ODataJPAModelException { final IntermediateStructuredType baseEntity = getBaseType(); if (baseEntity != null && !baseEntity.isAbstract() && isAbstract()) + // Abstract entity type '%1$s' must not inherit from a non-abstract entity type '%2$s' throw new ODataJPAModelException(ODataJPAModelException.MessageKeys.INHERITANCE_NOT_ALLOWED, this.internalName, baseEntity.internalName); - return baseEntity != null ? nameBuilder.buildFQN(baseEntity.getExternalName()) : null; + return baseEntity != null ? buildFQN(baseEntity.getExternalName()) : null; + } + + protected boolean determineHasStream() throws ODataJPAModelException { + return getStreamProperty() != null; } protected void determineIgnore() { - final EdmIgnore jpaIgnore = ((AnnotatedElement) this.jpaManagedType.getJavaType()).getAnnotation(EdmIgnore.class); + final EdmIgnore jpaIgnore = this.jpaManagedType.getJavaType().getAnnotation(EdmIgnore.class); if (jpaIgnore != null) { this.setIgnore(true); } } - protected boolean determineHasStream() throws ODataJPAModelException { - return getStreamProperty() == null ? false : true; - } - - protected IntermediateStructuredType getBaseType() throws ODataJPAModelException { + protected IntermediateStructuredType getBaseType() { final Class baseType = jpaManagedType.getJavaType().getSuperclass(); if (baseType != null) { final IntermediateStructuredType baseEntity = schema.getEntityType(baseType); @@ -262,17 +388,19 @@ protected IntermediateStructuredType getBaseType() throws ODataJPAModelException return null; } - protected IntermediateProperty getStreamProperty() throws ODataJPAModelException { + protected IntermediateSimpleProperty getStreamProperty() throws ODataJPAModelException { int count = 0; - IntermediateProperty result = null; - for (final String internalName : declaredPropertiesList.keySet()) { - if (declaredPropertiesList.get(internalName).isStream()) { + IntermediateSimpleProperty result = null; + for (final Entry property : declaredPropertiesList.entrySet()) { + // Edm.Stream, or a type definition whose underlying type is Edm.Stream, cannot be used in collections or for + // non-binding parameters to functions or actions. + if (property.getValue().isStream()) { count += 1; - result = declaredPropertiesList.get(internalName); + result = (IntermediateSimpleProperty) property.getValue(); } } if (this.getBaseType() != null) { - final IntermediateProperty superResult = getBaseType().getStreamProperty(); + final IntermediateSimpleProperty superResult = getBaseType().getStreamProperty(); if (superResult != null) { count += 1; result = superResult; @@ -286,10 +414,11 @@ protected IntermediateProperty getStreamProperty() throws ODataJPAModelException } List getAssociations() throws ODataJPAModelException { - lazyBuildEdmItem(); - final List jpaAttributes = new ArrayList(); - for (final String internalName : declaredNaviPropertiesList.keySet()) { - final IntermediateNavigationProperty property = declaredNaviPropertiesList.get(internalName); + if (edmStructuralType == null) + lazyBuildEdmItem(); + final List jpaAttributes = new ArrayList<>(); + for (final Entry naviProperty : declaredNaviPropertiesList.entrySet()) { + final IntermediateNavigationProperty property = naviProperty.getValue(); if (!property.ignore()) jpaAttributes.add(property); } @@ -309,15 +438,14 @@ JPAAssociationAttribute getCorrespondingAssiciation(final IntermediateStructured @Override abstract CsdlStructuralType getEdmItem() throws ODataJPAModelException; - Map getIntermediatePathMap() throws ODataJPAModelException { + Map getIntermediatePathMap() throws ODataJPAModelException { lazyBuildCompletePathMap(); return intermediatePathMap; } - List getJoinColumns(final IntermediateStructuredType sourceType, - final String relationshipName) { + List getJoinColumns(final String relationshipName) { - final List result = new ArrayList(); + final List result = new ArrayList<>(); final Attribute jpaAttribute = jpaManagedType.getAttribute(relationshipName); if (jpaAttribute != null) { @@ -346,10 +474,10 @@ List getJoinColumns(final IntermediateStructuredType sou */ JPAPath getPathByDBField(final String dbFieldName) throws ODataJPAModelException { lazyBuildCompletePathMap(); - for (final String internalName : resolvedPathMap.keySet()) { - final JPAPath property = resolvedPathMap.get(internalName); - if (property.getDBFieldName().equals(dbFieldName)) - return property; + + for (final Entry path : resolvedPathMap.entrySet()) { + if (path.getValue().getDBFieldName().equals(dbFieldName)) + return path.getValue(); } return null; } @@ -361,7 +489,8 @@ JPAPath getPathByDBField(final String dbFieldName) throws ODataJPAModelException * @throws ODataJPAModelException */ IntermediateProperty getProperty(final String internalName) throws ODataJPAModelException { - lazyBuildEdmItem(); + if (edmStructuralType == null) + lazyBuildEdmItem(); IntermediateProperty result = declaredPropertiesList.get(internalName); if (result == null && getBaseType() != null) result = getBaseType().getProperty(internalName); @@ -377,15 +506,17 @@ IntermediateProperty getProperty(final String internalName) throws ODataJPAModel */ IntermediateModelElement getPropertyByDBField(final String dbFieldName) throws ODataJPAModelException { buildPropertyList(); - for (final String internalName : declaredPropertiesList.keySet()) { - final IntermediateProperty property = declaredPropertiesList.get(internalName); + for (final Entry declaredProperty : declaredPropertiesList.entrySet()) { + final IntermediateProperty property = declaredProperty.getValue(); if (property.isComplex()) { - IntermediateProperty embeddedProperty = (IntermediateProperty) ((IntermediateStructuredType) property - .getStructuredType()).getPropertyByDBField(dbFieldName); + IntermediateProperty embeddedProperty = + (IntermediateProperty) ((IntermediateStructuredType) property + .getStructuredType()).getPropertyByDBField(dbFieldName); if (embeddedProperty != null && embeddedProperty.getDBFieldName().equals(dbFieldName)) return embeddedProperty; - } else if (property.getDBFieldName().equals(dbFieldName)) + } else if (property.getDBFieldName().equals(dbFieldName)) { return property; + } } if (getBaseType() != null) return getBaseType().getPropertyByDBField(dbFieldName); @@ -397,6 +528,10 @@ Map getResolvedPathMap() throws ODataJPAModelException { return resolvedPathMap; } + private String buildPath(final String pathRoot, final String pathElement) { + return pathRoot + JPAPath.PATH_SEPERATOR + pathElement; + } + private String determineDBFieldName(final IntermediateModelElement property, final JPAPath jpaPath) { final Attribute jpaAttribute = jpaManagedType.getAttribute(property.getInternalName()); if (jpaAttribute.getJavaMember() instanceof AnnotatedElement) { @@ -409,9 +544,8 @@ private String determineDBFieldName(final IntermediateModelElement property, fin } } else { final AttributeOverride overwrite = a.getAnnotation(AttributeOverride.class); - if (overwrite != null) { - if (overwrite.name().equals(jpaPath.getLeaf().getInternalName())) - return overwrite.column().name(); + if (overwrite != null && overwrite.name().equals(jpaPath.getLeaf().getInternalName())) { + return overwrite.column().name(); } } } @@ -420,7 +554,7 @@ private String determineDBFieldName(final IntermediateModelElement property, fin private List determineJoinColumns(final IntermediateModelElement property, final JPAAssociationPath association) { - final List result = new ArrayList(); + final List result = new ArrayList<>(); final Attribute jpaAttribute = jpaManagedType.getAttribute(property.getInternalName()); if (jpaAttribute.getJavaMember() instanceof AnnotatedElement) { @@ -436,31 +570,25 @@ private List determineJoinColumns(final IntermediateMode } } else { final AssociationOverride overwrite = a.getAnnotation(AssociationOverride.class); - if (overwrite != null) { - if (overwrite.name().equals(association.getLeaf().getInternalName())) { - for (final JoinColumn column : overwrite.joinColumns()) - result.add(new IntermediateJoinColumn(column)); - } + if (overwrite != null && overwrite.name().equals(association.getLeaf().getInternalName())) { + for (final JoinColumn column : overwrite.joinColumns()) + result.add(new IntermediateJoinColumn(column)); } } } } return result; + } private Attribute findCorrespondingAssociation(final IntermediateStructuredType sourceType, final String sourceRelationshipName) { - Class targetClass = null; for (final Attribute jpaAttribute : jpaManagedType.getAttributes()) { if (jpaAttribute.getPersistentAttributeType() != null && jpaAttribute.getJavaMember() instanceof AnnotatedElement && !sourceRelationshipName.equals(IntNameBuilder.buildAssociationName(jpaAttribute))) { - if (jpaAttribute.isCollection()) { - targetClass = ((PluralAttribute) jpaAttribute).getElementType().getJavaType(); - } else { - targetClass = jpaAttribute.getJavaType(); - } + final Class targetClass = determineTargetClass(jpaAttribute); if (targetClass.equals(sourceType.getTypeClass())) { final OneToMany cardinalityOtM = ((AnnotatedElement) jpaAttribute.getJavaMember()).getAnnotation( OneToMany.class); @@ -474,6 +602,27 @@ private List determineJoinColumns(final IntermediateMode return null; } + private Class determineTargetClass(final Attribute jpaAttribute) { + Class targetClass; + if (jpaAttribute.isCollection()) { + targetClass = ((PluralAttribute) jpaAttribute).getElementType().getJavaType(); + } else { + targetClass = jpaAttribute.getJavaType(); + } + return targetClass; + } + + @Override + public final JPAPath getPath(final String externalName, final boolean respectIgnore) throws ODataJPAModelException { + lazyBuildCompletePathMap(); + JPAPath targetPath = resolvedPathMap.get(externalName); + if (targetPath == null) + targetPath = intermediatePathMap.get(externalName); + if (targetPath == null || targetPath.ignore() && respectIgnore) + return null; + return targetPath; + } + private void lazyBuildCompleteAssociationPathMap() throws ODataJPAModelException { JPAAssociationPathImpl associationPath; lazyBuildCompletePathMap(); @@ -484,16 +633,16 @@ private void lazyBuildCompleteAssociationPathMap() throws ODataJPAModelException resolvedAssociationPathMap.put(associationPath.getAlias(), associationPath); } - for (final String key : this.intermediatePathMap.keySet()) { - final JPAPath attributePath = this.intermediatePathMap.get(key); + for (final Entry entity : this.intermediatePathMap.entrySet()) { + final JPAPath attributePath = entity.getValue(); if (attributePath.getPath().size() == 1) { // Only direct attributes final IntermediateProperty property = (IntermediateProperty) attributePath.getLeaf(); final IntermediateStructuredType is = (IntermediateStructuredType) property.getStructuredType(); for (final JPAAssociationPath association : is.getAssociationPathList()) { - associationPath = new JPAAssociationPathImpl(nameBuilder, association, - this, determineJoinColumns(property, association), property); + associationPath = new JPAAssociationPathImpl(association, this, determineJoinColumns(property, association), + property); resolvedAssociationPathMap.put(associationPath.getAlias(), associationPath); } } @@ -503,38 +652,46 @@ private void lazyBuildCompleteAssociationPathMap() throws ODataJPAModelException private void lazyBuildCompletePathMap() throws ODataJPAModelException { ArrayList pathList; - - lazyBuildEdmItem(); + if (edmStructuralType == null) + lazyBuildEdmItem(); if (resolvedPathMap.size() == 0) { - for (final String internalName : declaredPropertiesList.keySet()) { - final IntermediateProperty property = declaredPropertiesList.get(internalName); - // if (!property.ignore()) { + for (final Entry propertyEntity : declaredPropertiesList.entrySet()) { + final IntermediateProperty property = propertyEntity.getValue(); if (property.isComplex()) { intermediatePathMap.put(property.getExternalName(), new JPAPathImpl(property.getExternalName(), null, property)); - final Map intermediatePath = ((IntermediateStructuredType) property + final Map intermediatePath = ((IntermediateStructuredType) property .getStructuredType()).getIntermediatePathMap(); - for (final String externalName : intermediatePath.keySet()) { - pathList = new ArrayList(intermediatePath.get(externalName).getPath()); + for (final Entry path : intermediatePath.entrySet()) { + pathList = new ArrayList<>(); + if (path.getValue().getLeaf() instanceof IntermediateCollectionProperty) { + if (path.getValue().getPath().size() > 1) + pathList.addAll(path.getValue().getPath().subList(0, path.getValue().getPath().size() - 1)); + pathList.add(new IntermediateCollectionProperty((IntermediateCollectionProperty) path.getValue() + .getLeaf(), this, property)); + } else { + pathList.addAll(path.getValue().getPath()); + } pathList.add(0, property); - intermediatePathMap.put(nameBuilder.buildPath(property.getExternalName(), externalName), - new JPAPathImpl(nameBuilder.buildPath(property.getExternalName(), - externalName), null, pathList)); + final JPAPath newPath = new JPAPathImpl(buildPath(property.getExternalName(), path.getKey()), null, + pathList); + intermediatePathMap.put(newPath.getAlias(), newPath); } final Map resolvedPath = ((IntermediateStructuredType) property .getStructuredType()).getResolvedPathMap(); - for (final String externalName : resolvedPath.keySet()) { - pathList = new ArrayList(resolvedPath.get(externalName).getPath()); + for (final Entry path : resolvedPath.entrySet()) { + pathList = new ArrayList<>(path.getValue().getPath()); pathList.add(0, property); JPAPathImpl newPath; if (property.isKey()) { - newPath = new JPAPathImpl(externalName, determineDBFieldName(property, resolvedPath.get(externalName)), + newPath = new JPAPathImpl(path.getKey(), determineDBFieldName(property, resolvedPath.get(path.getKey())), pathList); } else { - newPath = new JPAPathImpl(nameBuilder.buildPath(property.getExternalName(), externalName), - determineDBFieldName(property, resolvedPath.get(externalName)), pathList); + + newPath = new JPAPathImpl(buildPath(property.getExternalName(), path.getKey()), + determineDBFieldName(property, path.getValue()), rebuildPathList(pathList)); } resolvedPathMap.put(newPath.getAlias(), newPath); @@ -544,13 +701,315 @@ private void lazyBuildCompletePathMap() throws ODataJPAModelException { .getDBFieldName(), property)); } } + final IntermediateStructuredType baseType = getBaseType(); + if (baseType != null) { + resolvedPathMap.putAll(baseType.getResolvedPathMap()); + intermediatePathMap.putAll(baseType.getIntermediatePathMap()); + } } - final IntermediateStructuredType baseType = getBaseType(); - if (baseType != null) { - resolvedPathMap.putAll(baseType.getResolvedPathMap()); - intermediatePathMap.putAll(baseType.getIntermediatePathMap()); + } + + private void lazyBuildCompleteProtectionList() throws ODataJPAModelException { + if (protectedAttributes == null) { + if (edmStructuralType == null) + lazyBuildEdmItem(); + this.protectedAttributes = new ArrayList<>(); + for (JPAAttribute attribute : getDeclaredAttributes()) { + if (attribute.hasProtection()) { + if (attribute.isComplex()) { + for (final String claimName : attribute.getProtectionClaimNames()) { + for (final String pathName : attribute.getProtectionPath(claimName)) { + final JPAPath path = this.getPath(pathName, false); + if (path == null) // Annotation EdmProtctedBy found at '%2$s' of '%1$s', but the given 'path' '%3$s'... + throw new ODataJPAModelException(COMPLEX_PROPERTY_WRONG_PROTECTION_PATH, attribute.getInternalName(), + this.getTypeClass().getSimpleName(), pathName); + protectedAttributes.add(new ProtectionInfo(path, claimName, attribute)); + } + } + } else { + for (final String claimName : attribute.getProtectionClaimNames()) { + protectedAttributes.add(new ProtectionInfo(this.getPath(attribute.getExternalName(), false), claimName, + attribute)); + } + } + } else if (attribute.isComplex()) { // Protection at attribute overrides protection within complex + for (final JPAProtectionInfo info : attribute.getStructuredType().getProtections()) { + // Copy and extend path + final String pathName = attribute.getExternalName() + JPAPath.PATH_SEPERATOR + info.getPath().getAlias(); + final JPAPath path = this.getPath(pathName, false); + protectedAttributes.add(new ProtectionInfo(path, info)); + } + } + } + } + } + + private List rebuildPathList(final List pathList) throws ODataJPAModelException { + + final StringBuilder path = new StringBuilder(); + for (int i = 0; i < pathList.size() - 1; i++) { + path.append(pathList.get(i).getExternalName()); + path.append(JPAPath.PATH_SEPERATOR); + } + path.deleteCharAt(path.length() - 1); + final JPAPath parentPath = intermediatePathMap.get(path.toString()); + if (parentPath == null) + return pathList; + else { + final List pathElements = new ArrayList<>(parentPath.getPath()); + JPAElement leaf = pathList.get(pathList.size() - 1); + if (leaf instanceof IntermediateCollectionProperty + && pathList.size() > 1 + && ((IntermediateCollectionProperty) leaf).getSourceType() != this) + leaf = new IntermediateCollectionProperty((IntermediateCollectionProperty) leaf, this, + (IntermediateProperty) pathList.get(0)); // pathList.size() - 2 + pathElements.add(leaf); + return pathElements; + } + } + + private void validateInternalPath(final String propertyName, final String internalPath) + throws ODataJPAModelException { + + IntermediateStructuredType hop = this; + for (final String pathPart : internalPath.split(JPAPath.PATH_SEPERATOR)) { + final JPAAttribute required = hop.getAttribute(pathPart).orElseThrow( + // The transient attribute '%1$s' of class '%2$s' requires '%3$s', which is not known + () -> new ODataJPAModelException(PROPERTY_REQUIRED_UNKNOWN, propertyName, getInternalName(), internalName)); + if (required.isComplex()) + hop = (IntermediateStructuredType) required.getStructuredType(); + } + } + + protected abstract static class TransientAttribute implements Attribute { + protected final ManagedType parent; + protected final Field attribute; + + TransientAttribute(final ManagedType parent, Field attribute) { + super(); + this.parent = parent; + this.attribute = attribute; + } + + @Override + public ManagedType getDeclaringType() { + return parent; + } + + @Override + public Member getJavaMember() { + return attribute; + } + + @SuppressWarnings("unchecked") + @Override + public Class getJavaType() { + return (Class) attribute.getType(); + } + + @Override + public String getName() { + return attribute.getName(); + } + + @Override + public boolean isAssociation() { + return false; + } + } + + protected static class TransientPluralAttribute extends TransientAttribute + implements PluralAttribute { + + private final TransientRowType type; + + /** + * @param parent + * @param attribute + */ + TransientPluralAttribute(final ManagedType parent, final Field attribute, final IntermediateSchema schema) { + super(parent, attribute); + this.type = new TransientRowType<>(attribute, schema); + } + + @Override + public BindableType getBindableType() { + return null; } - // } + @Override + public Class getBindableJavaType() { + return null; + } + + @Override + public CollectionType getCollectionType() { + if (Map.class.isAssignableFrom(attribute.getType())) + return CollectionType.MAP; + if (Set.class.isAssignableFrom(attribute.getType())) + return CollectionType.SET; + if (List.class.isAssignableFrom(attribute.getType())) + return CollectionType.LIST; + return CollectionType.COLLECTION; + } + + @SuppressWarnings("unchecked") + @Override + public Type getElementType() { + return (Type) type; + } + + @Override + public PersistentAttributeType getPersistentAttributeType() { + return PersistentAttributeType.ELEMENT_COLLECTION; + } + + @Override + public boolean isCollection() { + return true; + } + } + + protected static class TransientRowType implements Type { + + private final Class rowType; + private final PersistenceType persistenceType; + + /** + * @param attribute + */ + public TransientRowType(final Field attribute, final IntermediateSchema schema) { + if (attribute.getGenericType() instanceof ParameterizedType) { + final java.lang.reflect.Type[] attributes = ((ParameterizedType) attribute.getGenericType()) + .getActualTypeArguments(); + this.rowType = (Class) attributes[attributes.length - 1]; + } else { + this.rowType = attribute.getType(); + } + this.persistenceType = determinePersistanceType(schema); + + } + + @Override + public PersistenceType getPersistenceType() { + return persistenceType; + } + + @SuppressWarnings("unchecked") + @Override + public Class getJavaType() { + return (Class) rowType; + } + + /** + * @param schema + * @return + */ + private PersistenceType determinePersistanceType(IntermediateSchema schema) { + return schema.getStructuredType(rowType) == null ? PersistenceType.BASIC : PersistenceType.EMBEDDABLE; + } + + } + + protected static class TransientSingularAttribute extends TransientAttribute + implements SingularAttribute { + + TransientSingularAttribute(final ManagedType parent, Field attribute) { + super(parent, attribute); + } + + @Override + public PersistentAttributeType getPersistentAttributeType() { + return PersistentAttributeType.BASIC; + } + + @Override + public boolean isCollection() { + return false; + } + + @Override + public BindableType getBindableType() { + return null; + } + + @Override + public Class getBindableJavaType() { + return null; + } + + @Override + public boolean isId() { + final Id id = this.attribute.getAnnotation(Id.class); + return id != null; + } + + @Override + public boolean isVersion() { + final Version version = this.attribute.getAnnotation(Version.class); + return version != null; + } + + @Override + public boolean isOptional() { + final Column column = this.attribute.getAnnotation(Column.class); + return column == null || column.nullable(); + } + + @Override + public Type getType() { + return null; + } + } + + private static class ProtectionInfo implements JPAProtectionInfo { + private final JPAPath pathToAttribute; + private final String claimName; + private final boolean wildcardSupported; + + /** + * Copy with a new path. This can be used for nested structured types + * @param path + * @param info + */ + public ProtectionInfo(JPAPath path, JPAProtectionInfo info) { + this.pathToAttribute = path; + this.claimName = info.getClaimName(); + this.wildcardSupported = info.supportsWildcards(); + } + + public ProtectionInfo(final JPAPath path, final String claimName, final JPAAttribute attribute) { + this.pathToAttribute = path; + this.claimName = claimName; + this.wildcardSupported = ((IntermediateProperty) attribute).protectionWithWildcard(claimName, path.getLeaf() + .getType()); + + } + + @Override + public JPAAttribute getAttribute() { + return pathToAttribute.getLeaf(); + } + + @Override + public String getClaimName() { + return claimName; + } + + @Override + public JPAPath getPath() { + return pathToAttribute; + } + + @Override + public boolean supportsWildcards() { + return wildcardSupported; + } + + @Override + public String toString() { + return "ProtectionInfo [pathToAttribute=" + pathToAttribute.getAlias() + ", claimName=" + claimName + + ", wildcardSupported=" + wildcardSupported + "]"; + } } } \ No newline at end of file diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPAAssociationPathImpl.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPAAssociationPathImpl.java index d17d3d5f8..2db49914c 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPAAssociationPathImpl.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPAAssociationPathImpl.java @@ -4,35 +4,55 @@ import java.util.Collections; import java.util.List; +import javax.annotation.Nonnull; import javax.persistence.metamodel.Attribute.PersistentAttributeType; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAAssociationAttribute; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAAssociationPath; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAAttribute; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAElement; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAJoinTable; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAOnConditionItem; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAPath; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAStructuredType; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; final class JPAAssociationPathImpl implements JPAAssociationPath { - final private String alias; - final private List pathElements; - final private IntermediateStructuredType sourceType; - final private IntermediateStructuredType targetType; + private final String alias; + private final List pathElements; + private final IntermediateStructuredType sourceType; + private final IntermediateStructuredType targetType; private final List joinColumns; private final PersistentAttributeType cardinality; private final boolean isCollection; private final JPAAssociationAttribute partner; + private final JPAJoinTable joinTable; - JPAAssociationPathImpl(final JPAEdmNameBuilder namebuilder, final JPAAssociationPath associationPath, - final IntermediateStructuredType source, final List joinColumns, - final JPAAttribute attribute) { + JPAAssociationPathImpl(final IntermediateNavigationProperty association, + final IntermediateStructuredType source) throws ODataJPAModelException { + + final List pathElementsBuffer = new ArrayList<>(); + pathElementsBuffer.add(association); + + alias = association.getExternalName(); + this.sourceType = source; + this.targetType = (IntermediateStructuredType) association.getTargetEntity(); + this.joinColumns = association.getJoinColumns(); + this.pathElements = Collections.unmodifiableList(pathElementsBuffer); + this.cardinality = association.getJoinCardinality(); + this.isCollection = association.isCollection(); + this.partner = association.getPartner(); + this.joinTable = association.getJoinTable(); + } + + JPAAssociationPathImpl(final JPAAssociationPath associationPath, final IntermediateStructuredType source, + final List joinColumns, final JPAAttribute attribute) { - final List pathElementsBuffer = new ArrayList(); + final List pathElementsBuffer = new ArrayList<>(); pathElementsBuffer.add(attribute); pathElementsBuffer.addAll(associationPath.getPath()); - alias = namebuilder.buildNaviPropertyBindingName(associationPath, attribute); + alias = buildNaviPropertyBindingName(associationPath, attribute); this.sourceType = source; this.targetType = (IntermediateStructuredType) associationPath.getTargetType(); if (joinColumns.isEmpty()) @@ -43,30 +63,30 @@ final class JPAAssociationPathImpl implements JPAAssociationPath { this.cardinality = ((JPAAssociationPathImpl) associationPath).getCardinality(); this.isCollection = associationPath.isCollection(); this.partner = associationPath.getPartner(); + this.joinTable = associationPath.getJoinTable(); } - JPAAssociationPathImpl(final IntermediateNavigationProperty association, - final IntermediateStructuredType source) throws ODataJPAModelException { - - final List pathElementsBuffer = new ArrayList(); - pathElementsBuffer.add(association); + /** + * Collection Properties + * @param collectionProperty + * @param source + * @param path + * @param joinColumns + * @throws ODataJPAModelException + */ + public JPAAssociationPathImpl(final IntermediateCollectionProperty collectionProperty, + final IntermediateStructuredType source, final JPAPath path, final List joinColumns) + throws ODataJPAModelException { - alias = association.getExternalName(); + alias = path.getAlias(); this.sourceType = source; - this.targetType = (IntermediateStructuredType) association.getTargetEntity(); - this.joinColumns = association.getJoinColumns(); - this.pathElements = Collections.unmodifiableList(pathElementsBuffer); - this.cardinality = association.getJoinCardinality(); - this.isCollection = association.isCollection(); - this.partner = association.getPartner(); - } - - private List getJoinColumns() { - return joinColumns; - } - - private PersistentAttributeType getCardinality() { - return cardinality; + this.targetType = null; + this.joinColumns = joinColumns; + this.pathElements = path.getPath(); + this.cardinality = PersistentAttributeType.ONE_TO_MANY; + this.isCollection = true; + this.partner = null; + this.joinTable = collectionProperty.getJoinTable(); } /* @@ -79,6 +99,16 @@ public String getAlias() { return alias; } + @Override + public List getInverseLeftJoinColumnsList() throws ODataJPAModelException { + final List result = new ArrayList<>(); + if (joinTable instanceof IntermediateJoinTable) + for (final IntermediateJoinColumn column : ((IntermediateJoinTable) joinTable).buildInverseJoinColumns()) { + result.add(targetType.getPathByDBField(column.getName())); + } + return result; + } + /* * (non-Javadoc) * @@ -86,20 +116,25 @@ public String getAlias() { */ @Override public List getJoinColumnsList() throws ODataJPAModelException { - final List joinColumns = new ArrayList(); + final List result = new ArrayList<>(); for (final IntermediateJoinColumn column : this.joinColumns) { // ManyToOne if (cardinality == PersistentAttributeType.MANY_TO_ONE || cardinality == PersistentAttributeType.MANY_TO_MANY) - joinColumns.add(new JPAOnConditionItemImpl( + result.add(new JPAOnConditionItemImpl( sourceType.getPathByDBField(column.getName()), targetType.getPathByDBField(column.getReferencedColumnName()))); else - joinColumns.add(new JPAOnConditionItemImpl( + result.add(new JPAOnConditionItemImpl( sourceType.getPathByDBField(column.getReferencedColumnName()), targetType.getPathByDBField(column.getName()))); } - return joinColumns; + return result; + } + + @Override + public JPAJoinTable getJoinTable() { + return joinTable; } /* @@ -112,6 +147,28 @@ public JPAAssociationAttribute getLeaf() { return (JPAAssociationAttribute) pathElements.get(pathElements.size() - 1); } + @Override + public List getLeftColumnsList() throws ODataJPAModelException { + final List result = new ArrayList<>(); + for (final IntermediateJoinColumn column : this.joinColumns) { + JPAPath columnPath = null; + if (joinTable != null || (cardinality == PersistentAttributeType.MANY_TO_ONE)) { + columnPath = sourceType.getPathByDBField(column.getName()); + + } else { + columnPath = sourceType.getPathByDBField(column.getReferencedColumnName()); + } + if (columnPath != null) + result.add(columnPath); + } + return result; + } + + @Override + public JPAAssociationAttribute getPartner() { + return partner; + } + /* * (non-Javadoc) * @@ -122,24 +179,40 @@ public List getPath() { return pathElements; } + @Override + public List getRightColumnsList() throws ODataJPAModelException { + final List result = new ArrayList<>(); + for (final IntermediateJoinColumn column : this.joinColumns) { + JPAPath columnPath = null; + if (cardinality == PersistentAttributeType.MANY_TO_ONE) + columnPath = targetType.getPathByDBField(column.getReferencedColumnName()); + else + columnPath = targetType.getPathByDBField(column.getName()); + + if (columnPath != null) + result.add(columnPath); + } + return result; + } + /* * (non-Javadoc) * - * @see com.sap.olingo.jpa.metadata.core.edm.mapper.impl.JPAAssociationPath#getTargetType() + * @see com.sap.olingo.jpa.metadata.core.edm.mapper.impl.JPAAssociationPath#getSourceType() */ @Override - public JPAStructuredType getTargetType() { - return targetType; + public JPAStructuredType getSourceType() { + return sourceType; } /* * (non-Javadoc) * - * @see com.sap.olingo.jpa.metadata.core.edm.mapper.impl.JPAAssociationPath#getSourceType() + * @see com.sap.olingo.jpa.metadata.core.edm.mapper.impl.JPAAssociationPath#getTargetType() */ @Override - public JPAStructuredType getSourceType() { - return sourceType; + public JPAStructuredType getTargetType() { + return targetType; } /* @@ -153,7 +226,58 @@ public boolean isCollection() { } @Override - public JPAAssociationAttribute getPartner() { - return partner; + public String toString() { + return "JPAAssociationPathImpl [alias=" + alias + ", pathElements=" + pathElements + ", sourceType=" + sourceType + + ", targetType=" + targetType + ", joinColumns=" + joinColumns + ", cardinality=" + cardinality + + ", joinTable=" + joinTable + "]"; + } + + private PersistentAttributeType getCardinality() { + return cardinality; + } + + private List getJoinColumns() { + return joinColumns; + } + + /** + * A navigation property binding MUST name a navigation property of the + * entity set’s, singleton's, or containment navigation property's entity + * type or one of its subtypes in the Path attribute. If the navigation + * property is defined on a subtype, the path attribute MUST contain the + * QualifiedName of the subtype, followed by a forward slash, followed by + * the navigation property name. If the navigation property is defined on + * a complex type used in the definition of the entity set’s entity type, + * the path attribute MUST contain a forward-slash separated list of complex + * property names and qualified type names that describe the path leading + * to the navigation property. See + * Navigation Property Binding. + * @param associationPath + * @param parent + * @return non empty unique name of a Navigation Property Binding + */ + // TODO respect subtype name + @Nonnull + private String buildNaviPropertyBindingName(final JPAAssociationPath associationPath, final JPAAttribute parent) { + final StringBuilder name = new StringBuilder(); + + name.append(parent.getExternalName()); + for (final JPAElement pathElement : associationPath.getPath()) { + name.append(JPAPath.PATH_SEPERATOR); + name.append(pathElement.getExternalName()); + + } + return name.toString(); + } + + /* + * (non-Javadoc) + * + * @see com.sap.olingo.jpa.metadata.core.edm.mapper.impl.JPAAssociationPath#hasJoinTable() + */ + @Override + public boolean hasJoinTable() { + return joinTable != null; } } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPADefaultEdmNameBuilder.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPADefaultEdmNameBuilder.java new file mode 100644 index 000000000..b63f47d78 --- /dev/null +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPADefaultEdmNameBuilder.java @@ -0,0 +1,136 @@ +package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; + +import java.util.Objects; + +import javax.annotation.Nonnull; +import javax.persistence.metamodel.Attribute; +import javax.persistence.metamodel.EmbeddableType; +import javax.persistence.metamodel.EntityType; + +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEdmNameBuilder; + +public final class JPADefaultEdmNameBuilder implements JPAEdmNameBuilder { + // V2 NameBuilder: package org.apache.olingo.odata2.jpa.processor.core.access.model + private static final String ENTITY_CONTAINER_SUFFIX = "Container"; + private static final String ENTITY_SET_SUFFIX = "s"; + + public static String firstToLower(final String substring) { + return Character.toLowerCase(substring.charAt(0)) + substring.substring(1); + } + + public static String firstToUpper(final String jpaAttributeName) { + return Character.toUpperCase(jpaAttributeName.charAt(0)) + jpaAttributeName.substring(1); + } + + private final String namespace; + + public JPADefaultEdmNameBuilder(@Nonnull final String namespace) { + super(); + this.namespace = Objects.requireNonNull(namespace); + } + + /** + * EDM Complex Type Name - RULE:

+ * Use JPA Embeddable Type Simple Name as Complex Type Name + */ + @Override + public final String buildComplexTypeName(final EmbeddableType jpaEnbeddedType) { + return jpaEnbeddedType.getJavaType().getSimpleName(); + } + + /** + * EDM EntityContainer Name - RULE:

+ * The Entity Container Name is build of EDM Namespace + Literal "Container". Container names are simple identifiers, + * so contain only letter, digits and underscores. However namespaces + * can contain also dots => eliminate dots and convert to camel case. + */ + @Override + public String buildContainerName() { + final StringBuilder containerName = new StringBuilder(); + final String[] elements = namespace.split("\\."); + for (final String element : elements) { + containerName.append(firstToUpper(element)); + } + containerName.append(ENTITY_CONTAINER_SUFFIX); + return containerName.toString(); + } + + /** + * EDM EntitySet Name - RULE:

+ * Use plural of entity type name. The naming bases on the assumption that English nouns are used.
+ * Entity Set Name = JPA Entity Type Name + Literal "s" + */ + @Override + public final String buildEntitySetName(final String entityTypeName) { + if (entityTypeName.charAt(entityTypeName.length() - 1) == 'y' + && entityTypeName.charAt(entityTypeName.length() - 2) != 'a' + && entityTypeName.charAt(entityTypeName.length() - 2) != 'e' + && entityTypeName.charAt(entityTypeName.length() - 2) != 'i' + && entityTypeName.charAt(entityTypeName.length() - 2) != 'o' + && entityTypeName.charAt(entityTypeName.length() - 2) != 'u') { + return entityTypeName.substring(0, entityTypeName.length() - 1) + "ie" + ENTITY_SET_SUFFIX; + } + return entityTypeName + ENTITY_SET_SUFFIX; + } + + /** + * EDM EntityType Name - RULE:

+ * Use JPA Entity Name as EDM Entity Type Name + */ + @Override + public String buildEntityTypeName(final EntityType jpaEntityType) { + return jpaEntityType.getName(); + } + + @Override + public final String getNamespace() { + return namespace; + } + + /** + * EDM Navigation Property Name - RULE:

+ * OData requires: "The name of the navigation property MUST be unique + * within the set of structural and navigation properties of the containing + * structured type and any of its base types." + * This is fulfilled by taking the property name it self. + * @param jpaAttribute + * @return + */ + @Override + public final String buildNaviPropertyName(final Attribute jpaAttribute) { + return buildPropertyName(jpaAttribute.getName()); + } + + /** + * EDM Property Name - RULE:

+ * OData Property Names are represented in Camel Case. The first character + * of JPA Attribute Name is converted to an UpperCase Character. + * @param jpaAttributeName + * @return + */ + @Override + public final String buildPropertyName(final String jpaAttributeName) { + return firstToUpper(jpaAttributeName); + } + + /** + * Convert the internal name of a java based operation into the external entity data model name. + * @param internalOperationName + * @return + */ + @Override + public final String buildOperationName(final String internalOperationName) { + return firstToUpper(internalOperationName); + } + + /** + * Convert the internal java class name of an enumeration into the external entity data model name. + * @param javaEnum + * @return + */ + @Override + public final String buildEnumerationTypeName(final Class> javaEnum) { + return javaEnum.getSimpleName(); + } + +} diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPAEdmNameBuilder.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPAEdmNameBuilder.java deleted file mode 100644 index f46504b6d..000000000 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPAEdmNameBuilder.java +++ /dev/null @@ -1,227 +0,0 @@ -package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; - -import javax.persistence.metamodel.Attribute; -import javax.persistence.metamodel.EmbeddableType; -import javax.persistence.metamodel.EntityType; - -import org.apache.olingo.commons.api.edm.FullQualifiedName; -import org.apache.olingo.commons.api.edm.provider.CsdlEntityType; - -import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAAssociationPath; -import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAAttribute; -import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAElement; -import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAPath; - -public final class JPAEdmNameBuilder { - // V2 NameBuilder: package org.apache.olingo.odata2.jpa.processor.core.access.model - private static final String ENTITY_CONTAINER_SUFFIX = "Container"; - private static final String ENTITY_SET_SUFFIX = "s"; - - public static String firstToLower(final String substring) { - return Character.toLowerCase(substring.charAt(0)) + substring.substring(1); - } - - public static String firstToUpper(final String jpaAttributeName) { - return Character.toUpperCase(jpaAttributeName.charAt(0)) + jpaAttributeName.substring(1); - } - - final private String namespace; - - public JPAEdmNameBuilder(final String namespace) { - super(); - this.namespace = namespace; - } - - /* - * ************************************************************************ - * EDM Complex Type Name - RULES - * ************************************************************************ - * Complex Type Name = JPA Embeddable Type Simple Name. - * ************************************************************************ - * EDM Complex Type Name - RULES - * ************************************************************************ - */ - final public String buildComplexTypeName(final Attribute jpaAttribute) { - return jpaAttribute.getJavaType().getSimpleName(); - } - - final public String buildComplexTypeName(final EmbeddableType jpaEnbeddedType) { - return jpaEnbeddedType.getJavaType().getSimpleName(); - } - - /* - * ************************************************************************ - * EDM EntityContainer Name - RULES - * ************************************************************************ - * Entity Container Name = EDM Namespace + Literal "Container" - * Container names are simple identifiers: - * http://docs.oasis-open.org/odata/odata/v4.0/errata02/os/complete/part3-csdl/odata-v4.0-errata02-os-part3-csdl- - * complete.html#_SimpleIdentifier - * So contain only letter, digits and underscores. However namespaces - * can contain also dots => eliminate dots and convert to camel case - * ************************************************************************ - * EDM EntityContainer Name - RULES - * ************************************************************************ - */ - public String buildContainerName() { - final StringBuffer containerName = new StringBuffer(); - final String[] elements = namespace.split("\\."); - for (final String element : elements) { - containerName.append(firstToUpper(element)); - } - containerName.append(ENTITY_CONTAINER_SUFFIX); - return containerName.toString(); - // return firstToUpper(namespace) + ENTITY_CONTAINER_SUFFIX; - } - - /* - * ************************************************************************ - * EDM EntitySet Name - RULES - * ************************************************************************ - * The naming bases on the assumption that English nouns are used. - * Entity Set Name = JPA Entity Type Name + Literal "s" - * ************************************************************************ - * EDM EntitySet Name - RULES - * ************************************************************************ - */ - final public String buildEntitySetName(final CsdlEntityType entityType) { - return buildEntitySetName(entityType.getName()); - } - - final public String buildEntitySetName(final FullQualifiedName entityTypeFQName) { - return buildEntitySetName(entityTypeFQName.getName()); - } - - final public String buildEntitySetName(final String entityTypeName) { - if (entityTypeName.charAt(entityTypeName.length() - 1) == 'y' - && entityTypeName.charAt(entityTypeName.length() - 2) != 'a' - && entityTypeName.charAt(entityTypeName.length() - 2) != 'e' - && entityTypeName.charAt(entityTypeName.length() - 2) != 'i' - && entityTypeName.charAt(entityTypeName.length() - 2) != 'o' - && entityTypeName.charAt(entityTypeName.length() - 2) != 'u') { - return entityTypeName.substring(0, entityTypeName.length() - 1) + "ie" + ENTITY_SET_SUFFIX; - } - return entityTypeName + ENTITY_SET_SUFFIX; - } - - /* - * ************************************************************************ - * EDM EntityType Name - RULES - * ************************************************************************ - * EDM Entity Type Name = JPA Entity Name EDM Entity Type Internal Name = - * JPA Entity Name - * ************************************************************************ - * EDM Entity Type Name - RULES - * ************************************************************************ - */ - public String buildEntityTypeName(final EntityType jpaEntityType) { - return jpaEntityType.getName(); - } - - final public FullQualifiedName buildFQN(final String name) { - final FullQualifiedName fqName = new FullQualifiedName(buildNamespace(), name); - return fqName; - } - - /* - * ************************************************************************ - * EDM Schema Name - RULES - * ************************************************************************ - * Java Persistence Unit name is set as Schema's Namespace - * ************************************************************************ - * EDM Schema Name - RULES - * ************************************************************************ - */ - final public String buildNamespace() { - return namespace; - } - - /* - * ************************************************************************ - * EDM Navigation Property Binding - RULES - * ************************************************************************ - * V4 specification states: - * A navigation property binding MUST name a navigation property of the - * entity set’s, singleton's, or containment navigation property's entity - * type or one of its subtypes in the Path attribute. If the navigation - * property is defined on a subtype, the path attribute MUST contain the - * QualifiedName of the subtype, followed by a forward slash, followed by - * the navigation property name. If the navigation property is defined on - * a complex type used in the definition of the entity set’s entity type, - * the path attribute MUST contain a forward-slash separated list of complex - * property names and qualified type names that describe the path leading - * to the navigation property. - * - * http://docs.oasis-open.org/odata/odata/v4.0/errata02/os/complete/part3-csdl/odata-v4.0-errata02-os-part3-csdl- - * complete.html#_Toc406398035 - * ************************************************************************ - * EDM Property Name - RULES - * ************************************************************************ - */ - // TODO respect subtype name - final public String buildNaviPropertyBindingName(final JPAAssociationPath associationPath, - final JPAAttribute parent) { - final StringBuffer name = new StringBuffer(); - - name.append(parent.getExternalName()); - for (final JPAElement pathElement : associationPath.getPath()) { - name.append(JPAPath.PATH_SEPERATOR); - name.append(pathElement.getExternalName()); - - } - return name.toString(); - } - - /* - * ************************************************************************ - * EDM Navigation Property Name - RULES - * ************************************************************************ - * V2 rules were navigation target entity name + Details. In case of - * multiple navigation properties with the same target an counter was added - * - * New rules for V4: - * OData requires: "The name of the navigation property MUST be unique - * within the set of structural and navigation properties of the containing - * structured type and any of its base types." - * The is fulfilled by taking the property name it self. In addition it - * could be expected that, in case of multiple navigation properties with - * the same target, the name is more expressive, if the property name is - * well chosen;-) - * ************************************************************************ - * EDM Navigation Property Name - RULES - * ************************************************************************ - */ - final public String buildNaviPropertyName(final Attribute jpaAttribute) { - return buildPropertyName(jpaAttribute.getName()); - } - - final public String buildPath(final String pathRoot, final String pathElement) { - return pathRoot + JPAPath.PATH_SEPERATOR + pathElement; - } - - final public FullQualifiedName buildPropertyFQN(final String jpaAttributeName) { - return buildFQN(buildPropertyName(jpaAttributeName)); - } - - /* - * ************************************************************************ - * EDM Property Name - RULES - * ************************************************************************ - * OData Property Names are represented in Camel Case. The first character - * of JPA Attribute Name is converted to an UpperCase Character and set as - * OData Property Name. JPA Attribute Name is set as Internal Name for OData - * Property. The Column name (annotated as @Column(name="x")) is set as - * column name in the mapping object. - * ************************************************************************ - * EDM Property Name - RULES - * ************************************************************************ - */ - final public String buildPropertyName(final String jpaAttributeName) { - return firstToUpper(jpaAttributeName); - } - - final public String buildOperationName(String internalFunctionName) { - return firstToUpper(internalFunctionName); - } - -} diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPANameBuilder.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPANameBuilder.java index 6a9aea123..e57f5ef3d 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPANameBuilder.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPANameBuilder.java @@ -2,8 +2,11 @@ import javax.persistence.metamodel.Attribute; +import org.apache.olingo.commons.api.edm.FullQualifiedName; + import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmAction; import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmFunction; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEdmNameBuilder; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAStructuredType; /** @@ -34,6 +37,10 @@ public String buildActionName(final EdmAction jpaAction) { } public String buildEntitySetName(final JPAEdmNameBuilder nameBuilder, final JPAStructuredType entityType) { - return nameBuilder.buildFQN(entityType.getInternalName()).getFullQualifiedNameAsString(); + return buildFQN(entityType.getInternalName(), nameBuilder).getFullQualifiedNameAsString(); + } + + protected final FullQualifiedName buildFQN(final String name, final JPAEdmNameBuilder nameBuilder) { + return new FullQualifiedName(nameBuilder.getNamespace(), name); } } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPAOnConditionItemImpl.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPAOnConditionItemImpl.java index 7b368ab93..2ba4dd109 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPAOnConditionItemImpl.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPAOnConditionItemImpl.java @@ -32,4 +32,9 @@ public JPAPath getRightPath() { return jpaRightAttribute; } + @Override + public String toString() { + return "JPAOnConditionItem [LeftAttribute=" + jpaLeftAttribute + ", RightAttribute=" + jpaRightAttribute + "]"; + } + } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPAPathImpl.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPAPathImpl.java index a0bb869d8..06bfbc30a 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPAPathImpl.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPAPathImpl.java @@ -1,6 +1,8 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; -import java.util.ArrayList; +import static com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException.MessageKeys.NOT_SUPPORTED_MIXED_PART_OF_GROUP; + +import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -10,27 +12,32 @@ import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; final class JPAPathImpl implements JPAPath { - final private String alias; - final private List pathElements; - final private String dbFieldName; - final private boolean ignore; + private static final List EMPTY_FILED_GROUPS = Collections.emptyList(); + private final String alias; + private final List pathElements; + private final String dbFieldName; + private final boolean ignore; + private final List fieldGroups; - JPAPathImpl(final String alias, final String dbFieldName, final IntermediateModelElement element) { - final List pathElementsBuffer = new ArrayList(); + JPAPathImpl(final String alias, final String dbFieldName, final IntermediateProperty element) + throws ODataJPAModelException { - this.alias = alias; - pathElementsBuffer.add(element); - this.pathElements = Collections.unmodifiableList(pathElementsBuffer); - this.dbFieldName = dbFieldName; - this.ignore = element.ignore(); + this(alias, dbFieldName, Arrays.asList(element)); } - JPAPathImpl(final String selection, final String dbFieldName, final List attribute) + JPAPathImpl(final String alias, final String dbFieldName, final List attribute) throws ODataJPAModelException { - this.alias = selection; + + this.alias = alias; this.pathElements = Collections.unmodifiableList(attribute); this.dbFieldName = dbFieldName; - this.ignore = ((IntermediateModelElement) pathElements.get(1)).ignore(); + this.ignore = ((IntermediateModelElement) pathElements.get(pathElements.size() - 1)).ignore(); + this.fieldGroups = determineFieldGroups(); + } + + @Override + public int compareTo(final JPAPath o) { + return this.alias.compareTo(o.getAlias()); } @Override @@ -108,7 +115,55 @@ public boolean ignore() { } @Override - public int compareTo(final JPAPath o) { - return this.alias.compareTo(o.getAlias()); + public boolean isPartOfGroups(List groups) { + + return fieldGroups == EMPTY_FILED_GROUPS || fieldGroupMatches(groups); } + + @Override + public String toString() { + return "JPAPathImpl [alias=" + alias + ", pathElements=" + pathElements + ", dbFieldName=" + dbFieldName + + ", ignore=" + ignore + ", fieldGroups=" + fieldGroups + "]"; + } + + /** + * @return + * @throws ODataJPAModelException + */ + private List determineFieldGroups() throws ODataJPAModelException { + List groups = null; + for (JPAElement pathElement : pathElements) { + if (pathElement instanceof IntermediateProperty && ((IntermediateProperty) pathElement).isPartOfGroup()) { + if (groups == null) + groups = ((IntermediateProperty) pathElement).getGroups(); + else { + List newGroups = ((IntermediateProperty) pathElement).getGroups(); + if (groups.size() != newGroups.size() || !groups.stream().allMatch(newGroups::contains)) + throw new ODataJPAModelException(NOT_SUPPORTED_MIXED_PART_OF_GROUP, alias); + } + } + } + return groups == null ? EMPTY_FILED_GROUPS : groups; + } + + /** + * @param groups + * @return + */ + private boolean fieldGroupMatches(final List groups) { + for (final String group : groups) { + if (fieldGroups.contains(group)) + return true; + } + return false; + } + + @Override + public boolean isTransient() { + return pathElements.stream() + .filter(e -> e instanceof JPAAttribute) + .map(e -> (JPAAttribute) e) + .anyMatch(JPAAttribute::isTransient); + } + } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPAProtectionInfo.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPAProtectionInfo.java new file mode 100644 index 000000000..c399e104b --- /dev/null +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPAProtectionInfo.java @@ -0,0 +1,43 @@ +package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; + +import java.util.List; + +final class JPAProtectionInfo { + private final List path; + private final boolean wildcards; + + JPAProtectionInfo(List path, boolean wildcards) { + super(); + this.path = path; + this.wildcards = wildcards; + } + + @Override + public String toString() { + return "JPAProtectionInfo [path=" + path + ", wildcards=" + wildcards + "]"; + } + + List getPath() { + return path; + } + + /** + * Returns the maintained wildcard setting. + * @return + */ + boolean supportsWildcards() { + return wildcards; + } + + /** + * Returns wildcard support if the protected property it of type clazz + * @param + * @param clazz + * @return + */ + boolean supportsWildcards(final Class clazz) { + if (clazz.equals(String.class)) + return wildcards; + return false; + } +} diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPAServiceDocumentFactory.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPAServiceDocumentFactory.java index a38f75e68..42f7f5785 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPAServiceDocumentFactory.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPAServiceDocumentFactory.java @@ -3,26 +3,32 @@ import javax.persistence.metamodel.Metamodel; import com.sap.olingo.jpa.metadata.api.JPAEdmMetadataPostProcessor; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEdmNameBuilder; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAServiceDocument; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; public final class JPAServiceDocumentFactory { - private final String namespace; + private final JPAEdmNameBuilder nameBuilder; private final Metamodel jpaMetamodel; private final JPAEdmMetadataPostProcessor postProcessor; private final String[] packageName; - public JPAServiceDocumentFactory(final String namespace, final Metamodel jpaMetamodel, + public JPAServiceDocumentFactory(final JPAEdmNameBuilder nameBuilder, final Metamodel jpaMetamodel, final JPAEdmMetadataPostProcessor postProcessor, final String[] packageName) { super(); - this.namespace = namespace; + this.nameBuilder = nameBuilder; this.jpaMetamodel = jpaMetamodel; this.postProcessor = postProcessor; this.packageName = packageName; } + /** + * Late creation of the service document. A service document contains at least one schema and a container. + * @return + * @throws ODataJPAModelException + */ public JPAServiceDocument getServiceDocument() throws ODataJPAModelException { - return new IntermediateServiceDocument(namespace, jpaMetamodel, postProcessor, packageName); + return new IntermediateServiceDocument(nameBuilder, jpaMetamodel, postProcessor, packageName); } } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPATypeConvertor.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPATypeConvertor.java index ade62fe74..1e7a3d5b4 100644 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPATypeConvertor.java +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/JPATypeConvertor.java @@ -5,6 +5,9 @@ import java.sql.Blob; import java.sql.Clob; import java.sql.Timestamp; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZonedDateTime; import java.util.Calendar; import java.util.UUID; @@ -26,6 +29,8 @@ */ public final class JPATypeConvertor { + private JPATypeConvertor() {} + public static EdmPrimitiveTypeKind convertToEdmSimpleType(final Class type) throws ODataJPAModelException { return convertToEdmSimpleType(type, null); } @@ -43,8 +48,9 @@ public static EdmPrimitiveTypeKind convertToEdmSimpleType(final Class type) t * @see EdmPrimitiveTypeKind */ - public static EdmPrimitiveTypeKind convertToEdmSimpleType(final Class jpaType, + public static EdmPrimitiveTypeKind convertToEdmSimpleType(final Class jpaType, // NOSONAR final Attribute currentAttribute) throws ODataJPAModelException { + if (jpaType.equals(String.class) || jpaType.equals(Character.class) || jpaType.equals(char.class) || jpaType.equals( char[].class) || jpaType.equals(Character[].class)) { return EdmPrimitiveTypeKind.String; @@ -81,10 +87,13 @@ public static EdmPrimitiveTypeKind convertToEdmSimpleType(final Class jpaType } else { return EdmPrimitiveTypeKind.DateTimeOffset; } + } else if (jpaType.equals(ZonedDateTime.class) || jpaType.equals(LocalDateTime.class) + || jpaType.equals(OffsetDateTime.class)) { + // Looks like Olingo does not support LocalDateTime or OffsetDateTime, which are supported by JPA 2.2. Olingo only + // takes ZonedDateTime. + return EdmPrimitiveTypeKind.DateTimeOffset; } else if (jpaType.equals(UUID.class)) { return EdmPrimitiveTypeKind.Guid; - } else if (jpaType.equals(Byte[].class)) { - return EdmPrimitiveTypeKind.Binary; } else if (jpaType.equals(Blob.class) && isBlob(currentAttribute)) { return EdmPrimitiveTypeKind.Binary; } else if (jpaType.equals(Clob.class) && isBlob(currentAttribute)) { @@ -107,8 +116,18 @@ public static EdmPrimitiveTypeKind convertToEdmSimpleType(final JPAAttribute att return convertToEdmSimpleType(attribute.getType(), null); } + public static boolean isSimpleType(final Class type, final Attribute currentAttribute) { + return type != null + && (isScalarType(type) + || type.equals(Byte[].class) + || type.equals(Blob.class) + || type.equals(Clob.class) + || isGeography(currentAttribute) + || isGeometry(currentAttribute)); + } + public static boolean isScalarType(final Class type) { - if (type == String.class || + return (type == String.class || type == Character.class || type == Long.class || type == Short.class || @@ -122,24 +141,35 @@ public static boolean isScalarType(final Class type) { type == java.sql.Time.class || type == java.time.Duration.class || type == java.time.LocalDate.class || + type == java.time.OffsetDateTime.class || + type == java.time.ZonedDateTime.class || type == java.sql.Date.class || type == Calendar.class || type == Timestamp.class || type == java.util.Date.class || - type == UUID.class) { - return true; - } - return false; + type == UUID.class); } /** - * For supported java types see {@link org.apache.olingo.commons.api.edm.EdmPrimitiveType} + * For supported java types see {@link org.apache.olingo.commons.api.edm.EdmPrimitiveType}. In addition, since 4.7.1, + * also some types from the java.time package are supported, see: + *

    + *
  • For EdmDate: LocalDate, see + * {@link org.apache.olingo.commons.core.edm.primitivetype.EdmDate#internalValueToString + * EdmDate.internalValueToString}
  • + *
  • For EdmTimeOfDay: LocalTime, see + * {@link org.apache.olingo.commons.core.edm.primitivetype.EdmTimeOfDay#internalValueToString + * EdmTimeOfDay.internalValueToString}
  • + *
  • For EdmDateTimeOffset: ZonedDateTime, see + * {@link org.apache.olingo.commons.core.edm.primitivetype.EdmDateTimeOffset#internalValueToString + * EdmDateTimeOffset.internalValueToString}
  • + *
* @param type * @return */ public static boolean isSupportedByOlingo(final Class type) { - if (type == Boolean.class || + return (type == Boolean.class || type == Byte.class || type == Byte[].class || type == byte[].class || @@ -151,14 +181,14 @@ public static boolean isSupportedByOlingo(final Class type) { type == java.sql.Time.class || type == java.sql.Timestamp.class || type == java.util.Calendar.class || + type == java.time.LocalTime.class || + type == java.time.LocalDate.class || + type == java.time.ZonedDateTime.class || type == java.util.Date.class || type == java.util.UUID.class || type == Long.class || type == Short.class || - type == String.class) { - return true; - } - return false; + type == String.class); } private static EdmPrimitiveTypeKind convertGeography(final Class jpaType, final Attribute currentAttribute) @@ -237,10 +267,10 @@ private static boolean isBlob(final Attribute currentAttribute) { } private static boolean isGeography(final Attribute currentAttribute) { - return currentAttribute != null && getDimension(currentAttribute) == Dimension.GEOGRAPHY ? true : false; + return currentAttribute != null && getDimension(currentAttribute) == Dimension.GEOGRAPHY; } private static boolean isGeometry(final Attribute currentAttribute) { - return currentAttribute != null && getDimension(currentAttribute) == Dimension.GEOMETRY ? true : false; + return currentAttribute != null && getDimension(currentAttribute) == Dimension.GEOMETRY; } } diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/ODataEnum.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/ODataEnum.java deleted file mode 100644 index f965a16b0..000000000 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/ODataEnum.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; - -public interface ODataEnum { - public Integer getValue(); -} diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/ODataEnumerationType.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/ODataEnumerationType.java deleted file mode 100644 index 206304349..000000000 --- a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/ODataEnumerationType.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; - -public abstract class ODataEnumerationType { - -} diff --git a/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/OffsetDateTimeConverter.java b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/OffsetDateTimeConverter.java new file mode 100644 index 000000000..e2bbe028d --- /dev/null +++ b/jpa/odata-jpa-metadata/src/main/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/OffsetDateTimeConverter.java @@ -0,0 +1,29 @@ +package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; + +import java.time.OffsetDateTime; +import java.time.ZonedDateTime; + +import javax.persistence.AttributeConverter; +import javax.persistence.Converter; + +/** + * Default converter to convert from {@link java.time.OffsetDateTime} to {@link java.time.ZonedDateTime}. This is + * required, as Olingo 4.7.1 only supports ZonedDateTime, where as JPA 2.2 supports OffsetDateTime. + * @author Oliver Grande + * Created: 09.03.2020 + * + */ +@Converter(autoApply = false) +public class OffsetDateTimeConverter implements AttributeConverter { + + @Override + public OffsetDateTime convertToDatabaseColumn(final ZonedDateTime zonedDateTime) { + return zonedDateTime == null ? null : zonedDateTime.toOffsetDateTime(); + } + + @Override + public ZonedDateTime convertToEntityAttribute(final OffsetDateTime dateTimeWithOffset) { + return dateTimeWithOffset == null ? null : dateTimeWithOffset.toZonedDateTime(); + } + +} diff --git a/jpa/odata-jpa-metadata/src/main/resources/metadata-exceptions-i18n.properties b/jpa/odata-jpa-metadata/src/main/resources/metadata-exceptions-i18n.properties index 717ff9d5e..52bfa318a 100644 --- a/jpa/odata-jpa-metadata/src/main/resources/metadata-exceptions-i18n.properties +++ b/jpa/odata-jpa-metadata/src/main/resources/metadata-exceptions-i18n.properties @@ -18,63 +18,69 @@ #------------------------------------------------------------------------------- # Basic Apache Olingo exception messages # -ODataJPAModelException.INVALID_ENTITY_TYPE = INVALID_ENTITY_TYPE -ODataJPAModelException.INVALID_COMPLEX_TYPE = INVLAID_COMPLEX_TYPE -ODataJPAModelException.INVALID_ASSOCIATION = INVALID_ASSOCIATION -ODataJPAModelException.INVALID_ENTITY_SET = INVALID_ENTITY_SET -ODataJPAModelException.INVALID_ENTITY_CONTAINER = INVALID_ENTITY_CONTAINER -ODataJPAModelException.INVALID_FUNC_IMPORT = INVALID_FUNC_IMPORT -ODataJPAModelException.INVALID_DESCIPTION_PROPERTY = The attribute %2$s has not been found at entity %1$s -ODataJPAModelException.FUNC_ENTITY_SET_EXP = FUNC_ENTITY_SET_EXP -ODataJPAModelException.FUNC_RETURN_TYPE_EXP = Type parameter expected for %1$s -ODataJPAModelException.FUNC_RETURN_TYPE_ENTITY_NOT_FOUND = FUNC_RETURN_TYPE_ENTITY_NOT_FOUND -ODataJPAModelException.FUNC_RETURN_TYPE_UNKNOWN = Unknown return type %1$s -ODataJPAModelException.FUNC_RETURN_TYPE_INVALID = The return type %1$s from EdmFunction does not match type %2$s declared at method %3$s -ODataJPAModelException.FUNC_PARAM_NAME_EXP = FUNC_PARAM_NAME_EXP -ODataJPAModelException.FUNC_PARAM_OUT_WRONG_TYPE = FUNC_PARAM_OUT_WRONG_TYPE -ODataJPAModelException.FUNC_PARAM_OUT_MISSING = FUNC_PARAM_OUT_MISSING -ODataJPAModelException.FUNC_PARAM_OUT_TO_MANY = "FUNC_PARAM_TO_MANY -ODataJPAModelException.FUNC_CONSTRUCTOR_MISSING = No valid constructor found for class %1$s -ODataJPAModelException.FUNC_PARAM_ONLY_PRIMITIVE = Only parameter with a primitive type are supported for java based functions. Parameter %3$s of method %2$s of class %1$s could not be converted into a primitive type -ODataJPAModelException.FUNC_PARAM_ANNOTATION_MISSING = Function parameter %1$s of method %2$s at class %3$s without required annotation +ODataJPAModelException.INVALID_DESCIPTION_PROPERTY = The attribute '%2$s' has not been found at entity '%1$s' +ODataJPAModelException.INVALID_COLLECTION_TYPE = Base type of collection '%1$s' of structured type '%2$s' not found -ODataJPAModelException.ACTION_RETURN_TYPE_INVALID = The return type %1$s from EdmAction does not match type %2$s declared at method %3$s -ODataJPAModelException.ACTION_RETURN_TYPE_EXP = Type parameter expected for %1$s at method %2$s -ODataJPAModelException.ACTION_PARAM_ANNOTATION_MISSING = Action parameter %1$s of method %2$s at class %3$s without required annotation -ODataJPAModelException.ACTION_PARAM_ONLY_PRIMITIVE = Only parameter with a primitive type are supported for action. Parameter %3$s of method %2$s of class %1$s could not be converted into a primitive type -ODataJPAModelException.ACTION_PARAM_TYPE_INVALID = The type of %1$s of action of method %2$s of class %3$s could not be converted -ODataJPAModelException.ACTION_PARAM_BINGING_NOT_FOUND = Binding parameter not found within in interface of method %1$s of class %2$s. Binding parameter must be the first parameter -ODataJPAModelException.ACTION_UNBOUND_ENTITY_SET = Entity Set Path shall only provided for bound actions. Action method %1$s of class %2$s is unbound. +ODataJPAModelException.FUNC_RETURN_TYPE_EXP = Type parameter expected for '%1$s' +ODataJPAModelException.FUNC_RETURN_TYPE_UNKNOWN = Unknown return type '%1$s' +ODataJPAModelException.FUNC_RETURN_TYPE_INVALID = The return type '%1$s' from EdmFunction does not match type '%2$s' declared at method '%3$s' +ODataJPAModelException.FUNC_RETURN_NOT_SUPPORTED = The return type '%1$s' used at method '%3$s' is not supported +ODataJPAModelException.FUNC_CONV_ERROR = An error occurred during function metadata conversion. +ODataJPAModelException.FUNC_CONSTRUCTOR_MISSING = No valid constructor found for class '%1$s' +ODataJPAModelException.FUNC_PARAM_ONLY_PRIMITIVE = Only parameter with a primitive type or an enumeration are supported for java based functions. Parameter '%3$s' of method '%2$s' of class '%1$s' could not be converted. +ODataJPAModelException.FUNC_PARAM_ANNOTATION_MISSING = Function parameter '%1$s' of method '%2$s' at class '%3$s' without required annotation +ODataJPAModelException.FUNC_PARAM_BOUND_IGNORE = Bound function '%1$s' is bound to entity '%2$s', which shall be ignored +ODataJPAModelException.ACTION_RETURN_TYPE_INVALID = The return type '%1$s' from EdmAction does not match type '%2$s' declared at method '%3$s' +ODataJPAModelException.ACTION_RETURN_TYPE_EXP = Type parameter expected for '%1$s' at method '%2$s' +ODataJPAModelException.ACTION_PARAM_ANNOTATION_MISSING = Action parameter '%1$s' of method '%2$s' at class '%3$s' without required annotation +ODataJPAModelException.ACTION_PARAM_ONLY_PRIMITIVE = Only parameter with a primitive type are supported for action. Parameter '%3$s' of method '%2$s' of class '%1$s' could not be converted into a primitive type +ODataJPAModelException.ACTION_PARAM_TYPE_INVALID = The type of '%1$s' of action of method '%2$s' of class '%3$s' could not be converted +ODataJPAModelException.ACTION_PARAM_BINGING_NOT_FOUND = Binding parameter not found within in interface of method '%1$s' of class '%2$s'. Binding parameter must be the first parameter +ODataJPAModelException.ACTION_UNBOUND_ENTITY_SET = Entity Set Path shall only provided for bound actions. Action method '%1$s' of class '%2$s' is unbound. -ODataJPAModelException.GENERAL = GENERAL -ODataJPAModelException.BUILDER_NULL = BUILDER_NULL -ODataJPAModelException.TYPE_NOT_SUPPORTED = Type (%1$s) of attribute (%2$s) is not supported. Mapping not possible -ODataJPAModelException.INNER_EXCEPTION = INNER_EXCEPTION -ODataJPAModelException.REF_ATTRIBUTE_NOT_FOUND = REF_ATTRIBUTE_NOT_FOUND -ODataJPAModelException.TYPE_MAPPER_COULD_NOT_INSANTIATE = Type mapper could not be instantiated -ODataJPAModelException.NOT_SUPPORTED_EMBEDDED_KEY = "EMBEDDED_KEY_NOT_SUPPORTED"; -ODataJPAModelException.NOT_SUPPORTED_ATTRIBUTE_TYPE = Attribute Type (%1$s) as of now not supported -ODataJPAModelException.NOT_SUPPORTED_NO_IMPLICIT_COLUMNS = Relationship %1$s: Only one implicit column name supported -ODataJPAModelException.NOT_SUPPORTED_EMBEDDED_STREAM = Streams via embedded types (%1$s) are not supported +ODataJPAModelException.ENUMERATION_ANNOTATION_MISSING = Annotation EdmEnumeration is missing for Enum '%1$s'. +ODataJPAModelException.ENUMERATION_UNSUPPORTED_TYPE = Enumeration '%1$s' has the unsupported type '%2$s'. +ODataJPAModelException.ENUMERATION_NO_NEGATIVE_VALUE = An Enumeration that is marked as Flag must not have a negative value: '%1$s - %2$s'. -ODataJPAModelException.DESCRIPTION_LOCALE_FIELD_MISSING = EdmDescriptionAssozation: At least one of the fields languageAttribute or localeAttribute must be filled at %1$s - %2$s -ODataJPAModelException.DESCRIPTION_ANNOTATION_MISSING = EdmDescriptionAssozation: Annotation not found at %1$s - %2$s +ODataJPAModelException.TYPE_NOT_SUPPORTED = Type '%1$s' of attribute '%2$s' is not supported. Mapping not possible. If '%1$s' is an enumeration, check if related package is provided. +ODataJPAModelException.TYPE_MAPPER_COULD_NOT_INSANTIATE = Type mapper could not be instantiated. +ODataJPAModelException.NOT_SUPPORTED_ATTRIBUTE_TYPE = Attribute Type '%1$s' as of now not supported. +ODataJPAModelException.NOT_SUPPORTED_NO_IMPLICIT_COLUMNS = Relationship '%1$s': Only one implicit column name supported. +ODataJPAModelException.NOT_SUPPORTED_EMBEDDED_STREAM = Streams via embedded types '%1$s' are not supported. +ODataJPAModelException.NOT_SUPPORTED_NO_IMPLICIT_COLUMNS_COMPEX = Relationship '%1$s': implicit column name not supported for embedded types. +ODataJPAModelException.NOT_SUPPORTED_PROTECTED_COLLECTION = Annotation EdmProtctedBy found at '%2$s' of '%1$s'. EdmProtctedBy is not supported at collection attributes. +ODataJPAModelException.NOT_SUPPORTED_PROTECTED_NAVIGATION = Annotation EdmProtctedBy found at '%2$s' of '%1$s'. EdmProtctedBy is not supported at navigation attributes. +ODataJPAModelException.NOT_SUPPORTED_NAVIGATION_PART_OF_GROUP = Annotation EdmVisibleFor found at '%2$s' of '%1$s'. EdmVisibleFor is not supported at navigation attributes. +ODataJPAModelException.NOT_SUPPORTED_MANDATORY_PART_OF_GROUP = Annotation EdmVisibleFor found at '%2$s' of '%1$s'. EdmVisibleFor is not supported at mandatory attributes. +ODataJPAModelException.NOT_SUPPORTED_KEY_PART_OF_GROUP = Annotation EdmVisibleFor found at '%2$s' of '%1$s'. EdmVisibleFor is not supported at key attributes. +ODataJPAModelException.NOT_SUPPORTED_MIXED_PART_OF_GROUP = Two sets of groups have been assigned to elements of path '%1$s'. This is not supported. +ODataJPAModelException.COMPLEX_PROPERTY_MISSING_PROTECTION_PATH = Annotation EdmProtctedBy found at '%2$s' of '%1$s'. As '%1$s' is embedded a 'path' to an attributes is required. +ODataJPAModelException.COMPLEX_PROPERTY_WRONG_PROTECTION_PATH = Annotation EdmProtctedBy found at '%2$s' of '%1$s', but the given 'path' '%3$s' could not be resolved. + +ODataJPAModelException.DESCRIPTION_LOCALE_FIELD_MISSING = EdmDescriptionAssozation: At least one of the fields languageAttribute or localeAttribute must be filled at '%1$s - %2$s' +ODataJPAModelException.DESCRIPTION_ANNOTATION_MISSING = EdmDescriptionAssozation: Annotation not found at '%1$s - %2$s' ODataJPAModelException.DESCRIPTION_FIELD_WRONG_TYPE = EdmDescriptionAssozation: Description field shall be a String -ODataJPAModelException.PROPERTY_DEFAULT_ERROR = Error when determining default of %1$s -ODataJPAModelException.PROPERTY_MISSING_PRECISION = The type of property %1$s requires that a precision is given -ODataJPAModelException.NAVI_PROPERTY_NOT_FOUND = Could not determine the target for navigation property "%1$s" of type "%2$s" -ODataJPAModelException.PATH_ELEMENT_NOT_FOUND = Element "%1$s" of path "%2$s" not found +ODataJPAModelException.PROPERTY_DEFAULT_ERROR = Error when determining default of '%1$s' +ODataJPAModelException.PROPERTY_MISSING_PRECISION = The type of property '%1$s' requires that a precision is given +ODataJPAModelException.PROPERTY_REQUIRED_UNKNOWN = The transient attribute '%1$s' of class '%2$s' requires '%3$s', which is not known +ODataJPAModelException.TRANSIENT_CALCULATOR_TOO_MANY_CONSTRUCTORS = The calculator '%1$s' of transient attribute '%2$s' of class '%3$s' has more than one constructors +ODataJPAModelException.TRANSIENT_CALCULATOR_WRONG_PARAMETER = The calculator '%1$s' of transient attribute '%2$s' of class '%3$s'contains of unsupported parameter type +ODataJPAModelException.TRANSIENT_KEY_NOT_SUPPORTED = The class '%1$s'contains a key that is annotated as transient. This is not supported +ODataJPAModelException.NAVI_PROPERTY_NOT_FOUND = Could not determine the target for navigation property '%1$s' of type '%2$s' +ODataJPAModelException.PATH_ELEMENT_NOT_FOUND = Element '%1$s' of path '%2$s' not found -ODataJPAModelException.REFERENCED_PROPERTY_NOT_FOUND = Error when creating Referential Constraints for %1$s: Property for %2$s not found at %3$s -ODataJPAModelException.NOT_SUPPORTED_ATTRIBUTE_TYPE = Abstract entity type %1$s must not inherit from a non-abstract entity type %2$s +ODataJPAModelException.REFERENCED_PROPERTY_NOT_FOUND = Error when creating Referential Constraints for '%1$s': Property for '%2$s' not found at '%3$s' +ODataJPAModelException.INHERITANCE_NOT_ALLOWED = Abstract entity type '%1$s' must not inherit from a non-abstract entity type '%2$s' -ODataJPAModelException.TO_MANY_STREAMS = Only one stream property per entity is allowed. For %1$s %2$s have been found -ODataJPAModelException.ANNOTATION_STREAM_INCOMPLETE = Either contentType or contentTypeAttribute have to be given for stream at %1$s -ODataJPAModelException.ANNOTATION_PARSE_ERROR = Parsing of %1$s failed with message "%2$s" -ODataJPAModelException.ODATA_ANNOTATION_TWO_EXPRESSIONS = OData annotation only supports either a constant or a dynamic expression. See %1$s +ODataJPAModelException.TO_MANY_STREAMS = Only one stream property per entity is allowed. For '%1$s-%2$s' have been found +ODataJPAModelException.ANNOTATION_STREAM_INCOMPLETE = Either contentType or contentTypeAttribute have to be given for stream at '%1$s' +ODataJPAModelException.ANNOTATION_PARSE_ERROR = Parsing of '%1$s' failed with message '%2$s' +ODataJPAModelException.ODATA_ANNOTATION_TWO_EXPRESSIONS = OData annotation only supports either a constant or a dynamic expression. See '%1$s' ODataJPAModelException.ON_LEFT_ATTRIBUTE_NULL = ON condition left attribute is null / not found -ODataJPAModelException.ON_RIGHT_ATTRIBUTE_NULL = ON condition right attribute is null / not found \ No newline at end of file +ODataJPAModelException.ON_RIGHT_ATTRIBUTE_NULL = ON condition right attribute is null / not found + +ODataJPAModelException.FILE_NOT_FOUND = File with path '%1$s' not found; \ No newline at end of file diff --git a/jpa/odata-jpa-metadata/src/main/resources/metadata-exceptions-i18n_de.properties b/jpa/odata-jpa-metadata/src/main/resources/metadata-exceptions-i18n_de.properties deleted file mode 100644 index ff0712bdc..000000000 --- a/jpa/odata-jpa-metadata/src/main/resources/metadata-exceptions-i18n_de.properties +++ /dev/null @@ -1,45 +0,0 @@ -#------------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you 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. -#------------------------------------------------------------------------------- -# Basic Apache Olingo exception messages -# -ODataJPAModelException.INVALID_ENTITY_TYPE = "INVALID_ENTITY_TYPE"; -ODataJPAModelException.INVALID_COMPLEX_TYPE = "INVLAID_COMPLEX_TYPE"; -ODataJPAModelException.INVALID_ASSOCIATION = "INVALID_ASSOCIATION"; -ODataJPAModelException.INVALID_ENTITYSET = "INVALID_ENTITYSET"; -ODataJPAModelException.INVALID_ENTITYCONTAINER = "INVALID_ENTITYCONTAINER"; -ODataJPAModelException.INVALID_ASSOCIATION_SET = "INVALID_ASSOCIATION_SET"; -ODataJPAModelException.INVALID_FUNC_IMPORT = "INVALID_FUNC_IMPORT"; - -ODataJPAModelException.BUILDER_NULL = "BUILDER_NULL"; -ODataJPAModelException.TYPE_NOT_SUPPORTED = "Type of attribute is not supported. Mapping not possible"; -ODataJPAModelException.FUNC_ENTITYSET_EXP = "FUNC_ENTITYSET_EXP"; -ODataJPAModelException.FUNC_RETURN_TYPE_EXP = "FUNC_RETURN_TYPE_EXP"; -ODataJPAModelException.FUNC_RETURN_TYPE_ENTITY_NOT_FOUND = "FUNC_RETURN_TYPE_ENTITY_NOT_FOUND"; -ODataJPAModelException.GENERAL = "GENERAL"; -ODataJPAModelException.INNER_EXCEPTION = "INNER_EXCEPTION"; -ODataJPAModelException.FUNC_PARAM_NAME_EXP = "FUNC_PARAM_NAME_EXP"; -ODataJPAModelException.FUNC_PARAM_OUT_WRONG_TYPE = "FUNC_PARAM_OUT_WRONG_TYPE"; -ODataJPAModelException.FUNC_PARAM_OUT_MISSING = "FUNC_PARAM_OUT_MISSING"; -ODataJPAModelException.FUNC_PARAM_OUT_TO_MANY = "FUNC_PARAM_TO_MANY"; -ODataJPAModelException.REF_ATTRIBUTE_NOT_FOUND = "REF_ATTRIBUTE_NOT_FOUND"; -ODataJPAModelException.TYPE_MAPPER_COULD_NOT_INSANTIATE = "Type mapper could not be instantiated"; -ODataJPAModelException.NOT_SUPPORTED_EMBEDDED_KEY = "EMBEDDED_KEY_NOT_SUPPORTED"; -ODataJPAModelException.NOT_SUPPORTED_ATTRIBUTE_TYPE = "ATTRIBUTE_TYPE_NOT_SUPPORTED"; -ODataJPAModelException.NOT_SUPPORTED_NO_IMPLICIT_COLUMNS = "NOT_SUPPORTED_NO_IMPLICIT_COLUMNS"; -ODataJPAModelException.DESCRIPTION_LOCALE_FIELD_MISSING = "DESCRIPTION_LOCALE_FIELD_MISSING"; \ No newline at end of file diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/api/TestJPAEdmProvider.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/api/TestJPAEdmProvider.java new file mode 100644 index 000000000..c6ff47256 --- /dev/null +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/api/TestJPAEdmProvider.java @@ -0,0 +1,314 @@ +/** + * + */ +package com.sap.olingo.jpa.metadata.api; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.List; + +import javax.persistence.EntityManagerFactory; +import javax.sql.DataSource; + +import org.apache.olingo.commons.api.edm.FullQualifiedName; +import org.apache.olingo.commons.api.edm.provider.CsdlAction; +import org.apache.olingo.commons.api.edm.provider.CsdlActionImport; +import org.apache.olingo.commons.api.edm.provider.CsdlAnnotations; +import org.apache.olingo.commons.api.edm.provider.CsdlComplexType; +import org.apache.olingo.commons.api.edm.provider.CsdlEntityContainer; +import org.apache.olingo.commons.api.edm.provider.CsdlEntityContainerInfo; +import org.apache.olingo.commons.api.edm.provider.CsdlEntitySet; +import org.apache.olingo.commons.api.edm.provider.CsdlEntityType; +import org.apache.olingo.commons.api.edm.provider.CsdlEnumType; +import org.apache.olingo.commons.api.edm.provider.CsdlFunction; +import org.apache.olingo.commons.api.edm.provider.CsdlFunctionImport; +import org.apache.olingo.commons.api.edm.provider.CsdlSchema; +import org.apache.olingo.commons.api.edm.provider.CsdlTerm; +import org.apache.olingo.commons.api.edm.provider.CsdlTypeDefinition; +import org.apache.olingo.commons.api.ex.ODataException; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEdmNameBuilder; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAServiceDocument; +import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; +import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediateEntityTypeAccess; +import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediateNavigationPropertyAccess; +import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediatePropertyAccess; +import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediateReferenceList; +import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediateReferenceList.IntermediateReferenceAccess; +import com.sap.olingo.jpa.metadata.core.edm.mapper.impl.CustomJPANameBuilder; +import com.sap.olingo.jpa.processor.core.testmodel.DataSourceHelper; + +/** + * @author Oliver Grande + * Created: 10.02.2020 + * + */ +public class TestJPAEdmProvider { + private static final String PUNIT_NAME = "com.sap.olingo.jpa"; + private static final String[] enumPackages = { "com.sap.olingo.jpa.processor.core.testmodel" }; + private static EntityManagerFactory emf; + private static DataSource ds; + private JPAEdmProvider cut; + private JPAEdmMetadataPostProcessor pp; + + @BeforeAll + public static void setupClass() throws ODataJPAModelException { + ds = DataSourceHelper.createDataSource(DataSourceHelper.DB_H2); + emf = JPAEntityManagerFactory.getEntityManagerFactory(PUNIT_NAME, ds); + } + + @BeforeEach + public void setup() throws ODataException { + cut = new JPAEdmProvider(PUNIT_NAME, emf, null, enumPackages); + } + + @Test + public void checkThrowsExceptionOnMissingNamespace() throws ODataException { + assertThrows(NullPointerException.class, () -> new JPAEdmProvider(null, emf, null, enumPackages)); + } + + @Test + public void checkThrowsExceptionOnMissingEmf() throws ODataException { + final EntityManagerFactory nullFactory = null; + assertThrows(NullPointerException.class, () -> new JPAEdmProvider("Willi", nullFactory, null, enumPackages)); + } + + @Test + public void checkGetSchemas() throws ODataException { + final JPAEdmNameBuilder nameBuilder = new CustomJPANameBuilder(); + cut = new JPAEdmProvider(emf.getMetamodel(), null, null, nameBuilder); + final JPAServiceDocument act = cut.getServiceDocument(); + assertNotNull(act); + assertEquals(nameBuilder, act.getNameBuilder()); + } + + @Test + public void checkGetSchemasReturnsOneSchema() throws ODataException { + final List act = cut.getSchemas(); + assertEquals(1, act.size()); + assertNotNull(act.get(0)); + assertEquals(PUNIT_NAME, act.get(0).getNamespace()); + } + + @Test + public void checkGetEnumReturnsNullOnUnknown() throws ODataException { + final CsdlEnumType act = cut.getEnumType(new FullQualifiedName("Hello", "World")); + assertNull(act); + } + + @Test + public void checkGetEnumReturnsKnownEnum() throws ODataException { + final CsdlEnumType act = cut.getEnumType(new FullQualifiedName(PUNIT_NAME, "AccessRights")); + assertNotNull(act); + assertTrue(act.isFlags()); + } + + @Test + public void checkGetComplexTypeReturnsNullOnUnknown() throws ODataException { + final CsdlComplexType act = cut.getComplexType(new FullQualifiedName("Hello", "World")); + assertNull(act); + } + + @Test + public void checkGetComplexTypeReturnsKnownEnum() throws ODataException { + final CsdlComplexType act = cut.getComplexType(new FullQualifiedName(PUNIT_NAME, "PostalAddressData")); + assertNotNull(act); + assertFalse(act.isAbstract()); + } + + @Test + public void checkGeEntityContainerReturnsContainer() throws ODataException { + final CsdlEntityContainer act = cut.getEntityContainer(); + assertNotNull(act); + assertEquals(cut.getServiceDocument().getNameBuilder().buildContainerName(), act.getName()); + } + + @Test + public void checkGetEntityContainerInfoReturnsNullOnUnknown() throws ODataException { + final CsdlEntityContainerInfo act = cut.getEntityContainerInfo(new FullQualifiedName("Hello", "World")); + assertNull(act); + } + + @Test + public void checkEntityContainerInfoReturnsKnownContainer() throws ODataException { + final String name = cut.getServiceDocument().getNameBuilder().buildContainerName(); + final FullQualifiedName fqn = new FullQualifiedName(PUNIT_NAME, name); + final CsdlEntityContainerInfo act = cut.getEntityContainerInfo(new FullQualifiedName(PUNIT_NAME, name)); + assertNotNull(act); + assertEquals(fqn, act.getContainerName()); + } + + @Test + public void checkEntityContainerInfoReturnsContainerIfNull() throws ODataException { + final FullQualifiedName fqn = buildContainerFQN(); + final CsdlEntityContainerInfo act = cut.getEntityContainerInfo(null); + assertNotNull(act); + assertEquals(fqn, act.getContainerName()); + } + + @Test + public void checkGetEntitySetReturnsNullOnUnknown() throws ODataException { + final FullQualifiedName fqn = buildContainerFQN(); + final CsdlEntitySet act = cut.getEntitySet(fqn, "Hello"); + assertNull(act); + } + + @Test + public void checkGetEntitySetReturnsKnownSet() throws ODataException { + final FullQualifiedName fqn = buildContainerFQN(); + final CsdlEntitySet act = cut.getEntitySet(fqn, "Persons"); + assertNotNull(act); + assertEquals("Persons", act.getName()); + } + + @Test + public void checkGetEntityTypeReturnsNullOnUnknown() throws ODataException { + final CsdlEntityType act = cut.getEntityType(new FullQualifiedName("Hello", "World")); + assertNull(act); + } + + @Test + public void checkGetEntityTypeReturnsKnownEnum() throws ODataException { + final CsdlEntityType act = cut.getEntityType(new FullQualifiedName(PUNIT_NAME, "BusinessPartner")); + assertNotNull(act); + assertTrue(act.isAbstract()); + } + + @Test + public void checkGetFunctionImportReturnsNullOnUnknownContainer() throws ODataException { + final CsdlFunctionImport act = cut.getFunctionImport(new FullQualifiedName("Hello", "World"), "Hello"); + assertNull(act); + } + + @Test + public void checkGetFunctionImportReturnsNullOnUnknownFunction() throws ODataException { + final FullQualifiedName fqn = buildContainerFQN(); + final CsdlFunctionImport act = cut.getFunctionImport(fqn, "Hello"); + assertNull(act); + } + + @Test + public void checkGetFunctionImportReturnsKnownImport() throws ODataException { + final FullQualifiedName fqn = buildContainerFQN(); + final CsdlFunctionImport act = cut.getFunctionImport(fqn, "Siblings"); + assertNotNull(act); + } + + @Test + public void checkGetFunctionsReturnsNullOnUnknownFunction() throws ODataException { + final List act = cut.getFunctions(new FullQualifiedName(PUNIT_NAME, "Hello")); + assertNull(act); + } + + @Test + public void checkGetFunctionsReturnsNullOnUnknownschema() throws ODataException { + final List act = cut.getFunctions(new FullQualifiedName("Hallo", "Welt")); + assertNull(act); + } + + @Test + public void checkGetFunctionsReturnsKnownFunction() throws ODataException { + final List act = cut.getFunctions(new FullQualifiedName(PUNIT_NAME, "PopulationDensity")); + assertNotNull(act); + assertEquals(1, act.size()); + assertEquals(2, act.get(0).getParameters().size()); + } + + @Test + public void checkGetAnnotationsGroupReturnsNull() throws ODataException { + final CsdlAnnotations act = cut.getAnnotationsGroup(new FullQualifiedName(PUNIT_NAME, "Hello"), "World"); + assertNull(act); + } + + @Test + public void checkGetTermReturnsNullOnUnknown() throws ODataException { + final CsdlTerm act = cut.getTerm(new FullQualifiedName("Hello", "World")); + assertNull(act); + } + + @Test + public void checkGetTermReturnsKnownTerm() throws ODataException { + pp = new PostProcessor(); + cut = new JPAEdmProvider(PUNIT_NAME, emf, pp, enumPackages); + final CsdlTerm act = cut.getTerm(new FullQualifiedName("Org.OData.Measures.V1", "ISOCurrency")); + assertNotNull(act); + } + + @Test + public void checkTypeDefinitionReturnsNullOnUnknown() throws ODataException { + final CsdlTypeDefinition act = cut.getTypeDefinition(new FullQualifiedName("Hello", "World")); + assertNull(act); + } + + @Test + public void checkGetActionsReturnsNullOnUnknown() throws ODataException { + final List act = cut.getActions(new FullQualifiedName("Hello", "World")); + assertNull(act); + } + + @Test + public void checkGetActionsReturnsKnownAction() throws ODataException { + final String[] operationPackages = { "com.sap.olingo.jpa.metadata.core.edm.mapper.testaction", + "com.sap.olingo.jpa.processor.core.testmodel" }; + cut = new JPAEdmProvider(PUNIT_NAME, emf, null, operationPackages); + final List act = cut.getActions(new FullQualifiedName(PUNIT_NAME, "BoundNoImport")); + assertNotNull(act); + assertEquals(1, act.size()); + } + + @Test + public void checkGetActionImportReturnsNullOnUnknownContainer() throws ODataException { + final CsdlActionImport act = cut.getActionImport(new FullQualifiedName("Hello", "World"), "Dummy"); + assertNull(act); + } + + @Test + public void checkGetActionImportReturnsNullOnUnknownAction() throws ODataException { + final FullQualifiedName fqn = buildContainerFQN(); + final CsdlActionImport act = cut.getActionImport(fqn, "Dummy"); + assertNull(act); + } + + @Test + public void checkGetActionImportReturnsKnownAction() throws ODataException { + final FullQualifiedName fqn = buildContainerFQN(); + final String[] operationPackages = { "com.sap.olingo.jpa.metadata.core.edm.mapper.testaction", + "com.sap.olingo.jpa.processor.core.testmodel" }; + cut = new JPAEdmProvider(PUNIT_NAME, emf, null, operationPackages); + final CsdlActionImport act = cut.getActionImport(fqn, "WithImport"); + assertNotNull(act); + } + + private FullQualifiedName buildContainerFQN() { + final String name = cut.getServiceDocument().getNameBuilder().buildContainerName(); + final FullQualifiedName fqn = new FullQualifiedName(PUNIT_NAME, name); + return fqn; + } + + private class PostProcessor extends JPAEdmMetadataPostProcessor { + @Override + public void processNavigationProperty(final IntermediateNavigationPropertyAccess property, + final String jpaManagedTypeClassName) {} + + @Override + public void processProperty(final IntermediatePropertyAccess property, final String jpaManagedTypeClassName) {} + + @Override + public void processEntityType(IntermediateEntityTypeAccess entity) {} + + @Override + public void provideReferences(final IntermediateReferenceList references) throws ODataJPAModelException { + String uri = "http://docs.oasisopen.org/odata/odata/v4.0/os/vocabularies/Org.OData.Measures.V1.xml"; + IntermediateReferenceAccess reference = references.addReference(uri, "annotations/Org.OData.Measures.V1.xml"); + reference.addInclude("Org.OData.Core.V1", "Core"); + } + } +} diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/TestAnnotationPOJO.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/TestAnnotationPOJO.java index 9ccf8eb70..448105698 100644 --- a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/TestAnnotationPOJO.java +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/TestAnnotationPOJO.java @@ -1,12 +1,12 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.annotation; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import java.io.IOException; import java.util.List; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.JsonMappingException; @@ -49,9 +49,9 @@ public void TestSimpleXMLConverted() throws JsonParseException, JsonMappingExcep assertNotNull(act.getDataService()); Schema[] actSchemas = act.getDataService().getSchemas(); - assertEquals(actSchemas.length, 1); + assertEquals(1, actSchemas.length); List actTerms = actSchemas[0].getTerms(); - assertEquals(actTerms.size(), 3); + assertEquals(3, actTerms.size()); } } diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/TestSchemaReader.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/TestSchemaReader.java index 5e076a482..f20961099 100644 --- a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/TestSchemaReader.java +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/TestSchemaReader.java @@ -1,28 +1,75 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.annotation; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.io.IOException; +import java.net.URI; +import java.util.List; import java.util.Map; +import org.apache.olingo.commons.api.edm.geo.SRID; +import org.apache.olingo.commons.api.edm.provider.CsdlAction; +import org.apache.olingo.commons.api.edm.provider.CsdlComplexType; +import org.apache.olingo.commons.api.edm.provider.CsdlEnumMember; +import org.apache.olingo.commons.api.edm.provider.CsdlEnumType; +import org.apache.olingo.commons.api.edm.provider.CsdlFunction; +import org.apache.olingo.commons.api.edm.provider.CsdlParameter; +import org.apache.olingo.commons.api.edm.provider.CsdlProperty; +import org.apache.olingo.commons.api.edm.provider.CsdlReturnType; import org.apache.olingo.commons.api.edm.provider.CsdlSchema; -import org.junit.Before; -import org.junit.Test; +import org.apache.olingo.commons.api.edm.provider.CsdlTypeDefinition; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.databind.JsonMappingException; +import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; public class TestSchemaReader { private SchemaReader cut; - @Before + @BeforeEach public void setup() { cut = new SchemaReader(); } @Test - public void TestGetNamespaceFromPath() throws JsonParseException, JsonMappingException, IOException { + public void testConvertEDMXReturnsNullIfEDMXNull() throws ODataJPAModelException, IOException { + assertNull(cut.convertEDMX(null)); + } + + @Test + public void testConvertEDMXReturnsNullIfDataServiceNull() throws ODataJPAModelException, IOException { + final Edmx edmx = mock(Edmx.class); + when(edmx.getDataService()).thenReturn(null); + assertNull(cut.convertEDMX(edmx)); + } + + @Test + public void testReadXMLWithNullPath() throws ODataJPAModelException, IOException { + final String nullString = null; + assertEquals(0, cut.getSchemas(nullString).size()); + } + + @Test + public void testReadXMLWithEmptyPath() throws ODataJPAModelException, IOException { + final String emptyString = new String(); + assertEquals(0, cut.getSchemas(emptyString).size()); + } + + @Test + public void testReadXMLWithNullURI() throws ODataJPAModelException, IOException { + final URI nullURI = null; + assertEquals(0, cut.getSchemas(nullURI).size()); + } + + @Test + public void testGetNamespaceFromPath() throws IOException, ODataJPAModelException { Map act; act = cut.getSchemas("annotations/Org.OData.Core.V1.xml"); assertNotNull(act.get("Org.OData.Core.V1")); @@ -31,7 +78,7 @@ public void TestGetNamespaceFromPath() throws JsonParseException, JsonMappingExc } @Test - public void TestGetAliasFromPath() throws JsonParseException, JsonMappingException, IOException { + public void testGetAliasFromPath() throws IOException, ODataJPAModelException { Map act; act = cut.getSchemas("annotations/Org.OData.Core.V1.xml"); assertNotNull(act.get("Org.OData.Core.V1")); @@ -40,38 +87,348 @@ public void TestGetAliasFromPath() throws JsonParseException, JsonMappingExcepti } @Test - public void TestGetTermsFromPath() throws JsonParseException, JsonMappingException, IOException { + public void testGetTermsFromPath() throws IOException, ODataJPAModelException { Map act; act = cut.getSchemas("annotations/Org.OData.Core.V1.xml"); assertNotNull(act.get("Org.OData.Core.V1")); CsdlSchema schema = act.get("Org.OData.Core.V1"); - assertEquals(15, schema.getTerms().size()); + assertEquals(28, schema.getTerms().size()); } @Test - public void TestGetTypeDefinitionFromPath() throws JsonParseException, JsonMappingException, IOException { + public void testGetTypeDefinitionFromPath() throws IOException, ODataJPAModelException { Map act; act = cut.getSchemas("annotations/Org.OData.Core.V1.xml"); assertNotNull(act.get("Org.OData.Core.V1")); CsdlSchema schema = act.get("Org.OData.Core.V1"); - assertEquals(1, schema.getTypeDefinitions().size()); + assertEquals(4, schema.getTypeDefinitions().size()); assertNotNull(schema.getTypeDefinition("Tag")); assertEquals("Edm.Boolean", schema.getTypeDefinition("Tag").getUnderlyingType()); } @Test - public void TestGetEnumSchemaFromPath() throws JsonParseException, JsonMappingException, IOException { + public void testGetTypeDefinitions() throws IOException, ODataJPAModelException { + final CsdlSchema act = cut.getSchemas("annotations/Org.Olingo.Test.V1.xml") + .get("Org.OData.Capabilities.V1"); + assertEquals(3, act.getTypeDefinitions().size()); + + assertNotNull(act.getTypeDefinition("TestTypeDecimal")); + CsdlTypeDefinition actType = act.getTypeDefinition("TestTypeDecimal"); + assertEquals(10, actType.getPrecision()); + assertEquals(5, actType.getScale()); + assertNull(actType.getSrid()); + assertNull(actType.getMaxLength()); + + actType = act.getTypeDefinition("TestTypeGeo"); + assertNull(actType.getPrecision()); + assertNull(actType.getScale()); + assertEquals(SRID.valueOf("variable"), actType.getSrid()); + assertNull(actType.getMaxLength()); + assertTrue(actType.isUnicode()); + + actType = act.getTypeDefinition("TestTypeString"); + assertNull(actType.getPrecision()); + assertNull(actType.getScale()); + assertNull(actType.getSrid()); + assertEquals(256, actType.getMaxLength()); + assertFalse(actType.isUnicode()); + } + + @Test + public void testGetEnumSchemaFromPath() throws IOException, ODataJPAModelException { Map act; act = cut.getSchemas("annotations/Org.OData.Core.V1.xml"); assertNotNull(act.get("Org.OData.Core.V1")); CsdlSchema schema = act.get("Org.OData.Core.V1"); assertEquals(1, schema.getEnumTypes().size()); assertNotNull(schema.getEnumType("Permission")); - assertEquals(3, schema.getEnumType("Permission").getMembers().size()); + assertEquals(5, schema.getEnumType("Permission").getMembers().size()); assertEquals("3", schema.getEnumType("Permission").getMember("ReadWrite").getValue()); } -// csdlSchema.setEnumTypes(asEnumTypes()); -// csdlSchema.setComplexTypes(asComplexTypes()); -// csdlSchema.setTypeDefinitions(asTypeDefinitions()); + @Test + public void testThrowsExceptionOnUnknownPath() throws IOException { + assertThrows(ODataJPAModelException.class, () -> { + cut.getSchemas("annotations/Org.OData.Core.V2.xml"); + }); + } + + @Test + public void testThrowsExceptionOnEmptyXML() throws IOException, ODataJPAModelException { + + assertThrows(IOException.class, () -> { + cut.getSchemas("annotations/empty.xml"); + }); + } + + @Test + public void testGetSimpleComplexTypes() throws IOException, ODataJPAModelException { + final Map act; + act = cut.getSchemas("annotations/Org.Olingo.Test.V1.xml"); + assertEquals(2, act.size()); + assertTrue(act.containsKey("Org.OData.Capabilities.V1")); + final CsdlSchema actSchema = act.get("Org.OData.Capabilities.V1"); + final CsdlComplexType actCt = actSchema.getComplexType("UpdateRestrictionsType"); + assertNotNull(actCt); + assertNull(actCt.getBaseType()); + assertNull(actCt.getBaseTypeFQN()); + assertFalse(actCt.isAbstract()); + assertFalse(actCt.isOpenType()); + assertEquals("UpdateRestrictionsType", actCt.getName()); + assertEquals(2, actCt.getProperties().size()); + assertEquals(0, actCt.getNavigationProperties().size()); + assertEquals(0, actCt.getAnnotations().size()); + } + + @Test + public void testGetDeepComplexTypes() throws IOException, ODataJPAModelException { + final CsdlComplexType actCt = cut.getSchemas("annotations/Org.Olingo.Test.V1.xml") + .get("Org.OData.Capabilities.V1").getComplexType("TestType"); + assertNotNull(actCt); + assertEquals(5, actCt.getProperties().size()); + assertTrue(actCt.isAbstract()); + assertTrue(actCt.isOpenType()); + assertNotNull(actCt.getBaseType()); + assertEquals("Core.Unknown", actCt.getBaseType()); + assertEquals("Core.Unknown", actCt.getBaseTypeFQN().getFullQualifiedNameAsString()); + assertEquals(0, actCt.getAnnotations().size()); // Annotations are ignored + } + + @Test + public void testGetSimpleProperty() throws IOException, ODataJPAModelException { + final CsdlComplexType actCt = cut.getSchemas("annotations/Org.Olingo.Test.V1.xml") + .get("Org.OData.Capabilities.V1").getComplexType("TestType"); + final CsdlProperty actProperty = actCt.getProperty("Deletable"); + assertNotNull(actProperty); + assertEquals("Deletable", actProperty.getName()); + assertEquals("Edm.Boolean", actProperty.getType()); + assertEquals("true", actProperty.getDefaultValue()); + assertNull(actProperty.getMaxLength()); + assertNull(actProperty.getScale()); + assertNull(actProperty.getSrid()); + assertNull(actProperty.getPrecision()); + assertTrue(actProperty.isUnicode()); + } + + @Test + public void testGetDecimalProperty() throws IOException, ODataJPAModelException { + final CsdlComplexType actCt = cut.getSchemas("annotations/Org.Olingo.Test.V1.xml") + .get("Org.OData.Capabilities.V1").getComplexType("TestType"); + final CsdlProperty actProperty = actCt.getProperty("TestDecimals"); + assertNotNull(actProperty); + assertEquals("TestDecimals", actProperty.getName()); + assertEquals("Edm.Decimal", actProperty.getType()); + assertNull(actProperty.getDefaultValue()); + assertNull(actProperty.getMaxLength()); + assertEquals(5, actProperty.getScale()); + assertNull(actProperty.getSrid()); + assertEquals(10, actProperty.getPrecision()); + assertTrue(actProperty.isUnicode()); + } + + @Test + public void testGetStringProperty() throws IOException, ODataJPAModelException { + final CsdlComplexType actCt = cut.getSchemas("annotations/Org.Olingo.Test.V1.xml") + .get("Org.OData.Capabilities.V1").getComplexType("TestType"); + final CsdlProperty actProperty = actCt.getProperty("TestString"); + assertNotNull(actProperty); + assertEquals("TestString", actProperty.getName()); + assertEquals("Edm.String", actProperty.getType()); + assertNull(actProperty.getDefaultValue()); + assertEquals(256, actProperty.getMaxLength()); + assertNull(actProperty.getScale()); + assertNull(actProperty.getSrid()); + assertNull(actProperty.getPrecision()); + assertFalse(actProperty.isUnicode()); + } + + @Test + public void testGetGeoProperty() throws IOException, ODataJPAModelException { + final CsdlComplexType actCt = cut.getSchemas("annotations/Org.Olingo.Test.V1.xml") + .get("Org.OData.Capabilities.V1").getComplexType("TestType"); + final CsdlProperty actProperty = actCt.getProperty("TestGeo"); + assertNotNull(actProperty); + assertEquals("TestGeo", actProperty.getName()); + assertEquals("Edm.GeometryPoint", actProperty.getType()); + assertNull(actProperty.getDefaultValue()); + assertNull(actProperty.getMaxLength()); + assertNull(actProperty.getScale()); + assertEquals(SRID.valueOf("3857"), actProperty.getSrid()); + assertNull(actProperty.getPrecision()); + assertTrue(actProperty.isUnicode()); + assertFalse(actProperty.isCollection()); + } + + @Test + public void testGetCollectionProperty() throws IOException, ODataJPAModelException { + final CsdlComplexType actCt = cut.getSchemas("annotations/Org.Olingo.Test.V1.xml") + .get("Org.OData.Capabilities.V1").getComplexType("TestType"); + final CsdlProperty actProperty = actCt.getProperty("NonDeletableNavigationProperties"); + assertNotNull(actProperty); + assertEquals("NonDeletableNavigationProperties", actProperty.getName()); + assertEquals("Edm.NavigationPropertyPath", actProperty.getType()); + assertTrue(actProperty.isCollection()); + } + + @Test + public void testGetEnum() throws IOException, ODataJPAModelException { + final CsdlSchema act = cut.getSchemas("annotations/Org.OData.Capabilities.V1.xml") + .get("Org.OData.Capabilities.V1"); + assertEquals(4, act.getEnumTypes().size()); + } + + @Test + public void testGetEnumNotAsFlags() throws IOException, ODataJPAModelException { + final CsdlEnumType actEnum = cut.getSchemas("annotations/Org.OData.Aggregation.V1.xml") + .get("Org.OData.Aggregation.V1").getEnumType("RollupType"); + assertNotNull(actEnum); + assertEquals(3, actEnum.getMembers().size()); + assertNotNull(actEnum.getMember("MultipleHierarchies")); + assertNull(actEnum.getUnderlyingType()); + assertFalse(actEnum.isFlags()); + } + + @Test + public void testGetEnumAsFlags() throws IOException, ODataJPAModelException { + final CsdlEnumType actEnum = cut.getSchemas("annotations/Org.OData.Capabilities.V1.xml") + .get("Org.OData.Capabilities.V1").getEnumType("IsolationLevel"); + assertNotNull(actEnum); + assertEquals(1, actEnum.getMembers().size()); + assertNotNull(actEnum.getMember(1)); + assertNull(actEnum.getUnderlyingType()); + assertTrue(actEnum.isFlags()); + final CsdlEnumMember actMember = actEnum.getMember(1); + assertEquals("Snapshot", actMember.getName()); + assertEquals("1", actMember.getValue()); + } + + @Test + public void testGetFunctions() throws IOException, ODataJPAModelException { + final CsdlSchema act = cut.getSchemas("annotations/Org.OData.Aggregation.V1.xml") + .get("Org.OData.Aggregation.V1"); + assertEquals(5, act.getFunctions().size()); + } + + @Test + public void testGetFunctionAttributes() throws IOException, ODataJPAModelException { + final List act = cut.getSchemas("annotations/Org.OData.Aggregation.V1.xml") + .get("Org.OData.Aggregation.V1").getFunctions("isleaf"); + assertEquals(1, act.size()); + final CsdlFunction actFunc = act.get(0); + assertEquals("isleaf", actFunc.getName()); + assertEquals(2, actFunc.getParameters().size()); + assertTrue(actFunc.isBound()); + assertFalse(actFunc.isComposable()); + assertNotNull(actFunc.getReturnType()); + } + + @Test + public void testGetFunctionParameter() throws IOException, ODataJPAModelException { + final List act = cut.getSchemas("annotations/Org.OData.Aggregation.V1.xml") + .get("Org.OData.Aggregation.V1").getFunctions("isancestor"); + + final CsdlFunction actFunc = act.get(0); + assertEquals(4, actFunc.getParameters().size()); + final CsdlParameter actMendatory = actFunc.getParameter("Entity"); + assertNotNull(actMendatory); + assertEquals("Entity", actMendatory.getName()); + assertEquals("Edm.EntityType", actMendatory.getType()); + assertFalse(actMendatory.isNullable()); + + final CsdlParameter actNullable = actFunc.getParameter("MaxDistance"); + assertTrue(actNullable.isNullable()); + } + + @Test + public void testGetFunctionParameterFacet() throws IOException, ODataJPAModelException { + final List act = cut.getSchemas("annotations/Org.Olingo.Test.V1.xml") + .get("Org.OData.Capabilities.V1").getFunctions("TestTheRest1"); + + final CsdlFunction actFunc = act.get(0); + final CsdlParameter actDecimal = actFunc.getParameter("Dec"); + assertEquals("Edm.Decimal", actDecimal.getTypeFQN().getFullQualifiedNameAsString()); + assertEquals(10, actDecimal.getPrecision()); + assertEquals(5, actDecimal.getScale()); + assertTrue(actDecimal.isNullable()); + + final CsdlParameter actGeo = actFunc.getParameter("Geo"); + assertEquals(SRID.valueOf("3857"), actGeo.getSrid()); + assertTrue(actGeo.isNullable()); + assertFalse(actGeo.isCollection()); + + final CsdlParameter actString = actFunc.getParameter("Text"); + assertEquals("Edm.String", actString.getType()); + assertTrue(actString.isCollection()); + assertEquals(512, actString.getMaxLength()); + } + + @Test + public void testGetFunctionReturnType() throws IOException, ODataJPAModelException { + final List act = cut.getSchemas("annotations/Org.OData.Aggregation.V1.xml") + .get("Org.OData.Aggregation.V1").getFunctions("isancestor"); + + final CsdlFunction actFunc = act.get(0); + final CsdlReturnType actReturn = actFunc.getReturnType(); + assertNotNull(actReturn); + assertEquals("Edm.Boolean", actReturn.getType()); + assertFalse(actReturn.isNullable()); + assertNull(actReturn.getMaxLength()); + assertNull(actReturn.getScale()); + assertNull(actReturn.getSrid()); + assertNull(actReturn.getPrecision()); + assertFalse(actReturn.isCollection()); + } + + @Test + public void testGetFunctionReturnTypeFacet() throws IOException, ODataJPAModelException { + final List act = cut.getSchemas("annotations/Org.Olingo.Test.V1.xml") + .get("Org.OData.Capabilities.V1").getFunctions("TestTheRest1"); + + final CsdlFunction actFunc = act.get(0); + assertEquals("timeslices", actFunc.getEntitySetPath()); + final CsdlReturnType actReturn = actFunc.getReturnType(); + assertNotNull(actReturn); + assertEquals("Edm.Decimal", actReturn.getTypeFQN().getFullQualifiedNameAsString()); + assertEquals(10, actReturn.getPrecision()); + assertEquals(5, actReturn.getScale()); + assertTrue(actReturn.isNullable()); + assertTrue(actReturn.isCollection()); + assertEquals(20, actReturn.getMaxLength()); + assertEquals(SRID.valueOf("3857"), actReturn.getSrid()); + } + + @Test + public void testGetActionss() throws IOException, ODataJPAModelException { + final List act = cut.getSchemas("annotations/Org.Olingo.Test.V1.xml") + .get("Org.OData.Capabilities.V1").getActions(); + assertEquals(2, act.size()); + } + + @Test + public void testGetActionParameter() throws IOException, ODataJPAModelException { + final List act = cut.getSchemas("annotations/Org.Olingo.Test.V1.xml") + .get("Org.OData.Capabilities.V1").getActions("UpsertTimeExample"); + + final CsdlAction actAction = act.get(0); + assertEquals(3, actAction.getParameters().size()); + assertTrue(actAction.isBound()); + assertEquals("UpsertTimeExample", actAction.getName()); + assertEquals("timeslices", actAction.getEntitySetPath()); + final CsdlParameter actParam = actAction.getParameter("timeslices"); + assertEquals("Edm.EntityType", actParam.getTypeFQN().getFullQualifiedNameAsString()); + assertTrue(actParam.isCollection()); + assertFalse(actParam.isNullable()); + } + + @Test + public void testGetActionReturnType() throws IOException, ODataJPAModelException { + final List act = cut.getSchemas("annotations/Org.Olingo.Test.V1.xml") + .get("Org.OData.Capabilities.V1").getActions("UpsertTimeExample"); + + final CsdlAction actAction = act.get(0); + assertNotNull(actAction.getReturnType()); + final CsdlReturnType actReturn = actAction.getReturnType(); + assertFalse(actReturn.isNullable()); + assertTrue(actReturn.isCollection()); + } } diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/TestTermReader.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/TestTermReader.java index 5441195a0..040ed7165 100644 --- a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/TestTermReader.java +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/annotation/TestTermReader.java @@ -1,8 +1,12 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.annotation; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.io.IOException; import java.net.MalformedURLException; @@ -11,43 +15,70 @@ import java.util.Map; import org.apache.olingo.commons.api.edm.provider.CsdlTerm; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.JsonMappingException; +import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; public class TestTermReader { private TermReader cut; - @Before + @BeforeEach public void setup() { cut = new TermReader(); } @Test - public void TestReadFromResource() throws JsonParseException, JsonMappingException, IOException { + public void testConvertEDMXReturnsNullIfEDMXNull() throws ODataJPAModelException, IOException { + assertNull(cut.convertEDMX(null)); + } + + @Test + public void testConvertEDMXReturnsNullIfDataServiceNull() throws ODataJPAModelException, IOException { + final Edmx edmx = mock(Edmx.class); + when(edmx.getDataService()).thenReturn(null); + assertNull(cut.convertEDMX(edmx)); + } + + @Test + public void testGetTermsByUriThrowsExceptionOnNull() throws IOException { + final URI nullUri = null; + assertThrows(NullPointerException.class, () -> cut.getTerms(nullUri)); + } + + @Test + public void testGetTermsByPathThrowsExceptionOnNull() throws IOException { + final String nullString = null; + assertThrows(NullPointerException.class, () -> cut.getTerms(nullString)); + } + + @Test + public void testReadFromResource() throws JsonParseException, JsonMappingException, IOException, + ODataJPAModelException { Edmx actEdmx = cut.readFromResource("annotations/Org.OData.Measures.V1.xml"); assertNotNull(actEdmx); assertNotNull(actEdmx.getDataService()); Schema[] actSchemas = actEdmx.getDataService().getSchemas(); - assertEquals(actSchemas.length, 1); + assertEquals(1, actSchemas.length); assertEquals("Org.OData.Measures.V1", actSchemas[0].getNamespace()); } @Test - public void TestGetTermsOneSchemaFromPath() throws JsonParseException, JsonMappingException, IOException { + public void testGetTermsOneSchemaFromPath() throws JsonParseException, JsonMappingException, IOException, + ODataJPAModelException { Map> act; act = cut.getTerms("annotations/Org.OData.Core.V1.xml"); assertNotNull(act.get("Org.OData.Core.V1")); Map terms = act.get("Org.OData.Core.V1"); - assertEquals(15, terms.size()); + assertEquals(28, terms.size()); } @Test - public void TestGetAppliesTo() throws JsonParseException, JsonMappingException, IOException { + public void testGetAppliesTo() throws JsonParseException, JsonMappingException, IOException, ODataJPAModelException { Map> act; act = cut.getTerms("annotations/Org.OData.Core.V1.xml"); assertNotNull(act.get("Org.OData.Core.V1")); @@ -59,7 +90,8 @@ public void TestGetAppliesTo() throws JsonParseException, JsonMappingException, } @Test - public void TestGetTermsTwoSchemaFromPath() throws JsonParseException, JsonMappingException, IOException { + public void testGetTermsTwoSchemaFromPath() throws JsonParseException, JsonMappingException, IOException, + ODataJPAModelException { Map> act; act = cut.getTerms("annotations/Org.Olingo.Test.V1.xml"); assertNotNull(act.get("Org.OData.Measures.V1")); @@ -67,9 +99,9 @@ public void TestGetTermsTwoSchemaFromPath() throws JsonParseException, JsonMappi } // TODO This test may not run because of proxy setting problems!! -> find alternative for Integration tests - @Ignore + @Disabled @Test - public void TestReadFromURI() throws URISyntaxException, JsonParseException, JsonMappingException, + public void testReadFromURI() throws URISyntaxException, JsonParseException, JsonMappingException, MalformedURLException, IOException { URI uri = new URI("http://docs.oasis-open.org/odata/odata/v4.0/os/vocabularies/Org.OData.Core.V1.xml"); Edmx actEdmx = cut.readFromURI(uri); @@ -77,19 +109,18 @@ public void TestReadFromURI() throws URISyntaxException, JsonParseException, Jso assertNotNull(actEdmx.getDataService()); Schema[] actSchemas = actEdmx.getDataService().getSchemas(); - assertEquals(actSchemas.length, 1); - assertEquals(actSchemas[0].getNamespace(), "Org.OData.Core.V1"); + assertEquals(1, actSchemas.length); + assertEquals("Org.OData.Core.V1", actSchemas[0].getNamespace()); } // TODO This test may not run because of proxy setting problems!! -> find alternative for Integration tests - @Ignore + @Disabled @Test - public void TestGetTermsOneSchemaFromURI() throws URISyntaxException, JsonParseException, JsonMappingException, + public void testGetTermsOneSchemaFromURI() throws URISyntaxException, JsonParseException, JsonMappingException, MalformedURLException, IOException { URI uri = new URI("http://docs.oasis-open.org/odata/odata/v4.0/os/vocabularies/Org.OData.Core.V1.xml"); Map> act; act = cut.getTerms(uri); assertNotNull(act.get("Org.OData.Core.V1")); } - } diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/exception/TestODataJPAMessageTextBuffer.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/exception/TestODataJPAMessageTextBuffer.java index 8a50f0f2a..47adb235b 100644 --- a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/exception/TestODataJPAMessageTextBuffer.java +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/exception/TestODataJPAMessageTextBuffer.java @@ -1,13 +1,13 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.exception; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.ArrayList; import java.util.Enumeration; import java.util.Locale; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import com.sap.olingo.jpa.processor.core.testmodel.LocaleEnumeration; @@ -15,7 +15,7 @@ public class TestODataJPAMessageTextBuffer { private static String BUNDLE_NAME = "test-i18n"; private ODataJPAMessageTextBuffer cut; - @Before + @BeforeEach public void setup() { cut = new ODataJPAMessageTextBuffer(BUNDLE_NAME); } @@ -93,7 +93,7 @@ public void checkSetLocalesRestDefaultWithEmpty() { @Test public void checkSetLocalesFirstMatches() { - ArrayList localesList = new ArrayList(); + ArrayList localesList = new ArrayList<>(); localesList.add(Locale.GERMAN); localesList.add(Locale.CANADA_FRENCH); Enumeration locales = new LocaleEnumeration(localesList); @@ -105,7 +105,7 @@ public void checkSetLocalesFirstMatches() { @Test public void checkSetLocalesSecondMatches() { - ArrayList localesList = new ArrayList(); + ArrayList localesList = new ArrayList<>(); localesList.add(Locale.CANADA_FRENCH); localesList.add(Locale.GERMAN); Enumeration locales = new LocaleEnumeration(localesList); @@ -117,7 +117,7 @@ public void checkSetLocalesSecondMatches() { @Test public void checkSetLocalesNonMatches() { - ArrayList localesList = new ArrayList(); + ArrayList localesList = new ArrayList<>(); localesList.add(Locale.CANADA_FRENCH); localesList.add(Locale.SIMPLIFIED_CHINESE); Enumeration locales = new LocaleEnumeration(localesList); diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/exception/TestODataJPAModelException.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/exception/TestODataJPAModelException.java index 73d92da76..86537f89b 100644 --- a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/exception/TestODataJPAModelException.java +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/exception/TestODataJPAModelException.java @@ -1,15 +1,14 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.exception; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; import java.util.ArrayList; import java.util.Enumeration; import java.util.Locale; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAException; import com.sap.olingo.jpa.processor.core.testmodel.LocaleEnumeration; public class TestODataJPAModelException { @@ -29,7 +28,7 @@ public void checkTextInDefaultLocale() { @Test public void checkTextInGerman() { try { - ArrayList localesList = new ArrayList(); + ArrayList localesList = new ArrayList<>(); localesList.add(Locale.GERMAN); Enumeration locales = new LocaleEnumeration(localesList); TestException.setLocales(locales); diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/CustomJPANameBuilder.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/CustomJPANameBuilder.java new file mode 100644 index 000000000..1ee01c09e --- /dev/null +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/CustomJPANameBuilder.java @@ -0,0 +1,76 @@ +/** + * + */ +package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; + +import java.util.stream.IntStream; + +import javax.persistence.metamodel.Attribute; +import javax.persistence.metamodel.EmbeddableType; +import javax.persistence.metamodel.EntityType; + +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEdmNameBuilder; + +/** + * @author Oliver Grande + * Created: 19.09.2019 + * + */ +public class CustomJPANameBuilder implements JPAEdmNameBuilder { + + @Override + public String buildComplexTypeName(EmbeddableType jpaEnbeddedType) { + return new StringBuilder("T_").append(jpaEnbeddedType.getJavaType().getSimpleName()).toString(); + } + + @Override + public String buildContainerName() { + return "service_container"; + } + + @Override + public String buildEntitySetName(String entityTypeName) { + return entityTypeName.toUpperCase(); + } + + @Override + public String buildEntityTypeName(EntityType jpaEntityType) { + final StringBuilder externalName = new StringBuilder(); + final IntStream name = jpaEntityType.getName().chars(); + name.forEach(i -> this.appeendChar(externalName, i)); + externalName.deleteCharAt(0); + return externalName.toString(); + } + + @Override + public String buildEnumerationTypeName(Class> javaEnum) { + return new StringBuilder("E_").append(javaEnum.getSimpleName()).toString(); + } + + @Override + public String buildNaviPropertyName(Attribute jpaAttribute) { + return jpaAttribute.getName(); + } + + @Override + public String buildOperationName(String internalOperationName) { + return new StringBuilder("O_").append(internalOperationName).toString(); + } + + @Override + public String buildPropertyName(String jpaAttributeName) { + return jpaAttributeName; + } + + @Override + public String getNamespace() { + return "test"; + } + + private void appeendChar(final StringBuilder builder, int i) { + if (Character.isUpperCase(i)) + builder.append('_').append(Character.toChars(i)[0]); + else + builder.append(Character.toChars(i)[0]); + } +} diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestHelper.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestHelper.java index 52554b513..82747f9c1 100644 --- a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestHelper.java +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestHelper.java @@ -1,8 +1,11 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.lang.reflect.AnnotatedElement; +import java.util.Arrays; +import java.util.HashSet; import java.util.List; import javax.persistence.metamodel.Attribute; @@ -10,29 +13,52 @@ import javax.persistence.metamodel.EntityType; import javax.persistence.metamodel.ManagedType; import javax.persistence.metamodel.Metamodel; +import javax.persistence.metamodel.PluralAttribute; import javax.persistence.metamodel.SingularAttribute; import org.reflections.Reflections; +import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmEnumeration; import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmFunction; import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmFunctions; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAAttribute; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; +import com.sap.olingo.jpa.processor.core.testmodel.ABCClassifiaction; +import com.sap.olingo.jpa.processor.core.testmodel.AccessRights; public class TestHelper { final private Metamodel jpaMetamodel; final public IntermediateSchema schema; public TestHelper(final Metamodel metamodel, final String namespace) throws ODataJPAModelException { + final Reflections r = mock(Reflections.class); + when(r.getTypesAnnotatedWith(EdmEnumeration.class)).thenReturn(new HashSet<>(Arrays.asList(new Class[] { + ABCClassifiaction.class, AccessRights.class }))); + this.jpaMetamodel = metamodel; - this.schema = new IntermediateSchema(new JPAEdmNameBuilder(namespace), jpaMetamodel, mock(Reflections.class)); + this.schema = new IntermediateSchema(new JPADefaultEdmNameBuilder(namespace), jpaMetamodel, r); } - public EntityType getEntityType(final String typeName) { - for (final EntityType entityType : jpaMetamodel.getEntities()) { - if (entityType.getJavaType().getSimpleName().equals(typeName)) { - return entityType; - } + public Object findAttribute(final List attributes, final String searchItem) { + for (final JPAAttribute attribute : attributes) { + if (attribute.getExternalName().equals(searchItem)) + return attribute; + } + return null; + } + + public Attribute getAttribute(final ManagedType et, final String attributeName) { + for (final SingularAttribute attribute : et.getSingularAttributes()) { + if (attribute.getName().equals(attributeName)) + return attribute; + } + return null; + } + + public PluralAttribute getCollectionAttribute(final ManagedType et, final String attributeName) { + for (final PluralAttribute attribute : et.getPluralAttributes()) { + if (attribute.getName().equals(attributeName)) + return attribute; } return null; } @@ -46,48 +72,50 @@ public EmbeddableType getComplexType(final String typeName) { return null; } - public EdmFunction getStoredProcedure(EntityType jpaEntityType, String string) { - if (jpaEntityType.getJavaType() instanceof AnnotatedElement) { - final EdmFunctions jpaStoredProcedureList = ((AnnotatedElement) jpaEntityType.getJavaType()) - .getAnnotation(EdmFunctions.class); - if (jpaStoredProcedureList != null) { - for (final EdmFunction jpaStoredProcedure : jpaStoredProcedureList.value()) { - if (jpaStoredProcedure.name().equals(string)) return jpaStoredProcedure; - } - } + public Attribute getDeclaredAttribute(final ManagedType et, final String attributeName) { + for (final Attribute attribute : et.getDeclaredAttributes()) { + if (attribute.getName().equals(attributeName)) + return attribute; } return null; } - public Attribute getAttribute(final ManagedType et, final String attributeName) { - for (final SingularAttribute attribute : et.getSingularAttributes()) { - if (attribute.getName().equals(attributeName)) - return attribute; + public EmbeddableType getEmbeddedableType(final String typeName) { + for (final EmbeddableType embeddableType : jpaMetamodel.getEmbeddables()) { + if (embeddableType.getJavaType().getSimpleName().equals(typeName)) { + return embeddableType; + } } return null; } - public EmbeddableType getEmbeddedableType(String typeName) { + public EmbeddableType getEmbeddedableType(final Class clazz) { for (final EmbeddableType embeddableType : jpaMetamodel.getEmbeddables()) { - if (embeddableType.getJavaType().getSimpleName().equals(typeName)) { + if (embeddableType.getJavaType().getSimpleName().equals(clazz.getSimpleName())) { return embeddableType; } } return null; } - public Attribute getDeclaredAttribute(final ManagedType et, final String attributeName) { - for (final Attribute attribute : et.getDeclaredAttributes()) { - if (attribute.getName().equals(attributeName)) - return attribute; + public EntityType getEntityType(final Class clazz) { + for (final EntityType entityType : jpaMetamodel.getEntities()) { + if (entityType.getJavaType().getSimpleName().equals(clazz.getSimpleName())) { + return entityType; + } } return null; } - public Object findAttribute(final List attributes, final String searchItem) { - for (final JPAAttribute attribute : attributes) { - if (attribute.getExternalName().equals(searchItem)) - return attribute; + public EdmFunction getStoredProcedure(EntityType jpaEntityType, String string) { + if (jpaEntityType.getJavaType() instanceof AnnotatedElement) { + final EdmFunctions jpaStoredProcedureList = ((AnnotatedElement) jpaEntityType.getJavaType()) + .getAnnotation(EdmFunctions.class); + if (jpaStoredProcedureList != null) { + for (final EdmFunction jpaStoredProcedure : jpaStoredProcedureList.value()) { + if (jpaStoredProcedure.name().equals(string)) return jpaStoredProcedure; + } + } } return null; } diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateActionFactory.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateActionFactory.java index 09cda2a48..45cc9ce59 100644 --- a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateActionFactory.java +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateActionFactory.java @@ -1,7 +1,7 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -9,8 +9,8 @@ import java.util.Map; import java.util.Set; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.reflections.Reflections; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; @@ -25,31 +25,31 @@ public class TestIntermediateActionFactory extends TestMappingRoot { private IntermediateActionFactory cut; private Set> javaActions; - @Before + @BeforeEach public void setUp() throws ODataJPAModelException { helper = new TestHelper(emf.getMetamodel(), PUNIT_NAME); reflections = mock(Reflections.class); cut = new IntermediateActionFactory(); - javaActions = new HashSet>(); + javaActions = new HashSet<>(); when(reflections.getSubTypesOf(ODataAction.class)).thenReturn(javaActions); } @Test public void checkReturnEmptyMapIfReflectionsNull() throws ODataJPAModelException { Reflections r = null; - assertNotNull(cut.create(new JPAEdmNameBuilder(PUNIT_NAME), r, helper.schema)); + assertNotNull(cut.create(new JPADefaultEdmNameBuilder(PUNIT_NAME), r, helper.schema)); } @Test public void checkReturnEmptyMapIfNoJavaFunctionsFound() throws ODataJPAModelException { - assertNotNull(cut.create(new JPAEdmNameBuilder(PUNIT_NAME), reflections, helper.schema)); + assertNotNull(cut.create(new JPADefaultEdmNameBuilder(PUNIT_NAME), reflections, helper.schema)); } @Test public void checkReturnMapWithOneIfOneJavaFunctionsFound() throws ODataJPAModelException { javaActions.add(ExampleJavaOneAction.class); - Map act = cut.create(new JPAEdmNameBuilder(PUNIT_NAME), + Map act = cut.create(new JPADefaultEdmNameBuilder(PUNIT_NAME), reflections, helper.schema); assertEquals(1, act.size()); } @@ -57,7 +57,7 @@ public void checkReturnMapWithOneIfOneJavaFunctionsFound() throws ODataJPAModelE @Test public void checkReturnMapWithTwoIfTwoJavaFunctionsFound() throws ODataJPAModelException { javaActions.add(ExampleJavaTwoActions.class); - Map act = cut.create(new JPAEdmNameBuilder(PUNIT_NAME), + Map act = cut.create(new JPADefaultEdmNameBuilder(PUNIT_NAME), reflections, helper.schema); assertEquals(2, act.size()); } @@ -66,7 +66,7 @@ public void checkReturnMapWithTwoIfTwoJavaFunctionsFound() throws ODataJPAModelE public void checkReturnMapWithWithJavaFunctionsFromTwoClassesFound() throws ODataJPAModelException { javaActions.add(ExampleJavaOneAction.class); javaActions.add(ExampleJavaTwoActions.class); - Map act = cut.create(new JPAEdmNameBuilder(PUNIT_NAME), + Map act = cut.create(new JPADefaultEdmNameBuilder(PUNIT_NAME), reflections, helper.schema); assertEquals(3, act.size()); } diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateCollectionProperty.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateCollectionProperty.java new file mode 100644 index 000000000..7ab2774fa --- /dev/null +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateCollectionProperty.java @@ -0,0 +1,211 @@ +package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.List; + +import javax.persistence.metamodel.ManagedType; +import javax.persistence.metamodel.PluralAttribute; +import javax.persistence.metamodel.Type.PersistenceType; + +import org.apache.olingo.commons.api.edm.provider.CsdlAnnotation; +import org.apache.olingo.commons.api.edm.provider.annotation.CsdlConstantExpression.ConstantExpressionType; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.reflections.Reflections; + +import com.sap.olingo.jpa.metadata.api.JPAEdmMetadataPostProcessor; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPACollectionAttribute; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAPath; +import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; +import com.sap.olingo.jpa.processor.core.testmodel.CollectionFirstLevelComplex; +import com.sap.olingo.jpa.processor.core.testmodel.ComplexWithTransientComplexCollction; +import com.sap.olingo.jpa.processor.core.testmodel.Organization; +import com.sap.olingo.jpa.processor.core.testmodel.Person; + +public class TestIntermediateCollectionProperty extends TestMappingRoot { + private IntermediateCollectionProperty cut; + private TestHelper helper; + private JPAEdmMetadataPostProcessor processor; + + private JPADefaultEdmNameBuilder nameBuilder; + private PluralAttribute jpaAttribute; + private ManagedType managedType; + private IntermediateSchema schema; + + @BeforeEach + public void setup() throws ODataJPAModelException { + helper = new TestHelper(emf.getMetamodel(), PUNIT_NAME); + processor = mock(JPAEdmMetadataPostProcessor.class); + nameBuilder = new JPADefaultEdmNameBuilder(PUNIT_NAME); + jpaAttribute = mock(PluralAttribute.class); + managedType = mock(ManagedType.class); + schema = new IntermediateSchema(nameBuilder, emf.getMetamodel(), mock(Reflections.class)); + } + + @SuppressWarnings("unchecked") + @Test + public void checkSimpleCollectionPropertyType() throws ODataJPAModelException { + when(jpaAttribute.getName()).thenReturn("Text"); + @SuppressWarnings("rawtypes") + javax.persistence.metamodel.Type type = mock(javax.persistence.metamodel.Type.class); + when(type.getPersistenceType()).thenReturn(PersistenceType.BASIC); + when(type.getJavaType()).thenAnswer(new Answer>() { + @Override + public Class answer(InvocationOnMock invocation) throws Throwable { + return String.class; + } + }); + when(jpaAttribute.getElementType()).thenReturn(type); + when(jpaAttribute.getDeclaringType()).thenAnswer(new Answer>() { + @Override + public ManagedType answer(InvocationOnMock invocation) throws Throwable { + return managedType; + } + }); + when(managedType.getJavaType()).thenAnswer(new Answer>() { + @Override + public Class answer(InvocationOnMock invocation) throws Throwable { + return Person.class; + } + }); + when(jpaAttribute.getJavaType()).thenAnswer(new Answer>() { + @Override + public Class answer(InvocationOnMock invocation) throws Throwable { + return List.class; + } + }); + cut = new IntermediateCollectionProperty(nameBuilder, jpaAttribute, helper.schema, helper.schema.getEntityType( + Organization.class)); + assertEquals("Edm.String", cut.getEdmItem().getType()); + assertEquals(String.class, cut.getType()); + } + + @Test + public void checkGetProptertyComplexType() throws ODataJPAModelException { + + PluralAttribute jpaAttribute = helper.getCollectionAttribute(helper.getEntityType( + Person.class), "inhouseAddress"); + IntermediateCollectionProperty property = new IntermediateCollectionProperty(nameBuilder, + jpaAttribute, helper.schema, helper.schema.getEntityType(Person.class)); + assertEquals(PUNIT_NAME + ".InhouseAddress", property.getEdmItem().getType()); + } + + @Test + public void checkGetProptertyIgnoreFalse() throws ODataJPAModelException { + + PluralAttribute jpaAttribute = helper.getCollectionAttribute(helper.getEntityType( + Person.class), "inhouseAddress"); + IntermediateCollectionProperty property = new IntermediateCollectionProperty(nameBuilder, + jpaAttribute, helper.schema, helper.schema.getEntityType(Person.class)); + assertFalse(property.ignore()); + } + + @Test + public void checkGetProptertyDBFieldName() throws ODataJPAModelException { + + PluralAttribute jpaAttribute = helper.getCollectionAttribute(helper.getEntityType( + Organization.class), "comment"); + IntermediateCollectionProperty property = new IntermediateCollectionProperty(nameBuilder, + jpaAttribute, helper.schema, helper.schema.getEntityType(Organization.class)); + assertEquals("\"Text\"", property.getDBFieldName()); + } + + @Test + public void checkPostProcessorCalled() throws ODataJPAModelException { + + IntermediateSimpleProperty.setPostProcessor(processor); + PluralAttribute jpaAttribute = helper.getCollectionAttribute(helper.getEntityType( + Organization.class), "comment"); + IntermediateCollectionProperty property = new IntermediateCollectionProperty(nameBuilder, + jpaAttribute, helper.schema, helper.schema.getEntityType(Organization.class)); + property.getEdmItem(); + verify(processor, atLeastOnce()).processProperty(property, ORG_CANONICAL_NAME); + } + + @Test + public void checkGetPropertyReturnsAnnotation() throws ODataJPAModelException { + + PluralAttribute jpaAttribute = helper.getCollectionAttribute(helper.getEntityType( + Person.class), "inhouseAddress"); + IntermediateCollectionProperty property = new IntermediateCollectionProperty(nameBuilder, + jpaAttribute, helper.schema, helper.schema.getEntityType(Person.class)); + + List annotations = property.getEdmItem().getAnnotations(); + assertEquals(1, property.getEdmItem().getAnnotations().size()); + assertTrue(annotations.get(0).getExpression().isConstant()); + } + + @Test + public void checkGetDeepComplexPropertyReturnsExternalName() throws ODataJPAModelException { + + final IntermediateStructuredType st = new IntermediateComplexType(nameBuilder, helper + .getComplexType("CollectionSecondLevelComplex"), helper.schema); + for (final JPACollectionAttribute collection : st.getDeclaredCollectionAttributes()) { + if (collection.getInternalName().equals("comment")) { + assertEquals("Comment", collection.asAssociation().getAlias()); + } + } + + final IntermediateStructuredType stst = new IntermediateComplexType(nameBuilder, helper + .getComplexType("CollectionFirstLevelComplex"), helper.schema); + for (final JPAPath collection : stst.getCollectionAttributesPath()) { + if (collection.getLeaf().getInternalName().equals("comment")) { + assertEquals("SecondLevel/Comment", collection.getAlias()); + } + } + } + + @Test + public void checkAnnotations() throws ODataJPAModelException { + PluralAttribute jpaAttribute = helper.getCollectionAttribute(helper.getEntityType( + Person.class), "inhouseAddress"); + IntermediateCollectionProperty cut = new IntermediateCollectionProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), + jpaAttribute, helper.schema, helper.schema.getEntityType(Person.class)); + + List annotations = cut.getEdmItem().getAnnotations(); + assertEquals(1, annotations.size()); + assertEquals("Core.Description", annotations.get(0).getTerm()); + assertEquals(ConstantExpressionType.String, annotations.get(0).getExpression().asConstant().getType()); + assertEquals("Address for inhouse Mail", annotations.get(0).getExpression().asConstant().getValue()); + assertEquals("Address", annotations.get(0).getQualifier()); + } + + @Test + public void checkIsTransientOfPrimitiveReturnsTrue() throws ODataJPAModelException, NoSuchFieldException, + SecurityException { + + final PluralAttribute jpaAttribute = new IntermediateStructuredType.TransientPluralAttribute<>( + helper.getEmbeddedableType(CollectionFirstLevelComplex.class), + CollectionFirstLevelComplex.class.getDeclaredField("transientCollection"), + schema); + + final IntermediateCollectionProperty cut = new IntermediateCollectionProperty(nameBuilder, + jpaAttribute, helper.schema, helper.schema.getStructuredType(CollectionFirstLevelComplex.class)); + assertTrue(cut.isTransient()); + assertEquals("Edm.String", cut.getEdmItem().getType()); + } + + @Test + public void checkIsTransientOfComplexReturnsTrue() throws ODataJPAModelException, NoSuchFieldException, + SecurityException { + + final PluralAttribute jpaAttribute = new IntermediateStructuredType.TransientPluralAttribute<>( + helper.getEmbeddedableType(ComplexWithTransientComplexCollction.class), + ComplexWithTransientComplexCollction.class.getDeclaredField("transientCollection"), + schema); + + final IntermediateCollectionProperty cut = new IntermediateCollectionProperty(nameBuilder, + jpaAttribute, helper.schema, helper.schema.getStructuredType(ComplexWithTransientComplexCollction.class)); + assertTrue(cut.isTransient()); + assertEquals("com.sap.olingo.jpa.InhouseAddress", cut.getEdmItem().getType()); + } +} diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateComplexType.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateComplexType.java index bd3e905b5..da12b72fc 100644 --- a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateComplexType.java +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateComplexType.java @@ -1,44 +1,54 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; +import java.util.List; import java.util.Set; import javax.persistence.metamodel.EmbeddableType; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; import org.reflections.Reflections; import com.sap.olingo.jpa.metadata.api.JPAEdmMetadataPostProcessor; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAProtectionInfo; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediateEntityTypeAccess; import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediateNavigationPropertyAccess; import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediatePropertyAccess; import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediateReferenceList; +import com.sap.olingo.jpa.processor.core.testmodel.CollectionFirstLevelComplex; public class TestIntermediateComplexType extends TestMappingRoot { private Set> etList; private IntermediateSchema schema; - @Before + @BeforeEach public void setup() throws ODataJPAModelException { IntermediateModelElement.setPostProcessor(new DefaultEdmPostProcessor()); etList = emf.getMetamodel().getEmbeddables(); - schema = new IntermediateSchema(new JPAEdmNameBuilder(PUNIT_NAME), emf.getMetamodel(), mock(Reflections.class)); - + schema = new IntermediateSchema(nameBuilder, emf.getMetamodel(), mock( + Reflections.class)); } @Test public void checkComplexTypeCanBeCreated() throws ODataJPAModelException { - new IntermediateComplexType(new JPAEdmNameBuilder(PUNIT_NAME), getEmbeddedableType("CommunicationData"), schema); + assertNotNull(new IntermediateComplexType(nameBuilder, getEmbeddedableType("CommunicationData"), + schema)); + } + + private EmbeddableType getEmbeddedableType(final Class type) { + return getEmbeddedableType(type.getSimpleName()); } private EmbeddableType getEmbeddedableType(String typeName) { @@ -52,23 +62,23 @@ private EmbeddableType getEmbeddedableType(String typeName) { @Test public void checkGetAllProperties() throws ODataJPAModelException { - IntermediateComplexType ct = new IntermediateComplexType(new JPAEdmNameBuilder(PUNIT_NAME), getEmbeddedableType( - "CommunicationData"), schema); - assertEquals("Wrong number of entities", 4, ct.getEdmItem().getProperties().size()); + IntermediateComplexType ct = new IntermediateComplexType(new JPADefaultEdmNameBuilder(PUNIT_NAME), + getEmbeddedableType("CommunicationData"), schema); + assertEquals(4, ct.getEdmItem().getProperties().size(), "Wrong number of entities"); } @Test public void checkGetPropertyByNameNotNull() throws ODataJPAModelException { - IntermediateComplexType ct = new IntermediateComplexType(new JPAEdmNameBuilder(PUNIT_NAME), getEmbeddedableType( - "CommunicationData"), schema); + IntermediateComplexType ct = new IntermediateComplexType(new JPADefaultEdmNameBuilder(PUNIT_NAME), + getEmbeddedableType("CommunicationData"), schema); assertNotNull(ct.getEdmItem().getProperty("LandlinePhoneNumber")); } @Test public void checkGetPropertyByNameCorrectEntity() throws ODataJPAModelException { - IntermediateComplexType ct = new IntermediateComplexType(new JPAEdmNameBuilder(PUNIT_NAME), getEmbeddedableType( - "CommunicationData"), schema); - assertEquals("LandlinePhoneNumber", ct.getEdmItem().getProperty("LandlinePhoneNumber").getName()); + IntermediateComplexType ct = new IntermediateComplexType(new JPADefaultEdmNameBuilder(PUNIT_NAME), + getEmbeddedableType("CommunicationData"), schema); + assertEquals(ct.getEdmItem().getProperty("LandlinePhoneNumber").getName(), "LandlinePhoneNumber"); } @Test @@ -76,8 +86,9 @@ public void checkGetPropertyIsNullable() throws ODataJPAModelException { PostProcessorSetIgnore pPDouble = new PostProcessorSetIgnore(); IntermediateModelElement.setPostProcessor(pPDouble); - IntermediateComplexType ct = new IntermediateComplexType(new JPAEdmNameBuilder(PUNIT_NAME), getEmbeddedableType( - "PostalAddressData"), schema); + IntermediateComplexType ct = new IntermediateComplexType(new JPADefaultEdmNameBuilder(PUNIT_NAME), + getEmbeddedableType( + "PostalAddressData"), schema); // In case nullable = true, nullable is not past to $metadata, as this is the default assertTrue(ct.getEdmItem().getProperty("POBox").isNullable()); } @@ -87,9 +98,10 @@ public void checkGetAllNaviProperties() throws ODataJPAModelException { PostProcessorSetIgnore pPDouble = new PostProcessorSetIgnore(); IntermediateModelElement.setPostProcessor(pPDouble); - IntermediateComplexType ct = new IntermediateComplexType(new JPAEdmNameBuilder(PUNIT_NAME), getEmbeddedableType( - "PostalAddressData"), schema); - assertEquals("Wrong number of entities", 1, ct.getEdmItem().getNavigationProperties().size()); + IntermediateComplexType ct = new IntermediateComplexType(new JPADefaultEdmNameBuilder(PUNIT_NAME), + getEmbeddedableType( + "PostalAddressData"), schema); + assertEquals(1, ct.getEdmItem().getNavigationProperties().size(), "Wrong number of entities"); } @Test @@ -97,8 +109,9 @@ public void checkGetNaviPropertyByNameNotNull() throws ODataJPAModelException { PostProcessorSetIgnore pPDouble = new PostProcessorSetIgnore(); IntermediateModelElement.setPostProcessor(pPDouble); - IntermediateComplexType ct = new IntermediateComplexType(new JPAEdmNameBuilder(PUNIT_NAME), getEmbeddedableType( - "PostalAddressData"), schema); + IntermediateComplexType ct = new IntermediateComplexType(new JPADefaultEdmNameBuilder(PUNIT_NAME), + getEmbeddedableType( + "PostalAddressData"), schema); assertNotNull(ct.getEdmItem().getNavigationProperty("AdministrativeDivision").getName()); } @@ -107,8 +120,9 @@ public void checkGetNaviPropertyByNameRightEntity() throws ODataJPAModelExceptio PostProcessorSetIgnore pPDouble = new PostProcessorSetIgnore(); IntermediateModelElement.setPostProcessor(pPDouble); - IntermediateComplexType ct = new IntermediateComplexType(new JPAEdmNameBuilder(PUNIT_NAME), getEmbeddedableType( - "PostalAddressData"), schema); + IntermediateComplexType ct = new IntermediateComplexType(new JPADefaultEdmNameBuilder(PUNIT_NAME), + getEmbeddedableType( + "PostalAddressData"), schema); assertEquals("AdministrativeDivision", ct.getEdmItem().getNavigationProperty("AdministrativeDivision").getName()); } @@ -117,9 +131,10 @@ public void checkGetPropertiesSkipIgnored() throws ODataJPAModelException { PostProcessorSetIgnore pPDouble = new PostProcessorSetIgnore(); IntermediateModelElement.setPostProcessor(pPDouble); - IntermediateComplexType ct = new IntermediateComplexType(new JPAEdmNameBuilder(PUNIT_NAME), getEmbeddedableType( - "CommunicationData"), schema); - assertEquals("Wrong number of entities", 3, ct.getEdmItem().getProperties().size()); + IntermediateComplexType ct = new IntermediateComplexType(new JPADefaultEdmNameBuilder(PUNIT_NAME), + getEmbeddedableType( + "CommunicationData"), schema); + assertEquals(3, ct.getEdmItem().getProperties().size(), "Wrong number of entities"); } @Test @@ -127,8 +142,9 @@ public void checkGetDescriptionPropertyManyToOne() throws ODataJPAModelException PostProcessorSetIgnore pPDouble = new PostProcessorSetIgnore(); IntermediateModelElement.setPostProcessor(pPDouble); - IntermediateComplexType ct = new IntermediateComplexType(new JPAEdmNameBuilder(PUNIT_NAME), getEmbeddedableType( - "PostalAddressData"), schema); + IntermediateComplexType ct = new IntermediateComplexType(new JPADefaultEdmNameBuilder(PUNIT_NAME), + getEmbeddedableType( + "PostalAddressData"), schema); assertNotNull(ct.getEdmItem().getProperty("CountryName")); } @@ -137,8 +153,9 @@ public void checkGetDescriptionPropertyManyToMany() throws ODataJPAModelExceptio PostProcessorSetIgnore pPDouble = new PostProcessorSetIgnore(); IntermediateModelElement.setPostProcessor(pPDouble); - IntermediateComplexType ct = new IntermediateComplexType(new JPAEdmNameBuilder(PUNIT_NAME), getEmbeddedableType( - "PostalAddressData"), schema); + IntermediateComplexType ct = new IntermediateComplexType(new JPADefaultEdmNameBuilder(PUNIT_NAME), + getEmbeddedableType( + "PostalAddressData"), schema); assertNotNull(ct.getEdmItem().getProperty("RegionName")); } @@ -147,49 +164,55 @@ public void checkDescriptionPropertyType() throws ODataJPAModelException { PostProcessorSetIgnore pPDouble = new PostProcessorSetIgnore(); IntermediateModelElement.setPostProcessor(pPDouble); - IntermediateComplexType ct = new IntermediateComplexType(new JPAEdmNameBuilder(PUNIT_NAME), getEmbeddedableType( - "PostalAddressData"), schema); + IntermediateComplexType ct = new IntermediateComplexType(new JPADefaultEdmNameBuilder(PUNIT_NAME), + getEmbeddedableType( + "PostalAddressData"), schema); ct.getEdmItem(); assertTrue(ct.getProperty("countryName") instanceof IntermediateDescriptionProperty); } @Test public void checkGetPropertyOfNestedComplexType() throws ODataJPAModelException { - IntermediateComplexType ct = new IntermediateComplexType(new JPAEdmNameBuilder(PUNIT_NAME), getEmbeddedableType( - "AdministrativeInformation"), schema); + IntermediateComplexType ct = new IntermediateComplexType(new JPADefaultEdmNameBuilder(PUNIT_NAME), + getEmbeddedableType( + "AdministrativeInformation"), schema); assertNotNull(ct.getPath("Created/By")); } @Test public void checkGetPropertyDBName() throws ODataJPAModelException { - IntermediateComplexType ct = new IntermediateComplexType(new JPAEdmNameBuilder(PUNIT_NAME), getEmbeddedableType( - "PostalAddressData"), schema); + IntermediateComplexType ct = new IntermediateComplexType(new JPADefaultEdmNameBuilder(PUNIT_NAME), + getEmbeddedableType( + "PostalAddressData"), schema); assertEquals("\"Address.PostOfficeBox\"", ct.getPath("POBox").getDBFieldName()); } @Test public void checkGetPropertyDBNameOfNestedComplexType() throws ODataJPAModelException { - IntermediateComplexType ct = new IntermediateComplexType(new JPAEdmNameBuilder(PUNIT_NAME), getEmbeddedableType( - "AdministrativeInformation"), schema); + IntermediateComplexType ct = new IntermediateComplexType(new JPADefaultEdmNameBuilder(PUNIT_NAME), + getEmbeddedableType( + "AdministrativeInformation"), schema); assertEquals("\"CreatedBy\"", ct.getPath("Created/By").getDBFieldName()); } @Test public void checkGetPropertyWithComplexType() throws ODataJPAModelException { - IntermediateComplexType ct = new IntermediateComplexType(new JPAEdmNameBuilder(PUNIT_NAME), getEmbeddedableType( - "AdministrativeInformation"), schema); + IntermediateComplexType ct = new IntermediateComplexType(new JPADefaultEdmNameBuilder(PUNIT_NAME), + getEmbeddedableType( + "AdministrativeInformation"), schema); assertNotNull(ct.getEdmItem().getProperty("Created")); } @Test public void checkGetPropertiesWithSameComplexTypeNotEqual() throws ODataJPAModelException { - IntermediateComplexType ct = new IntermediateComplexType(new JPAEdmNameBuilder(PUNIT_NAME), getEmbeddedableType( - "AdministrativeInformation"), schema); + IntermediateComplexType ct = new IntermediateComplexType(new JPADefaultEdmNameBuilder(PUNIT_NAME), + getEmbeddedableType( + "AdministrativeInformation"), schema); assertNotEquals(ct.getEdmItem().getProperty("Created"), ct.getEdmItem().getProperty("Updated")); assertNotEquals(ct.getProperty("created"), ct.getProperty("updated")); } - @Ignore + @Disabled @Test public void checkGetPropertyWithEnumerationType() { @@ -197,24 +220,87 @@ public void checkGetPropertyWithEnumerationType() { @Test public void checkGetProptertyIgnoreTrue() throws ODataJPAModelException { - IntermediateComplexType ct = new IntermediateComplexType(new JPAEdmNameBuilder(PUNIT_NAME), getEmbeddedableType( - "DummyEmbeddedToIgnore"), schema); + IntermediateComplexType ct = new IntermediateComplexType(new JPADefaultEdmNameBuilder(PUNIT_NAME), + getEmbeddedableType( + "DummyEmbeddedToIgnore"), schema); assertTrue(ct.ignore()); } @Test public void checkGetProptertyIgnoreFalse() throws ODataJPAModelException { - IntermediateComplexType ct = new IntermediateComplexType(new JPAEdmNameBuilder(PUNIT_NAME), getEmbeddedableType( - "ChangeInformation"), schema); + IntermediateComplexType ct = new IntermediateComplexType(new JPADefaultEdmNameBuilder(PUNIT_NAME), + getEmbeddedableType( + "ChangeInformation"), schema); assertFalse(ct.ignore()); } + @Test + public void checkOneSimpleProtectedProperty() throws ODataJPAModelException { + IntermediateComplexType ct = new IntermediateComplexType(new JPADefaultEdmNameBuilder(PUNIT_NAME), + getEmbeddedableType( + "InhouseAddressWithProtection"), schema); + List act = ct.getProtections(); + assertNotNull(act); + assertEquals(1, act.size()); + assertEquals("Building", act.get(0).getAttribute().getExternalName()); + assertEquals("BuildingNumber", act.get(0).getClaimName()); + } + + @Test + public void checkOneComplexProtectedPropertyDeep() throws ODataJPAModelException { + IntermediateComplexType ct = new IntermediateComplexType(new JPADefaultEdmNameBuilder(PUNIT_NAME), + getEmbeddedableType( + "AddressDeepProtected"), schema); + List act = ct.getProtections(); + assertNotNull(act); + assertEquals(1, act.size()); + assertEquals("Building", act.get(0).getAttribute().getExternalName()); + assertEquals("BuildingNumber", act.get(0).getClaimName()); + assertEquals(2, act.get(0).getPath().getPath().size()); + assertEquals(true, act.get(0).supportsWildcards()); + } + + @ParameterizedTest + @CsvSource({ + "Building, BuildingNumber", + "Floor, Floor", + "RoomNumber, RoomNumber" + }) + public void checkOneComplexProtectedPropertyDeepWoWildcards(final String externalName, final String claim) + throws ODataJPAModelException { + + IntermediateComplexType ct = new IntermediateComplexType(new JPADefaultEdmNameBuilder(PUNIT_NAME), + getEmbeddedableType( + "AddressDeepThreeProtections"), schema); + List act = ct.getProtections(); + assertNotNull(act); + assertEquals(3, act.size()); + JPAProtectionInfo targetAttribute = null; + for (final JPAProtectionInfo a : act) { + if (a.getAttribute().getExternalName().equals(externalName)) { + targetAttribute = a; + } + } + assertNotNull(targetAttribute); + assertEquals(claim, targetAttribute.getClaimName()); + assertEquals(2, act.get(0).getPath().getPath().size()); + assertFalse(act.get(0).supportsWildcards()); + } + + @Test + public void checkTransientCollectionProperty() throws ODataJPAModelException { + + final IntermediateComplexType ct = new IntermediateComplexType(nameBuilder, getEmbeddedableType( + CollectionFirstLevelComplex.class), schema); + + assertTrue(ct.getAttribute("transientCollection").get().isTransient()); + } + private class PostProcessorSetIgnore extends JPAEdmMetadataPostProcessor { @Override public void processProperty(IntermediatePropertyAccess property, String jpaManagedTypeClassName) { - if (jpaManagedTypeClassName.equals( - COMM_CANONICAL_NAME)) { + if (jpaManagedTypeClassName.equals(COMM_CANONICAL_NAME)) { if (property.getInternalName().equals("landlinePhoneNumber")) { property.setIgnore(true); } diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateContainer.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateContainer.java index cccebd05a..9c9fc2be4 100644 --- a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateContainer.java +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateContainer.java @@ -1,8 +1,8 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.fail; import java.util.ArrayList; import java.util.HashMap; @@ -17,10 +17,11 @@ import org.apache.olingo.commons.api.edm.provider.CsdlNavigationPropertyBinding; import org.apache.olingo.commons.api.edm.provider.annotation.CsdlConstantExpression; import org.apache.olingo.commons.api.edm.provider.annotation.CsdlConstantExpression.ConstantExpressionType; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.reflections.Reflections; import org.reflections.scanners.SubTypesScanner; +import org.reflections.scanners.TypeAnnotationsScanner; import org.reflections.util.ConfigurationBuilder; import org.reflections.util.FilterBuilder; @@ -35,23 +36,23 @@ import com.sap.olingo.jpa.processor.core.testmodel.TestDataConstants; public class TestIntermediateContainer extends TestMappingRoot { - private static final String PACKAGE = "com.sap.olingo.jpa.metadata.core.edm.mapper.impl"; - private HashMap schemas = new HashMap(); + private static final String PACKAGE1 = "com.sap.olingo.jpa.metadata.core.edm.mapper.impl"; + private static final String PACKAGE2 = "com.sap.olingo.jpa.processor.core.testmodel"; + private HashMap schemas = new HashMap<>(); private Set> etList; private IntermediateSchema schema; - @Before + @BeforeEach public void setup() throws ODataJPAModelException { IntermediateModelElement.setPostProcessor(new DefaultEdmPostProcessor()); Reflections r = new Reflections( new ConfigurationBuilder() - .forPackages(PACKAGE) - .filterInputsBy(new FilterBuilder().include(FilterBuilder.prefix( - "com.sap.olingo.jpa.metadata.core.edm.mapper.impl"))) - .setScanners(new SubTypesScanner(false))); + .forPackages(PACKAGE1, PACKAGE2) + .filterInputsBy(new FilterBuilder().includePackage(PACKAGE1, PACKAGE2)) + .setScanners(new SubTypesScanner(false), new TypeAnnotationsScanner())); - schema = new IntermediateSchema(new JPAEdmNameBuilder(PUNIT_NAME), emf.getMetamodel(), r); + schema = new IntermediateSchema(new JPADefaultEdmNameBuilder(PUNIT_NAME), emf.getMetamodel(), r); etList = emf.getMetamodel().getEntities(); schemas.put(PUNIT_NAME, schema); } @@ -59,27 +60,30 @@ public void setup() throws ODataJPAModelException { @Test public void checkContainerCanBeCreated() throws ODataJPAModelException { - new IntermediateEntityContainer(new JPAEdmNameBuilder(PUNIT_NAME), schemas); + new IntermediateEntityContainer(new JPADefaultEdmNameBuilder(PUNIT_NAME), schemas); } @Test public void checkGetName() throws ODataJPAModelException { - IntermediateEntityContainer container = new IntermediateEntityContainer(new JPAEdmNameBuilder(PUNIT_NAME), schemas); + IntermediateEntityContainer container = new IntermediateEntityContainer(new JPADefaultEdmNameBuilder(PUNIT_NAME), + schemas); assertEquals("ComSapOlingoJpaContainer", container.getExternalName()); } @Test public void checkGetNoEntitySets() throws ODataJPAModelException { - IntermediateEntityContainer container = new IntermediateEntityContainer(new JPAEdmNameBuilder(PUNIT_NAME), schemas); + IntermediateEntityContainer container = new IntermediateEntityContainer(new JPADefaultEdmNameBuilder(PUNIT_NAME), + schemas); assertEquals(TestDataConstants.NO_ENTITY_SETS, container.getEdmItem().getEntitySets().size()); } @Test public void checkGetEntitySetName() throws ODataJPAModelException { - IntermediateEntityContainer container = new IntermediateEntityContainer(new JPAEdmNameBuilder(PUNIT_NAME), schemas); + IntermediateEntityContainer container = new IntermediateEntityContainer(new JPADefaultEdmNameBuilder(PUNIT_NAME), + schemas); List entitySets = container.getEdmItem().getEntitySets(); for (CsdlEntitySet entitySet : entitySets) { if (entitySet.getName().equals("BusinessPartners")) return; @@ -90,11 +94,12 @@ public void checkGetEntitySetName() throws ODataJPAModelException { @Test public void checkGetEntitySetType() throws ODataJPAModelException { - IntermediateEntityContainer container = new IntermediateEntityContainer(new JPAEdmNameBuilder(PUNIT_NAME), schemas); - List entitySets = container.getEdmItem().getEntitySets(); - for (CsdlEntitySet entitySet : entitySets) { + final IntermediateEntityContainer container = new IntermediateEntityContainer(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schemas); + final List entitySets = container.getEdmItem().getEntitySets(); + for (final CsdlEntitySet entitySet : entitySets) { if (entitySet.getName().equals("BusinessPartners")) { - assertEquals(new JPAEdmNameBuilder(PUNIT_NAME).buildFQN("BusinessPartner"), entitySet.getTypeFQN()); + assertEquals(container.buildFQN("BusinessPartner"), entitySet.getTypeFQN()); return; } } @@ -104,7 +109,8 @@ public void checkGetEntitySetType() throws ODataJPAModelException { @Test public void checkGetNoNavigationPropertyBindings() throws ODataJPAModelException { - IntermediateEntityContainer container = new IntermediateEntityContainer(new JPAEdmNameBuilder(PUNIT_NAME), schemas); + IntermediateEntityContainer container = new IntermediateEntityContainer(new JPADefaultEdmNameBuilder(PUNIT_NAME), + schemas); List entitySets = container.getEdmItem().getEntitySets(); for (CsdlEntitySet entitySet : entitySets) { @@ -119,7 +125,8 @@ public void checkGetNoNavigationPropertyBindings() throws ODataJPAModelException @Test public void checkGetNavigationPropertyBindingsPath() throws ODataJPAModelException { - IntermediateEntityContainer container = new IntermediateEntityContainer(new JPAEdmNameBuilder(PUNIT_NAME), schemas); + IntermediateEntityContainer container = new IntermediateEntityContainer(new JPADefaultEdmNameBuilder(PUNIT_NAME), + schemas); List entitySets = container.getEdmItem().getEntitySets(); for (CsdlEntitySet entitySet : entitySets) { @@ -136,7 +143,8 @@ public void checkGetNavigationPropertyBindingsPath() throws ODataJPAModelExcepti @Test public void checkGetNavigationPropertyBindingsTarget() throws ODataJPAModelException { - IntermediateEntityContainer container = new IntermediateEntityContainer(new JPAEdmNameBuilder(PUNIT_NAME), schemas); + IntermediateEntityContainer container = new IntermediateEntityContainer(new JPADefaultEdmNameBuilder(PUNIT_NAME), + schemas); List entitySets = container.getEdmItem().getEntitySets(); for (CsdlEntitySet entitySet : entitySets) { @@ -155,7 +163,8 @@ public void checkGetNavigationPropertyBindingsTarget() throws ODataJPAModelExcep @Test public void checkGetNavigationPropertyBindingsPathComplexType() throws ODataJPAModelException { - IntermediateEntityContainer container = new IntermediateEntityContainer(new JPAEdmNameBuilder(PUNIT_NAME), schemas); + IntermediateEntityContainer container = new IntermediateEntityContainer(new JPADefaultEdmNameBuilder(PUNIT_NAME), + schemas); List entitySets = container.getEdmItem().getEntitySets(); for (CsdlEntitySet entitySet : entitySets) { @@ -172,7 +181,8 @@ public void checkGetNavigationPropertyBindingsPathComplexType() throws ODataJPAM @Test public void checkGetNavigationPropertyBindingsPathComplexTypeNested() throws ODataJPAModelException { - IntermediateEntityContainer container = new IntermediateEntityContainer(new JPAEdmNameBuilder(PUNIT_NAME), schemas); + IntermediateEntityContainer container = new IntermediateEntityContainer(new JPADefaultEdmNameBuilder(PUNIT_NAME), + schemas); List entitySets = container.getEdmItem().getEntitySets(); for (CsdlEntitySet entitySet : entitySets) { @@ -189,7 +199,8 @@ public void checkGetNavigationPropertyBindingsPathComplexTypeNested() throws ODa @Test public void checkGetNoFunctionImportIfBound() throws ODataJPAModelException { - IntermediateEntityContainer container = new IntermediateEntityContainer(new JPAEdmNameBuilder(PUNIT_NAME), schemas); + IntermediateEntityContainer container = new IntermediateEntityContainer(new JPADefaultEdmNameBuilder(PUNIT_NAME), + schemas); List funcImports = container.getEdmItem().getFunctionImports(); for (CsdlFunctionImport funcImport : funcImports) { @@ -202,7 +213,8 @@ public void checkGetNoFunctionImportIfBound() throws ODataJPAModelException { @Test public void checkGetNoFunctionImportIfUnBoundHasImportFalse() throws ODataJPAModelException { - IntermediateEntityContainer container = new IntermediateEntityContainer(new JPAEdmNameBuilder(PUNIT_NAME), schemas); + IntermediateEntityContainer container = new IntermediateEntityContainer(new JPADefaultEdmNameBuilder(PUNIT_NAME), + schemas); List funcImports = container.getEdmItem().getFunctionImports(); for (CsdlFunctionImport funcImport : funcImports) { @@ -214,7 +226,8 @@ public void checkGetNoFunctionImportIfUnBoundHasImportFalse() throws ODataJPAMod @Test public void checkGetNoFunctionImportForJavaBasedFunction() throws ODataJPAModelException { - IntermediateEntityContainer container = new IntermediateEntityContainer(new JPAEdmNameBuilder(PUNIT_NAME), schemas); + IntermediateEntityContainer container = new IntermediateEntityContainer(new JPADefaultEdmNameBuilder(PUNIT_NAME), + schemas); List funcImports = container.getEdmItem().getFunctionImports(); for (CsdlFunctionImport funcImport : funcImports) { @@ -228,7 +241,8 @@ public void checkGetNoFunctionImportForJavaBasedFunction() throws ODataJPAModelE @Test public void checkGetFunctionImportIfUnBoundHasImportTrue() throws ODataJPAModelException { - IntermediateEntityContainer container = new IntermediateEntityContainer(new JPAEdmNameBuilder(PUNIT_NAME), schemas); + IntermediateEntityContainer container = new IntermediateEntityContainer(new JPADefaultEdmNameBuilder(PUNIT_NAME), + schemas); List funcImports = container.getEdmItem().getFunctionImports(); for (CsdlFunctionImport funcImport : funcImports) { @@ -241,7 +255,8 @@ public void checkGetFunctionImportIfUnBoundHasImportTrue() throws ODataJPAModelE @Test public void checkAnnotationSet() throws ODataJPAModelException { IntermediateModelElement.setPostProcessor(new PostProcessorSetIgnore()); - IntermediateEntityContainer container = new IntermediateEntityContainer(new JPAEdmNameBuilder(PUNIT_NAME), schemas); + IntermediateEntityContainer container = new IntermediateEntityContainer(new JPADefaultEdmNameBuilder(PUNIT_NAME), + schemas); List act = container.getEdmItem().getAnnotations(); assertEquals(1, act.size()); assertEquals("Capabilities.AsynchronousRequestsSupported", act.get(0).getTerm()); @@ -250,10 +265,11 @@ public void checkAnnotationSet() throws ODataJPAModelException { @Test public void checkReturnEntitySetBasedOnInternalEntityType() throws ODataJPAModelException { - IntermediateEntityType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateEntityType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "BestOrganization"), schema); - IntermediateEntityContainer container = new IntermediateEntityContainer(new JPAEdmNameBuilder(PUNIT_NAME), schemas); + IntermediateEntityContainer container = new IntermediateEntityContainer(new JPADefaultEdmNameBuilder(PUNIT_NAME), + schemas); JPAElement act = container.getEntitySet(et); assertNotNull(act); @@ -290,7 +306,7 @@ public void processEntityContainer(IntermediateEntityContainerAccess container) CsdlAnnotation annotation = new CsdlAnnotation(); annotation.setExpression(mimeType); annotation.setTerm("Capabilities.AsynchronousRequestsSupported"); - List annotations = new ArrayList(); + List annotations = new ArrayList<>(); annotations.add(annotation); container.addAnnotations(annotations); } diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateDataBaseFunction.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateDataBaseFunction.java index 87f8d3c00..fe0f24158 100644 --- a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateDataBaseFunction.java +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateDataBaseFunction.java @@ -1,9 +1,10 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -11,72 +12,91 @@ import java.util.List; import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind; +import org.apache.olingo.commons.api.edm.FullQualifiedName; import org.apache.olingo.commons.api.edm.provider.CsdlParameter; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmFunction; import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmParameter; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; -import com.sap.olingo.jpa.processor.core.testmodel.AssertList; +import com.sap.olingo.jpa.processor.core.testmodel.AdministrativeDivision; import com.sap.olingo.jpa.processor.core.testmodel.BusinessPartner; import com.sap.olingo.jpa.processor.core.testmodel.ChangeInformation; import com.sap.olingo.jpa.processor.core.testmodel.DateConverter; +import com.sap.olingo.jpa.processor.core.testmodel.Organization; +import com.sap.olingo.jpa.processor.core.testmodel.Person; +import com.sap.olingo.jpa.processor.core.util.Assertions; public class TestIntermediateDataBaseFunction extends TestMappingRoot { private TestHelper helper; - @Before + @BeforeEach public void setup() throws ODataJPAModelException { helper = new TestHelper(emf.getMetamodel(), PUNIT_NAME); } @Test public void checkByEntityAnnotationCreate() throws ODataJPAModelException { - new IntermediateDataBaseFunction(new JPAEdmNameBuilder(PUNIT_NAME), helper.getStoredProcedure(helper.getEntityType( - "BusinessPartner"), "CountRoles"), BusinessPartner.class, helper.schema); + new IntermediateDataBaseFunction(new JPADefaultEdmNameBuilder(PUNIT_NAME), helper.getStoredProcedure(helper.getEntityType( + BusinessPartner.class), "CountRoles"), BusinessPartner.class, helper.schema); } @Test public void checkByEntityAnnotationGetName() throws ODataJPAModelException { - IntermediateFunction func = new IntermediateDataBaseFunction(new JPAEdmNameBuilder(PUNIT_NAME), helper + IntermediateFunction func = new IntermediateDataBaseFunction(new JPADefaultEdmNameBuilder(PUNIT_NAME), helper .getStoredProcedure( - helper.getEntityType("BusinessPartner"), "CountRoles"), BusinessPartner.class, helper.schema); + helper.getEntityType(BusinessPartner.class), "CountRoles"), BusinessPartner.class, helper.schema); assertEquals("CountRoles", func.getEdmItem().getName()); } @Test - public void checkByEntityAnnotationGetStoredProcedureName() throws ODataJPAModelException { - IntermediateFunction func = new IntermediateDataBaseFunction(new JPAEdmNameBuilder(PUNIT_NAME), helper + public void checkByEntityAnnotationGetFunctionName() throws ODataJPAModelException { + IntermediateFunction func = new IntermediateDataBaseFunction(new JPADefaultEdmNameBuilder(PUNIT_NAME), helper .getStoredProcedure( - helper.getEntityType("BusinessPartner"), "CountRoles"), BusinessPartner.class, helper.schema); + helper.getEntityType(BusinessPartner.class), "CountRoles"), BusinessPartner.class, helper.schema); assertEquals("COUNT_ROLES", func.getUserDefinedFunction()); } @Test - public void checkByEntityAnnotationInputParameter1() throws ODataJPAModelException { - IntermediateFunction func = new IntermediateDataBaseFunction(new JPAEdmNameBuilder(PUNIT_NAME), helper + public void checkByEntityAnnotationInputParameterBound() throws ODataJPAModelException { + IntermediateFunction func = new IntermediateDataBaseFunction(new JPADefaultEdmNameBuilder(PUNIT_NAME), helper .getStoredProcedure( - helper.getEntityType("BusinessPartner"), "CountRoles"), BusinessPartner.class, helper.schema); + helper.getEntityType(BusinessPartner.class), "CountRoles"), BusinessPartner.class, helper.schema); - List expInput = new ArrayList(); + List expInput = new ArrayList<>(); CsdlParameter param = new CsdlParameter(); - param.setName("Amount"); - param.setType(EdmPrimitiveTypeKind.Int32.getFullQualifiedName()); + param.setName("Key"); + param.setType(new FullQualifiedName("com.sap.olingo.jpa.BusinessPartner")); param.setNullable(false); expInput.add(param); - AssertList.assertEquals(expInput, func.getEdmItem().getParameters()); + Assertions.assertListEquals(expInput, func.getEdmItem().getParameters(), CsdlParameter.class); + } + + @Test + public void checkByEntityAnnotationInputParameterBoundCompoundKey() throws ODataJPAModelException { + IntermediateFunction func = new IntermediateDataBaseFunction(new JPADefaultEdmNameBuilder(PUNIT_NAME), helper + .getStoredProcedure(helper.getEntityType(AdministrativeDivision.class), "SiblingsBound"), + AdministrativeDivision.class, helper.schema); + + List expInput = new ArrayList<>(); + CsdlParameter param = new CsdlParameter(); + param.setName("Key"); + param.setType(new FullQualifiedName("com.sap.olingo.jpa.AdministrativeDivision")); + param.setNullable(false); + expInput.add(param); + Assertions.assertListEquals(expInput, func.getEdmItem().getParameters(), CsdlParameter.class); } @Test public void checkByEntityAnnotationInputParameter2() throws ODataJPAModelException { - IntermediateFunction func = new IntermediateDataBaseFunction(new JPAEdmNameBuilder(PUNIT_NAME), helper + IntermediateFunction func = new IntermediateDataBaseFunction(new JPADefaultEdmNameBuilder(PUNIT_NAME), helper .getStoredProcedure( - helper.getEntityType("BusinessPartner"), "IsPrime"), BusinessPartner.class, helper.schema); + helper.getEntityType(BusinessPartner.class), "IsPrime"), BusinessPartner.class, helper.schema); - List expInput = new ArrayList(); + List expInput = new ArrayList<>(); CsdlParameter param = new CsdlParameter(); param.setName("Number"); param.setType(EdmPrimitiveTypeKind.Decimal.getFullQualifiedName()); @@ -84,57 +104,105 @@ public void checkByEntityAnnotationInputParameter2() throws ODataJPAModelExcepti param.setPrecision(32); param.setScale(0); expInput.add(param); - AssertList.assertEquals(expInput, func.getEdmItem().getParameters()); + Assertions.assertListEquals(expInput, func.getEdmItem().getParameters(), CsdlParameter.class); } @Test - public void checkByEntityAnnotationResultParameterSimple() throws ODataJPAModelException { - IntermediateFunction func = new IntermediateDataBaseFunction(new JPAEdmNameBuilder(PUNIT_NAME), helper - .getStoredProcedure( - helper.getEntityType("BusinessPartner"), "IsPrime"), BusinessPartner.class, helper.schema); + public void checkByEntityAnnotationInputParameterIsEnumeration() throws ODataJPAModelException { - assertEquals(EdmPrimitiveTypeKind.Boolean.getFullQualifiedName().getFullQualifiedNameAsString(), func.getEdmItem() - .getReturnType().getType()); + IntermediateFunction func = new IntermediateDataBaseFunction(new JPADefaultEdmNameBuilder(PUNIT_NAME), helper + .getStoredProcedure(helper.getEntityType(Person.class), "CheckRights"), BusinessPartner.class, helper.schema); + + assertNotNull(func.getEdmItem().getParameters()); + assertEquals(2, func.getEdmItem().getParameters().size()); + assertEquals(PUNIT_NAME + ".AccessRights", func.getEdmItem().getParameters().get(0).getTypeFQN() + .getFullQualifiedNameAsString()); + assertEquals("Edm.Int32", func.getEdmItem().getParameters().get(1).getTypeFQN() + .getFullQualifiedNameAsString()); } @Test public void checkByEntityAnnotationResultParameterIsEmpty() throws ODataJPAModelException { - IntermediateFunction func = new IntermediateDataBaseFunction(new JPAEdmNameBuilder(PUNIT_NAME), helper + IntermediateFunction func = new IntermediateDataBaseFunction(new JPADefaultEdmNameBuilder(PUNIT_NAME), helper .getStoredProcedure( - helper.getEntityType("BusinessPartner"), "CountRoles"), BusinessPartner.class, helper.schema); + helper.getEntityType(BusinessPartner.class), "CountRoles"), BusinessPartner.class, helper.schema); assertEquals(PUNIT_NAME + ".BusinessPartner", func.getEdmItem().getReturnType().getType()); } + @Test + public void checkByEntityAnnotationIsBound() throws ODataJPAModelException { + IntermediateFunction func = new IntermediateDataBaseFunction(new JPADefaultEdmNameBuilder(PUNIT_NAME), helper + .getStoredProcedure( + helper.getEntityType(BusinessPartner.class), "CountRoles"), BusinessPartner.class, helper.schema); + + assertTrue(func.getEdmItem().isBound()); + assertTrue(func.isBound()); + assertEquals(PUNIT_NAME + ".BusinessPartner", func.getEdmItem().getParameters().get(0).getTypeFQN() + .getFullQualifiedNameAsString()); + } + + @Test + public void checkByEntityAnnotationResultParameterSimple() throws ODataJPAModelException { + IntermediateFunction func = new IntermediateDataBaseFunction(new JPADefaultEdmNameBuilder(PUNIT_NAME), helper + .getStoredProcedure( + helper.getEntityType(BusinessPartner.class), "IsPrime"), BusinessPartner.class, helper.schema); + + assertEquals(EdmPrimitiveTypeKind.Boolean.getFullQualifiedName().getFullQualifiedNameAsString(), func.getEdmItem() + .getReturnType().getType()); + } + @Test public void checkByEntityAnnotationResultParameterIsEntity() throws ODataJPAModelException { - IntermediateFunction func = new IntermediateFunctionFactory().create(new JPAEdmNameBuilder( - PUNIT_NAME), helper.getEntityType("Organization"), helper.schema).get("AllCustomersByABC"); + IntermediateFunction func = new IntermediateFunctionFactory().create(new JPADefaultEdmNameBuilder( + PUNIT_NAME), helper.getEntityType(Organization.class), helper.schema).get("AllCustomersByABC"); assertEquals(PUNIT_NAME + ".Organization", func.getEdmItem().getReturnType().getType()); } @Test - public void checkByEntityAnnotationResultParameterIsCollection() throws ODataJPAModelException { - IntermediateFunction func = new IntermediateFunctionFactory().create(new JPAEdmNameBuilder( - PUNIT_NAME), helper.getEntityType("Organization"), helper.schema).get("AllCustomersByABC"); + public void checkByEntityAnnotationResultParameterIsCollectionFalse() throws ODataJPAModelException { + IntermediateFunction func = new IntermediateFunctionFactory().create(new JPADefaultEdmNameBuilder( + PUNIT_NAME), helper.getEntityType(Organization.class), helper.schema).get("AllCustomersByABC"); assertTrue(func.getEdmItem().getReturnType().isCollection()); - func = new IntermediateFunctionFactory().create(new JPAEdmNameBuilder(PUNIT_NAME), helper - .getEntityType("BusinessPartner"), helper.schema).get("IsPrime"); + func = new IntermediateFunctionFactory().create(new JPADefaultEdmNameBuilder(PUNIT_NAME), helper + .getEntityType(BusinessPartner.class), helper.schema).get("IsPrime"); assertFalse(func.getEdmItem().getReturnType().isCollection()); } + @Test + public void checkByEntityAnnotationResultParameterNotGiven() throws ODataJPAModelException { + IntermediateFunction func = new IntermediateDataBaseFunction(new JPADefaultEdmNameBuilder(PUNIT_NAME), helper + .getStoredProcedure( + helper.getEntityType(BusinessPartner.class), "CountRoles"), BusinessPartner.class, helper.schema); + + assertTrue(func.getEdmItem().getReturnType().isCollection()); + assertEquals(PUNIT_NAME + ".BusinessPartner", func.getEdmItem().getReturnType().getType()); + assertEquals(BusinessPartner.class, func.getResultParameter().getType()); + } + @Test public void checkByEntityAnnotationResultParameterIsNullable() throws ODataJPAModelException { - IntermediateFunction func = new IntermediateFunctionFactory().create(new JPAEdmNameBuilder( - PUNIT_NAME), helper.getEntityType("Organization"), helper.schema).get("AllCustomersByABC"); + IntermediateFunction func = new IntermediateFunctionFactory().create(new JPADefaultEdmNameBuilder( + PUNIT_NAME), helper.getEntityType(Organization.class), helper.schema).get("AllCustomersByABC"); assertTrue(func.getEdmItem().getReturnType().isNullable()); - func = new IntermediateFunctionFactory().create(new JPAEdmNameBuilder(PUNIT_NAME), helper - .getEntityType("BusinessPartner"), helper.schema).get("IsPrime"); + func = new IntermediateFunctionFactory().create(new JPADefaultEdmNameBuilder(PUNIT_NAME), helper + .getEntityType(BusinessPartner.class), helper.schema).get("IsPrime"); assertFalse(func.getEdmItem().getReturnType().isNullable()); } + @Test + public void checkByEntityAnnotationResultParameterEnumerationType() throws ODataJPAModelException { + + IntermediateFunction func = new IntermediateDataBaseFunction(new JPADefaultEdmNameBuilder(PUNIT_NAME), helper + .getStoredProcedure(helper.getEntityType(Person.class), "ReturnRights"), BusinessPartner.class, helper.schema); + + assertNotNull(func.getEdmItem().getReturnType()); + assertEquals(PUNIT_NAME + ".AccessRights", func.getEdmItem().getReturnType().getTypeFQN() + .getFullQualifiedNameAsString()); + } + @Test public void checkReturnTypeEmbedded() throws ODataJPAModelException { EdmFunction func = mock(EdmFunction.class); @@ -150,9 +218,8 @@ public Class answer(InvocationOnMock invocation) throws Throwable { } }); - IntermediateFunction act = new IntermediateDataBaseFunction(new JPAEdmNameBuilder(PUNIT_NAME), func, - BusinessPartner.class, - helper.schema); + IntermediateFunction act = new IntermediateDataBaseFunction(new JPADefaultEdmNameBuilder(PUNIT_NAME), func, + BusinessPartner.class, helper.schema); assertEquals("com.sap.olingo.jpa.ChangeInformation", act.getEdmItem().getReturnType().getTypeFQN() .getFullQualifiedNameAsString()); } @@ -172,7 +239,7 @@ public Class answer(InvocationOnMock invocation) throws Throwable { }); IntermediateFunction act; try { - act = new IntermediateDataBaseFunction(new JPAEdmNameBuilder(PUNIT_NAME), func, BusinessPartner.class, + act = new IntermediateDataBaseFunction(new JPADefaultEdmNameBuilder(PUNIT_NAME), func, BusinessPartner.class, helper.schema); act.getEdmItem(); } catch (ODataJPAModelException e) { diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateDescriptionProperty.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateDescriptionProperty.java index 8ef7c082c..a984ec53a 100644 --- a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateDescriptionProperty.java +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateDescriptionProperty.java @@ -1,9 +1,12 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -15,78 +18,142 @@ import javax.persistence.metamodel.Attribute; import javax.persistence.metamodel.EmbeddableType; +import javax.persistence.metamodel.EntityType; import javax.persistence.metamodel.ManagedType; import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind; import org.apache.olingo.commons.api.edm.provider.CsdlAnnotation; import org.apache.olingo.commons.api.edm.provider.annotation.CsdlConstantExpression.ConstantExpressionType; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import com.sap.olingo.jpa.metadata.api.JPAEdmMetadataPostProcessor; import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmDescriptionAssoziation; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAAssociationPath; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEdmNameBuilder; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAStructuredType; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediateEntityTypeAccess; import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediateNavigationPropertyAccess; import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediatePropertyAccess; import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediateReferenceList; import com.sap.olingo.jpa.processor.core.testmodel.BusinessPartner; +import com.sap.olingo.jpa.processor.core.testmodel.Country; +import com.sap.olingo.jpa.processor.core.testmodel.Person; public class TestIntermediateDescriptionProperty extends TestMappingRoot { private TestHelper helper; private IntermediateDescriptionProperty cut; private JPAEdmMetadataPostProcessor processor; + private IntermediateStructuredType et; + private JPAEdmNameBuilder nameBuilder; - @Before + @BeforeEach public void setup() throws ODataJPAModelException { helper = new TestHelper(emf.getMetamodel(), PUNIT_NAME); processor = mock(JPAEdmMetadataPostProcessor.class); + nameBuilder = new JPADefaultEdmNameBuilder(PUNIT_NAME); + EntityType type = helper.getEntityType(BusinessPartner.class); + et = new IntermediateEntityType(nameBuilder, type, helper.schema); IntermediateModelElement.setPostProcessor(new DefaultEdmPostProcessor()); } @Test public void checkProptertyCanBeCreated() throws ODataJPAModelException { - EmbeddableType et = helper.getEmbeddedableType("PostalAddressData"); - Attribute jpaAttribute = helper.getDeclaredAttribute(et, "countryName"); - new IntermediateDescriptionProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, helper.schema); + EmbeddableType emtype = helper.getEmbeddedableType("PostalAddressData"); + Attribute jpaAttribute = helper.getDeclaredAttribute(emtype, "countryName"); + assertNotNull(new IntermediateDescriptionProperty(nameBuilder, jpaAttribute, et, helper.schema)); + } + + @Test + public void checkGetDescriptionAttributeReturnsAttribute() throws ODataJPAModelException { + createDefaultCut(); + assertNotNull(cut.getDescriptionAttribute()); + assertEquals("name", cut.getDescriptionAttribute().getInternalName()); + } + + @Test + public void checkGetFixedValueAssignmentReturnsEmptyList() throws ODataJPAModelException { + createDefaultCut(); + assertNotNull(cut.getFixedValueAssignment()); + assertTrue(cut.getFixedValueAssignment().isEmpty()); + } + + @Test + public void checkGetFixedValueAssignmentReturnsList() throws ODataJPAModelException { + final EntityType type = helper.getEntityType(Person.class); + et = new IntermediateEntityType(nameBuilder, type, helper.schema); + final Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType(BusinessPartner.class), + "locationName"); + cut = new IntermediateDescriptionProperty(nameBuilder, jpaAttribute, et, helper.schema); + cut.lazyBuildEdmItem(); + assertNotNull(cut.getFixedValueAssignment()); + assertEquals(2, cut.getFixedValueAssignment().size()); + } + + @Test + public void checkGetTypeReturnsDescAttributeType() throws ODataJPAModelException { + createDefaultCut(); + assertNotNull(cut.getType()); + assertEquals(String.class, cut.getType()); + } + + @Test + public void checkIsAssociationeReturnsTrue() throws ODataJPAModelException { + createDefaultCut(); + assertTrue(cut.isAssociation()); + } + + @Test + public void checkGetLocaleFieldNameReturnsPath() throws ODataJPAModelException { + createDefaultCut(); + assertNotNull(cut.getLocaleFieldName()); + assertEquals("\"LanguageISO\"", cut.getLocaleFieldName().getDBFieldName()); } @Test public void checkGetProptertyNameOneToMany() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEmbeddedableType("PostalAddressData"), - "countryName"); - cut = new IntermediateDescriptionProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); - assertEquals("Wrong name", "CountryName", cut.getEdmItem().getName()); + createDefaultCut(); + assertEquals("CountryName", cut.getEdmItem().getName(), "Wrong name"); } @Test public void checkGetProptertyNameManyToMany() throws ODataJPAModelException { Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEmbeddedableType("PostalAddressData"), "regionName"); - cut = new IntermediateDescriptionProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); - assertEquals("Wrong name", "RegionName", cut.getEdmItem().getName()); + cut = new IntermediateDescriptionProperty(nameBuilder, jpaAttribute, et, helper.schema); + assertEquals("RegionName", cut.getEdmItem().getName(), "Wrong name"); } @Test public void checkGetProptertyType() throws ODataJPAModelException { Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEmbeddedableType("PostalAddressData"), "countryName"); - cut = new IntermediateDescriptionProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); - assertEquals("Wrong type", EdmPrimitiveTypeKind.String.getFullQualifiedName().getFullQualifiedNameAsString(), - cut.getEdmItem().getType()); + cut = new IntermediateDescriptionProperty(nameBuilder, jpaAttribute, et, helper.schema); + assertEquals(EdmPrimitiveTypeKind.String.getFullQualifiedName().getFullQualifiedNameAsString(), + cut.getEdmItem().getType(), "Wrong type"); + } + + @Test + public void checkGetTargetEntity() throws ODataJPAModelException { + createDefaultCut(); + final JPAStructuredType target = cut.getTargetEntity(); + assertEquals("Country", target.getExternalName()); + } + + @Test + public void checkGetPartnerNull() throws ODataJPAModelException { + createDefaultCut(); + assertNull(cut.getPartner()); } @Test public void checkGetProptertyIgnoreFalse() throws ODataJPAModelException { Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEmbeddedableType("PostalAddressData"), "countryName"); - IntermediatePropertyAccess property = new IntermediateDescriptionProperty(new JPAEdmNameBuilder(PUNIT_NAME), - jpaAttribute, + IntermediatePropertyAccess property = new IntermediateDescriptionProperty(nameBuilder, jpaAttribute, et, helper.schema); assertFalse(property.ignore()); } @@ -95,8 +162,7 @@ public void checkGetProptertyIgnoreFalse() throws ODataJPAModelException { public void checkGetProptertyFacetsNullableTrue() throws ODataJPAModelException { Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEmbeddedableType("PostalAddressData"), "countryName"); - cut = new IntermediateDescriptionProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); + cut = new IntermediateDescriptionProperty(nameBuilder, jpaAttribute, et, helper.schema); assertTrue(cut.getEdmItem().isNullable()); } @@ -104,8 +170,7 @@ public void checkGetProptertyFacetsNullableTrue() throws ODataJPAModelException public void checkGetProptertyMaxLength() throws ODataJPAModelException { Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEmbeddedableType("PostalAddressData"), "countryName"); - cut = new IntermediateDescriptionProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); + cut = new IntermediateDescriptionProperty(nameBuilder, jpaAttribute, et, helper.schema); assertEquals(new Integer(100), cut.getEdmItem().getMaxLength()); } @@ -122,8 +187,7 @@ public void checkWrongPathElementThrowsEcxeption() { when(assoziation.valueAssignments()).thenReturn(valueAssignments); try { - cut = new IntermediateDescriptionProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); + cut = new IntermediateDescriptionProperty(nameBuilder, jpaAttribute, et, helper.schema); cut.getEdmItem(); } catch (ODataJPAModelException e) { return; @@ -144,8 +208,7 @@ public void checkWrongPathStartThrowsEcxeption() { when(assoziation.valueAssignments()).thenReturn(valueAssignments); try { - cut = new IntermediateDescriptionProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); + cut = new IntermediateDescriptionProperty(nameBuilder, jpaAttribute, et, helper.schema); cut.getEdmItem(); } catch (ODataJPAModelException e) { return; @@ -180,15 +243,15 @@ public Class answer(InvocationOnMock invocation) throws Throwab @Test public void checkAnnotations() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType("BusinessPartner"), + Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType(BusinessPartner.class), "locationName"); - cut = new IntermediateDescriptionProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); + cut = new IntermediateDescriptionProperty(nameBuilder, jpaAttribute, et, helper.schema); List annotations = cut.getEdmItem().getAnnotations(); assertEquals(1, annotations.size()); assertEquals("Core.IsLanguageDependent", annotations.get(0).getTerm()); assertEquals(ConstantExpressionType.Bool, annotations.get(0).getExpression().asConstant().getType()); assertEquals("true", annotations.get(0).getExpression().asConstant().getValue()); + assertNull(annotations.get(0).getQualifier()); } @Test @@ -197,9 +260,7 @@ public void checkPostProcessorCalled() throws ODataJPAModelException { IntermediateModelElement.setPostProcessor(processor); Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEmbeddedableType("PostalAddressData"), "countryName"); - cut = new IntermediateDescriptionProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); - + cut = new IntermediateDescriptionProperty(nameBuilder, jpaAttribute, et, helper.schema); cut.getEdmItem(); verify(processor, atLeastOnce()).processProperty(cut, ADDR_CANONICAL_NAME); } @@ -208,13 +269,11 @@ public void checkPostProcessorCalled() throws ODataJPAModelException { public void checkPostProcessorNameChanged() throws ODataJPAModelException { PostProcessorSetName pPDouble = new PostProcessorSetName(); IntermediateModelElement.setPostProcessor(pPDouble); - Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEmbeddedableType("PostalAddressData"), "countryName"); - cut = new IntermediateDescriptionProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); + cut = new IntermediateDescriptionProperty(nameBuilder, jpaAttribute, et, helper.schema); - assertEquals("Wrong name", "CountryDescription", cut.getEdmItem().getName()); + assertEquals("CountryDescription", cut.getEdmItem().getName(), "Wrong name"); } @Test @@ -224,10 +283,121 @@ public void checkPostProcessorExternalNameChanged() throws ODataJPAModelExceptio Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEmbeddedableType("PostalAddressData"), "countryName"); - IntermediatePropertyAccess property = new IntermediateProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); + IntermediatePropertyAccess property = new IntermediateSimpleProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), + jpaAttribute, helper.schema); + + assertEquals("CountryDescription", property.getExternalName(), "Wrong name"); + } + + @Test + public void checkEmptyAssoziationThrowsException() throws ODataJPAModelException { + + final IntermediateDescriptionProperty cut = new IntermediateDescriptionProperty(nameBuilder, createAttributeMock( + false, false, 0), et, helper.schema); + final ODataJPAModelException act = assertThrows(ODataJPAModelException.class, () -> cut.lazyBuildEdmItem()); + assertEquals(ODataJPAModelException.MessageKeys.DESCRIPTION_ANNOTATION_MISSING.getKey(), act.getId()); + } + + @Test + public void checkUnknownAttributeAtTargetThrowsException() throws ODataJPAModelException { + + final IntermediateDescriptionProperty cut = new IntermediateDescriptionProperty(nameBuilder, createAttributeMock( + true, false, 0), et, helper.schema); + final ODataJPAModelException act = assertThrows(ODataJPAModelException.class, () -> cut.lazyBuildEdmItem()); + assertEquals(ODataJPAModelException.MessageKeys.INVALID_DESCIPTION_PROPERTY.getKey(), act.getId()); + } + + @Test + public void checkNoLocationAtTargetThrowsException() throws ODataJPAModelException { + + final IntermediateDescriptionProperty cut = new IntermediateDescriptionProperty(nameBuilder, createAttributeMock( + true, true, 0), et, helper.schema); + final ODataJPAModelException act = assertThrows(ODataJPAModelException.class, () -> cut.lazyBuildEdmItem()); + assertEquals(ODataJPAModelException.MessageKeys.DESCRIPTION_LOCALE_FIELD_MISSING.getKey(), act.getId()); + } + + @Test + public void checkLocationAndLanguageAtTargetThrowsException() throws ODataJPAModelException { + + final IntermediateDescriptionProperty cut = new IntermediateDescriptionProperty(nameBuilder, createAttributeMock( + true, true, 2), et, helper.schema); + final ODataJPAModelException act = assertThrows(ODataJPAModelException.class, () -> cut.lazyBuildEdmItem()); + assertEquals(ODataJPAModelException.MessageKeys.DESCRIPTION_LOCALE_FIELD_MISSING.getKey(), act.getId()); + } + + @Test + public void checkGetPathReturns() throws ODataJPAModelException { + createDefaultCut(); + assertNotNull(cut.getPath()); + } + + @Test + public void checkPathLeftColumnsListEmpty() throws ODataJPAModelException { + createDefaultCut(); + assertTrue(cut.getPath().getLeftColumnsList().isEmpty()); + } + + @Test + public void checkPathRightColumnsListEmpty() throws ODataJPAModelException { + createDefaultCut(); + assertTrue(cut.getPath().getRightColumnsList().isEmpty()); + } + + @Test + public void checkGetLeafNull() throws ODataJPAModelException { + createDefaultCut(); + assertNull(cut.getPath().getLeaf()); + } + + @Test + public void checkPathGetPathEmpty() throws ODataJPAModelException { + createDefaultCut(); + assertTrue(cut.getPath().getPath().isEmpty()); + } + + @Test + public void checkPathGetInverseLeftJoinColumnsListEmpty() throws ODataJPAModelException { + createDefaultCut(); + assertTrue(cut.getPath().getInverseLeftJoinColumnsList().isEmpty()); + } + + @Test + public void checkPathIsCollectionFalse() throws ODataJPAModelException { + createDefaultCut(); + assertFalse(cut.getPath().isCollection()); + } - assertEquals("Wrong name", "CountryDescription", property.getExternalName()); + @Test + public void checkPathGetPartnerNull() throws ODataJPAModelException { + createDefaultCut(); + assertNull(cut.getPath().getPartner()); + } + + @Test + public void checkPathGetJoinTableNull() throws ODataJPAModelException { + createDefaultCut(); + assertNull(cut.getPath().getJoinTable()); + } + + @Test + public void checkPathGetSource() throws ODataJPAModelException { + createDefaultCut(); + final JPAStructuredType act = cut.getPath().getSourceType(); + assertEquals("BusinessPartner", act.getExternalName()); + } + + @Test + public void checkPathGetAliasNull() throws ODataJPAModelException { + createDefaultCut(); + final JPAAssociationPath act = cut.getPath(); + assertNull(act.getAlias()); + } + + @Test + public void checkPathHasJoinTableNull() throws ODataJPAModelException { + createDefaultCut(); + final JPAAssociationPath act = cut.getPath(); + assertNull(act.getJoinTable()); } private class PostProcessorSetName extends JPAEdmMetadataPostProcessor { @@ -255,4 +425,51 @@ public void provideReferences(IntermediateReferenceList references) throws OData private interface AnnotatedMember extends Member, AnnotatedElement { } + + private void createDefaultCut() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEmbeddedableType("PostalAddressData"), + "countryName"); + cut = new IntermediateDescriptionProperty(nameBuilder, jpaAttribute, et, helper.schema); + cut.lazyBuildEdmItem(); + } + + private Attribute createAttributeMock(final boolean assozation, final boolean assozationName, + final int langFields) { + final Attribute attribute = mock(Attribute.class); + final ManagedType mgedType = mock(ManagedType.class); + final Member member = mock(AnnotatedMember.class); + + when(attribute.getName()).thenReturn("WithLocationField"); + when(attribute.getJavaMember()).thenReturn(member); + when(attribute.getDeclaringType()).thenAnswer(new Answer>() { + @Override + public ManagedType answer(InvocationOnMock invocation) throws Throwable { + return mgedType; + } + }); + when(attribute.getJavaType()).thenAnswer(new Answer>() { + @Override + public Class answer(InvocationOnMock invocation) throws Throwable { + return Country.class; + } + }); + + when(mgedType.getJavaType()).thenAnswer(new Answer>() { + @Override + public Class answer(InvocationOnMock invocation) throws Throwable { + return BusinessPartner.class; + } + }); + if (assozation) { + final EdmDescriptionAssoziation a = mock(EdmDescriptionAssoziation.class); + when(((AnnotatedElement) member).getAnnotation(EdmDescriptionAssoziation.class)).thenReturn(a); + if (assozationName) + when(a.descriptionAttribute()).thenReturn("name"); + if (langFields > 0) + when(a.languageAttribute()).thenReturn("language"); + if (langFields > 1) + when(a.localeAttribute()).thenReturn("location"); + } + return attribute; + } } diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateEmbeddedIdProperty.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateEmbeddedIdProperty.java new file mode 100644 index 000000000..72623e96c --- /dev/null +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateEmbeddedIdProperty.java @@ -0,0 +1,64 @@ +/** + * + */ +package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; + +import static com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException.MessageKeys.TRANSIENT_KEY_NOT_SUPPORTED; +import static com.sap.olingo.jpa.processor.core.util.Assertions.assertException; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import javax.persistence.metamodel.Attribute; +import javax.persistence.metamodel.EntityType; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEdmNameBuilder; +import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; +import com.sap.olingo.jpa.processor.core.errormodel.TeamWithTransientEmbeddableKey; +import com.sap.olingo.jpa.processor.core.testmodel.AdministrativeDivisionDescription; + +/** + * @author Oliver Grande + * Created: 22.03.2020 + * + */ +public class TestIntermediateEmbeddedIdProperty extends TestMappingRoot { + private TestHelper helper; + private TestHelper errorHelper; + private JPAEdmNameBuilder nameBuilder; + + @BeforeEach + public void setup() throws ODataJPAModelException { + helper = new TestHelper(emf.getMetamodel(), PUNIT_NAME); + errorHelper = new TestHelper(errorEmf.getMetamodel(), ERROR_PUNIT); + nameBuilder = new JPADefaultEdmNameBuilder(PUNIT_NAME); + } + + @Test + public void checkEmbeddedIdCanBeCreated() throws ODataJPAModelException { + final EntityType et = helper.getEntityType(AdministrativeDivisionDescription.class); + final Attribute jpaAttribute = helper.getAttribute(et, "key"); + assertNotNull(new IntermediateEmbeddedIdProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), jpaAttribute, + helper.schema)); + } + + @Test + public void checkEmbeddedIdIsKey() throws ODataJPAModelException { + final EntityType et = helper.getEntityType(AdministrativeDivisionDescription.class); + final Attribute jpaAttribute = helper.getAttribute(et, "key"); + final IntermediateEmbeddedIdProperty cut = new IntermediateEmbeddedIdProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), jpaAttribute, helper.schema); + assertTrue(cut.isKey()); + } + + @Test + public void checkEmbeddedIdThrowsExceptionIfTransient() throws ODataJPAModelException { + final EntityType et = errorHelper.getEntityType(TeamWithTransientEmbeddableKey.class); + final Attribute jpaAttribute = helper.getAttribute(et, "key"); + assertException(ODataJPAModelException.class, + () -> new IntermediateEmbeddedIdProperty(nameBuilder, jpaAttribute, helper.schema), + TRANSIENT_KEY_NOT_SUPPORTED.getKey()); + } +} diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateEntitySet.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateEntitySet.java index 80d18bf4f..c4c3c08ad 100644 --- a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateEntitySet.java +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateEntitySet.java @@ -1,9 +1,12 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; import java.util.List; import java.util.Set; @@ -13,11 +16,12 @@ import org.apache.olingo.commons.api.edm.provider.CsdlEntitySet; import org.apache.olingo.commons.api.edm.provider.annotation.CsdlConstantExpression; import org.apache.olingo.commons.api.edm.provider.annotation.CsdlConstantExpression.ConstantExpressionType; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.reflections.Reflections; import com.sap.olingo.jpa.metadata.api.JPAEdmMetadataPostProcessor; +import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmEnumeration; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEntityType; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediateEntitySetAccess; @@ -25,18 +29,23 @@ import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediateNavigationPropertyAccess; import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediatePropertyAccess; import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediateReferenceList; +import com.sap.olingo.jpa.processor.core.testmodel.ABCClassifiaction; public class TestIntermediateEntitySet extends TestMappingRoot { private IntermediateSchema schema; private Set> etList; - private JPAEdmNameBuilder namebuilder; + private JPADefaultEdmNameBuilder namebuilder; - @Before + @BeforeEach public void setup() throws ODataJPAModelException { IntermediateModelElement.setPostProcessor(new DefaultEdmPostProcessor()); + final Reflections r = mock(Reflections.class); + when(r.getTypesAnnotatedWith(EdmEnumeration.class)).thenReturn(new HashSet<>(Arrays.asList(new Class[] { + ABCClassifiaction.class }))); + etList = emf.getMetamodel().getEntities(); - namebuilder = new JPAEdmNameBuilder(PUNIT_NAME); - schema = new IntermediateSchema(namebuilder, emf.getMetamodel(), mock(Reflections.class)); + namebuilder = new JPADefaultEdmNameBuilder(PUNIT_NAME); + schema = new IntermediateSchema(namebuilder, emf.getMetamodel(), r); } @Test @@ -52,7 +61,7 @@ public void checkAnnotationSet() throws ODataJPAModelException { @Test public void checkODataEntityTypeDiffers() throws ODataJPAModelException { - IntermediateEntityType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateEntityType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "BestOrganization"), schema); IntermediateEntitySet set = new IntermediateEntitySet(namebuilder, et); @@ -62,7 +71,7 @@ public void checkODataEntityTypeDiffers() throws ODataJPAModelException { @Test public void checkODataEntityTypeSame() throws ODataJPAModelException { - IntermediateEntityType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateEntityType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "Organization"), schema); IntermediateEntitySet set = new IntermediateEntitySet(namebuilder, et); @@ -72,11 +81,11 @@ public void checkODataEntityTypeSame() throws ODataJPAModelException { @Test public void checkEdmItemContainsODataEntityType() throws ODataJPAModelException { - IntermediateEntityType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( - "BestOrganization"), schema); - IntermediateEntitySet set = new IntermediateEntitySet(namebuilder, et); - CsdlEntitySet act = set.getEdmItem(); - assertEquals(namebuilder.buildFQN("BusinessPartner").getFullQualifiedNameAsString(), act.getType()); + final IntermediateEntityType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), + getEntityType("BestOrganization"), schema); + final IntermediateEntitySet set = new IntermediateEntitySet(namebuilder, et); + final CsdlEntitySet act = set.getEdmItem(); + assertEquals(et.buildFQN("BusinessPartner").getFullQualifiedNameAsString(), act.getType()); } @Test @@ -86,7 +95,7 @@ public void checkPostProcessorExternalNameChanged() throws ODataJPAModelExceptio IntermediateEntitySet set = new IntermediateEntitySet(namebuilder, et); set.getEdmItem(); // Trigger build of EdmEntitySet - assertEquals("Wrong name", "BusinessPartnerList", set.getExternalName()); + assertEquals("BusinessPartnerList", set.getExternalName(), "Wrong name"); } private class PostProcessor extends JPAEdmMetadataPostProcessor { @@ -118,7 +127,7 @@ public void processEntitySet(final IntermediateEntitySetAccess entitySet) { CsdlAnnotation annotation = new CsdlAnnotation(); annotation.setExpression(mimeType); annotation.setTerm("Capabilities.TopSupported"); - List annotations = new ArrayList(); + List annotations = new ArrayList<>(); annotations.add(annotation); entitySet.addAnnotations(annotations); diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateEntityType.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateEntityType.java index 1afa922a3..0d6c2d791 100644 --- a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateEntityType.java +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateEntityType.java @@ -1,13 +1,19 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException.MessageKeys.PROPERTY_REQUIRED_UNKNOWN; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; import java.util.List; import java.util.Set; @@ -18,43 +24,54 @@ import org.apache.olingo.commons.api.edm.provider.annotation.CsdlConstantExpression; import org.apache.olingo.commons.api.edm.provider.annotation.CsdlConstantExpression.ConstantExpressionType; import org.apache.olingo.commons.api.edm.provider.annotation.CsdlExpression; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.reflections.Reflections; import com.sap.olingo.jpa.metadata.api.JPAEdmMetadataPostProcessor; +import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmEnumeration; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEntityType; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAOnConditionItem; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAPath; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAProtectionInfo; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAStructuredType; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediateEntityTypeAccess; import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediateNavigationPropertyAccess; import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediatePropertyAccess; import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediateReferenceList; +import com.sap.olingo.jpa.processor.core.errormodel.TeamWithTransientError; +import com.sap.olingo.jpa.processor.core.testmodel.ABCClassifiaction; import com.sap.olingo.jpa.processor.core.testmodel.TestDataConstants; public class TestIntermediateEntityType extends TestMappingRoot { private Set> etList; private IntermediateSchema schema; + private IntermediateSchema errorSchema; - @Before + @BeforeEach public void setup() throws ODataJPAModelException { IntermediateModelElement.setPostProcessor(new DefaultEdmPostProcessor()); + final Reflections r = mock(Reflections.class); + when(r.getTypesAnnotatedWith(EdmEnumeration.class)).thenReturn(new HashSet<>(Arrays.asList(new Class[] { + ABCClassifiaction.class }))); + etList = emf.getMetamodel().getEntities(); - schema = new IntermediateSchema(new JPAEdmNameBuilder(PUNIT_NAME), emf.getMetamodel(), mock(Reflections.class)); + schema = new IntermediateSchema(new JPADefaultEdmNameBuilder(PUNIT_NAME), emf.getMetamodel(), r); + errorSchema = new IntermediateSchema(new JPADefaultEdmNameBuilder(ERROR_PUNIT), errorEmf.getMetamodel(), r); } @Test - public void checkEntityTypeCanBeCreated() throws ODataJPAModelException { + public void checkEntityTypeCanBeCreated() { - new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType("BusinessPartner"), schema); + assertNotNull(new IntermediateEntityType(new JPADefaultEdmNameBuilder( + PUNIT_NAME), getEntityType("BusinessPartner"), schema)); } @Test public void checkEntityTypeIgnoreSet() throws ODataJPAModelException { - IntermediateStructuredType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateStructuredType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "DummyToBeIgnored"), schema); et.getEdmItem(); assertTrue(et.ignore()); @@ -62,86 +79,86 @@ public void checkEntityTypeIgnoreSet() throws ODataJPAModelException { @Test public void checkGetAllProperties() throws ODataJPAModelException { - IntermediateStructuredType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateStructuredType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "BusinessPartner"), schema); - assertEquals("Wrong number of entities", TestDataConstants.NO_DEC_ATTRIBUTES_BUISNESS_PARTNER, et.getEdmItem() + assertEquals(TestDataConstants.NO_DEC_ATTRIBUTES_BUISNESS_PARTNER, et.getEdmItem() .getProperties() - .size()); + .size(), "Wrong number of entities"); } @Test public void checkGetPropertyByNameNotNull() throws ODataJPAModelException { - IntermediateStructuredType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateStructuredType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "BusinessPartner"), schema); assertNotNull(et.getEdmItem().getProperty("Type")); } @Test public void checkGetPropertyByNameCorrectEntity() throws ODataJPAModelException { - IntermediateStructuredType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateStructuredType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "BusinessPartner"), schema); assertEquals("Type", et.getEdmItem().getProperty("Type").getName()); } @Test public void checkGetPropertyByNameCorrectEntityID() throws ODataJPAModelException { - IntermediateStructuredType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateStructuredType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "BusinessPartner"), schema); assertEquals("ID", et.getEdmItem().getProperty("ID").getName()); } @Test public void checkGetPathByNameCorrectEntityID() throws ODataJPAModelException { - IntermediateStructuredType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateStructuredType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "BusinessPartner"), schema); assertEquals("ID", et.getPath("ID").getLeaf().getExternalName()); } @Test public void checkGetPathByNameIgnore() throws ODataJPAModelException { - IntermediateStructuredType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateStructuredType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "BusinessPartner"), schema); assertNull(et.getPath("CustomString2")); } @Test public void checkGetPathByNameIgnoreCompexType() throws ODataJPAModelException { - IntermediateStructuredType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateStructuredType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "BusinessPartner"), schema); assertNull(et.getPath("Address/RegionCodePublisher")); } @Test public void checkGetInheritedAttributeByNameCorrectEntityID() throws ODataJPAModelException { - IntermediateStructuredType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateStructuredType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "Person"), schema); assertEquals("ID", et.getPath("ID").getLeaf().getExternalName()); } @Test public void checkGetAllNaviProperties() throws ODataJPAModelException { - IntermediateStructuredType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateStructuredType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "BusinessPartner"), schema); - assertEquals("Wrong number of entities", 1, et.getEdmItem().getNavigationProperties().size()); + assertEquals(1, et.getEdmItem().getNavigationProperties().size(), "Wrong number of entities"); } @Test public void checkGetNaviPropertyByNameNotNull() throws ODataJPAModelException { - IntermediateStructuredType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateStructuredType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "BusinessPartner"), schema); assertNotNull(et.getEdmItem().getNavigationProperty("Roles")); } @Test public void checkGetNaviPropertyByNameCorrectEntity() throws ODataJPAModelException { - IntermediateStructuredType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateStructuredType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "BusinessPartner"), schema); assertEquals("Roles", et.getEdmItem().getNavigationProperty("Roles").getName()); } @Test public void checkGetAssoziationOfComplexTypeByNameCorrectEntity() throws ODataJPAModelException { - IntermediateStructuredType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateStructuredType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "BusinessPartner"), schema); assertEquals("Address/AdministrativeDivision", et.getAssociationPath("Address/AdministrativeDivision").getAlias()); } @@ -149,7 +166,7 @@ public void checkGetAssoziationOfComplexTypeByNameCorrectEntity() throws ODataJP @Test public void checkGetAssoziationOfComplexTypeByNameJoinColumns() throws ODataJPAModelException { int actCount = 0; - IntermediateStructuredType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateStructuredType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "BusinessPartner"), schema); for (JPAOnConditionItem item : et.getAssociationPath("Address/AdministrativeDivision").getJoinColumnsList()) { if (item.getLeftPath().getAlias().equals("Address/Region")) { @@ -165,7 +182,7 @@ public void checkGetAssoziationOfComplexTypeByNameJoinColumns() throws ODataJPAM actCount++; } } - assertEquals("Not all join columns found", 3, actCount); + assertEquals(3, actCount, "Not all join columns found"); } @Test @@ -173,62 +190,62 @@ public void checkGetPropertiesSkipIgnored() throws ODataJPAModelException { PostProcessorSetIgnore pPDouble = new PostProcessorSetIgnore(); IntermediateModelElement.setPostProcessor(pPDouble); - IntermediateStructuredType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateStructuredType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "BusinessPartner"), schema); - assertEquals("Wrong number of entities", TestDataConstants.NO_DEC_ATTRIBUTES_BUISNESS_PARTNER - 1, et.getEdmItem() - .getProperties().size()); + assertEquals(TestDataConstants.NO_DEC_ATTRIBUTES_BUISNESS_PARTNER - 1, et.getEdmItem() + .getProperties().size(), "Wrong number of entities"); } @Test public void checkGetIsAbstract() throws ODataJPAModelException { - IntermediateStructuredType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateStructuredType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "BusinessPartner"), schema); assertTrue(et.getEdmItem().isAbstract()); } @Test public void checkGetIsNotAbstract() throws ODataJPAModelException { - IntermediateStructuredType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateStructuredType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "Organization"), schema); assertFalse(et.getEdmItem().isAbstract()); } @Test public void checkGetHasBaseType() throws ODataJPAModelException { - IntermediateStructuredType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateStructuredType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "Organization"), schema); assertEquals(PUNIT_NAME + ".BusinessPartner", et.getEdmItem().getBaseType()); } @Test public void checkGetKeyProperties() throws ODataJPAModelException { - IntermediateEntityType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateEntityType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "BusinessPartnerRole"), schema); - assertEquals("Wrong number of key propeties", 2, et.getEdmItem().getKey().size()); + assertEquals(2, et.getEdmItem().getKey().size(), "Wrong number of key propeties"); } @Test public void checkGetAllAttributes() throws ODataJPAModelException { - IntermediateStructuredType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateStructuredType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "BusinessPartnerRole"), schema); - assertEquals("Wrong number of entities", 2, et.getPathList().size()); + assertEquals(2, et.getPathList().size(), "Wrong number of entities"); } @Test public void checkGetAllAttributesWithBaseType() throws ODataJPAModelException { - IntermediateStructuredType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateStructuredType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "Organization"), schema); int exp = TestDataConstants.NO_ATTRIBUTES_BUISNESS_PARTNER + TestDataConstants.NO_ATTRIBUTES_POSTAL_ADDRESS + TestDataConstants.NO_ATTRIBUTES_COMMUNICATION_DATA + 2 * TestDataConstants.NO_ATTRIBUTES_CHANGE_INFO + TestDataConstants.NO_ATTRIBUTES_ORGANIZATION; - assertEquals("Wrong number of entities", exp, et.getPathList().size()); + assertEquals(exp, et.getPathList().size(), "Wrong number of entities"); } @Test public void checkGetAllAttributesWithBaseTypeFields() throws ODataJPAModelException { - IntermediateStructuredType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateStructuredType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "Organization"), schema); assertNotNull(et.getPath("Type")); @@ -240,98 +257,126 @@ public void checkGetAllAttributesWithBaseTypeFields() throws ODataJPAModelExcept @Test public void checkGetAllAttributeIDWithBaseType() throws ODataJPAModelException { - IntermediateStructuredType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateStructuredType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "Organization"), schema); assertEquals("ID", et.getPath("ID").getAlias()); } + @Test + public void checkGetKeyAttributeFromEmbeddedId() throws ODataJPAModelException { + IntermediateEntityType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( + "AdministrativeDivisionDescription"), schema); + + assertTrue(et.getAttribute("codePublisher").isPresent()); + assertEquals("CodePublisher", et.getAttribute("codePublisher").get().getExternalName()); + } + @Test public void checkGetKeyWithBaseType() throws ODataJPAModelException { - IntermediateEntityType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateEntityType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "Organization"), schema); assertEquals(1, et.getKey().size()); } @Test public void checkEmbeddedIdResovedProperties() throws ODataJPAModelException { - IntermediateEntityType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateEntityType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "AdministrativeDivisionDescription"), schema); assertEquals(5, et.getEdmItem().getProperties().size()); } @Test public void checkEmbeddedIdResovedKey() throws ODataJPAModelException { - IntermediateEntityType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateEntityType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "AdministrativeDivisionDescription"), schema); assertEquals(4, et.getEdmItem().getKey().size()); } @Test public void checkEmbeddedIdResovedKeyInternal() throws ODataJPAModelException { - IntermediateEntityType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateEntityType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "AdministrativeDivisionDescription"), schema); assertEquals(4, et.getKey().size()); } + @Test + public void checkEmbeddedIdResovedKeyCorrectOrder() throws ODataJPAModelException { + IntermediateEntityType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( + "AdministrativeDivisionDescription"), schema); + assertEquals("Language", et.getKey().get(0).getExternalName()); + assertEquals("DivisionCode", et.getKey().get(1).getExternalName()); + assertEquals("CodeID", et.getKey().get(2).getExternalName()); + assertEquals("CodePublisher", et.getKey().get(3).getExternalName()); + } + + @Test + public void checkCompoundResovedKeyCorrectOrder() throws ODataJPAModelException { + IntermediateEntityType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( + "AdministrativeDivision"), schema); + assertEquals("DivisionCode", et.getKey().get(0).getExternalName()); + assertEquals("CodeID", et.getKey().get(1).getExternalName()); + assertEquals("CodePublisher", et.getKey().get(2).getExternalName()); + } + @Test public void checkEmbeddedIdResovedPath() throws ODataJPAModelException { - JPAStructuredType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + JPAStructuredType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "AdministrativeDivisionDescription"), schema); assertEquals(5, et.getPathList().size()); } @Test public void checkEmbeddedIdResovedPathCodeId() throws ODataJPAModelException { - JPAStructuredType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + JPAStructuredType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "AdministrativeDivisionDescription"), schema); assertEquals(2, et.getPath("CodeID").getPath().size()); } @Test public void checkHasStreamNoProperties() throws ODataJPAModelException { - IntermediateEntityType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateEntityType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "PersonImage"), schema); assertEquals(2, et.getEdmItem().getProperties().size()); } @Test public void checkHasStreamTrue() throws ODataJPAModelException { - IntermediateEntityType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateEntityType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "PersonImage"), schema); assertTrue(et.getEdmItem().hasStream()); } @Test public void checkHasStreamFalse() throws ODataJPAModelException { - IntermediateEntityType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateEntityType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "BusinessPartner"), schema); assertFalse(et.getEdmItem().hasStream()); } @Test public void checkHasETagTrue() throws ODataJPAModelException { - IntermediateEntityType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateEntityType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "BusinessPartner"), schema); assertTrue(et.hasEtag()); } @Test public void checkHasETagTrueIfInherited() throws ODataJPAModelException { - IntermediateEntityType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateEntityType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "Organization"), schema); assertTrue(et.hasEtag()); } @Test public void checkHasETagFalse() throws ODataJPAModelException { - IntermediateEntityType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateEntityType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "AdministrativeDivision"), schema); assertFalse(et.hasEtag()); } @Test public void checkIgnoreIfAsEntitySet() throws ODataJPAModelException { - IntermediateEntityType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateEntityType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "BestOrganization"), schema); assertTrue(et.ignore()); } @@ -339,7 +384,7 @@ public void checkIgnoreIfAsEntitySet() throws ODataJPAModelException { @Test public void checkAnnotationSet() throws ODataJPAModelException { IntermediateModelElement.setPostProcessor(new PostProcessorSetIgnore()); - IntermediateEntityType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateEntityType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "PersonImage"), schema); List act = et.getEdmItem().getAnnotations(); assertEquals(1, act.size()); @@ -348,29 +393,222 @@ public void checkAnnotationSet() throws ODataJPAModelException { @Test public void checkGetProptertyByDBFieldName() throws ODataJPAModelException { - IntermediateStructuredType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateStructuredType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "BusinessPartner"), schema); assertEquals("Type", et.getPropertyByDBField("\"Type\"").getExternalName()); } @Test public void checkGetProptertyByDBFieldNameFromSuperType() throws ODataJPAModelException { - IntermediateStructuredType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateStructuredType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "Organization"), schema); assertEquals("Type", et.getPropertyByDBField("\"Type\"").getExternalName()); } @Test public void checkGetProptertyByDBFieldNameFromEmbedded() throws ODataJPAModelException { - IntermediateStructuredType et = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), getEntityType( + IntermediateStructuredType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( "AdministrativeDivisionDescription"), schema); assertEquals("CodeID", et.getPropertyByDBField("\"CodeID\"").getExternalName()); } - @Ignore @Test - public void checkGetPropertyWithEnumerationType() { + public void checkAllPathContainsComplexCollcetion() throws ODataJPAModelException { + IntermediateStructuredType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( + "Collection"), schema); + final List act = et.getPathList(); + + assertEquals(11, act.size()); + assertNotNull(et.getPath("Complex/Address")); + assertTrue(et.getPath("Complex/Address").getLeaf().isCollection()); + final IntermediateCollectionProperty actIntermediate = (IntermediateCollectionProperty) et.getPath( + "Complex/Address").getLeaf(); + assertTrue(actIntermediate.asAssociation().getSourceType() instanceof JPAEntityType); + assertEquals(2, actIntermediate.asAssociation().getPath().size()); + + for (JPAPath p : act) { + if (p.getPath().size() > 1 + && p.getPath().get(0).getExternalName().equals("Complex") + && p.getPath().get(1).getExternalName().equals("Address")) { + assertTrue(p.getPath().get(1) instanceof IntermediateCollectionProperty); + final IntermediateCollectionProperty actProperty = (IntermediateCollectionProperty) p.getPath().get(1); + assertNotNull(actProperty.asAssociation()); + assertEquals(et, actProperty.asAssociation().getSourceType()); + break; + } + } + } + + @Test + public void checkAllPathContainsPrimitiveCollcetion() throws ODataJPAModelException { + IntermediateStructuredType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( + "Collection"), schema); + final List act = et.getPathList(); + + assertEquals(11, act.size()); + assertNotNull(et.getPath("Complex/Comment")); + assertTrue(et.getPath("Complex/Comment").getLeaf().isCollection()); + final IntermediateCollectionProperty actIntermediate = (IntermediateCollectionProperty) et.getPath( + "Complex/Comment").getLeaf(); + assertTrue(actIntermediate.asAssociation().getSourceType() instanceof JPAEntityType); + assertEquals("Complex/Comment", actIntermediate.asAssociation().getAlias()); + + for (JPAPath p : act) { + if (p.getPath().size() > 1 + && p.getPath().get(0).getExternalName().equals("Complex") + && p.getPath().get(1).getExternalName().equals("Comment")) { + assertTrue(p.getPath().get(1) instanceof IntermediateCollectionProperty); + final IntermediateCollectionProperty actProperty = (IntermediateCollectionProperty) p.getPath().get(1); + assertNotNull(actProperty.asAssociation()); + assertEquals(et, actProperty.asAssociation().getSourceType()); + break; + } + } + } + + @Test + public void checkAllPathContainsDeepComplexWithPrimitiveCollcetion() throws ODataJPAModelException { + IntermediateStructuredType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( + "CollectionDeep"), schema); + final List act = et.getPathList(); + + assertEquals(9, act.size()); + assertNotNull(et.getPath("FirstLevel/SecondLevel/Comment")); + assertTrue(et.getPath("FirstLevel/SecondLevel/Comment").getLeaf().isCollection()); + final IntermediateCollectionProperty actIntermediate = (IntermediateCollectionProperty) et.getPath( + "FirstLevel/SecondLevel/Comment").getLeaf(); + assertTrue(actIntermediate.asAssociation().getSourceType() instanceof JPAEntityType); + assertEquals(3, actIntermediate.asAssociation().getPath().size()); + assertEquals("FirstLevel/SecondLevel/Comment", actIntermediate.asAssociation().getAlias()); + } + + @Test + public void checkAllPathContainsDeepComplexWithComplexCollcetion() throws ODataJPAModelException { + IntermediateStructuredType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( + "CollectionDeep"), schema); + + assertNotNull(et.getPath("FirstLevel/SecondLevel/Address")); + assertTrue(et.getPath("FirstLevel/SecondLevel/Address").getLeaf().isCollection()); + final IntermediateCollectionProperty actIntermediate = (IntermediateCollectionProperty) et.getPath( + "FirstLevel/SecondLevel/Address").getLeaf(); + assertTrue(actIntermediate.asAssociation().getSourceType() instanceof JPAEntityType); + assertEquals(3, actIntermediate.asAssociation().getPath().size()); + assertEquals("FirstLevel/SecondLevel/Address", actIntermediate.asAssociation().getAlias()); + for (JPAPath path : et.getPathList()) { + String[] pathElements = path.getAlias().split("/"); + assertEquals(pathElements.length, path.getPath().size()); + } + } + + @Test + public void checkOneSimpleProtectedProperty() throws ODataJPAModelException { + IntermediateStructuredType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( + "BusinessPartnerProtected"), schema); + List act = et.getProtections(); + assertNotNull(act); + assertEquals(1, act.size()); + assertEquals("Username", act.get(0).getAttribute().getExternalName()); + assertEquals("UserId", act.get(0).getClaimName()); + } + + @Test + public void checkOneComplexProtectedProperty() throws ODataJPAModelException { + IntermediateStructuredType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( + "DeepProtectedExample"), schema); + List act = et.getProtections(); + assertNotNull(act); + assertEquals(3, act.size()); + assertNotNull(act.get(0).toString()); + } + + @Test + public void checkComplexAndInheritedProtectedProperty() throws ODataJPAModelException { + IntermediateStructuredType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( + "PersonDeepProtectedHidden"), schema); + + List act = et.getProtections(); + assertNotNull(act); + assertInherited(act); + assertComplexAnnotated(act, "Creator", "Created"); + assertComplexAnnotated(act, "Updator", "Updated"); + assertComplexDeep(act); + assertEquals(4, act.size()); + } + + @Test + public void checkEmbeddedIdKeyIsCompound() throws ODataJPAModelException { + IntermediateEntityType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( + "AdministrativeDivisionDescription"), schema); + assertTrue(et.hasCompoundKey()); + } + + @Test + public void checkMultipleKeyIsCompound() throws ODataJPAModelException { + IntermediateEntityType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( + "AdministrativeDivision"), schema); + assertTrue(et.hasCompoundKey()); + } + + @Test + public void checkIdIsNotCompound() throws ODataJPAModelException { + IntermediateEntityType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), getEntityType( + "BusinessPartner"), schema); + assertFalse(et.hasCompoundKey()); + } + + @Test + public void checkTransientWithRefComplex() throws ODataJPAModelException { + final IntermediateEntityType et = new IntermediateEntityType(nameBuilder, + getEntityType("TransientRefComplex"), schema); + assertTrue(et.getAttribute("concatenatedAddr").get().isTransient()); + } + + @Test + public void checkTransientThrowsExceptionWithReferenceUnknown() throws ODataJPAModelException { + final EntityType jpaEt = errorEmf.getMetamodel().entity(TeamWithTransientError.class); + final IntermediateEntityType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder( + ERROR_PUNIT), jpaEt, errorSchema); + + final ODataJPAModelException act = assertThrows(ODataJPAModelException.class, () -> et.getAttribute("fullName")); + assertEquals(PROPERTY_REQUIRED_UNKNOWN.getKey(), act.getId()); + } + + private void assertComplexDeep(List act) { + for (final JPAProtectionInfo info : act) { + if (info.getClaimName().equals("BuildingNumber")) { + assertEquals("Building", info.getAttribute().getExternalName()); + assertEquals(3, info.getPath().getPath().size()); + assertEquals("InhouseAddress/InhouseAddress/Building", info.getPath().getAlias()); + return; + } + } + fail("Deep protected complex attribute not found"); + + } + private void assertComplexAnnotated(List act, final String expClaimName, + final String pathElement) { + for (final JPAProtectionInfo info : act) { + if (info.getClaimName().equals(expClaimName)) { + assertEquals("By", info.getAttribute().getExternalName()); + assertEquals(3, info.getPath().getPath().size()); + assertEquals("ProtectedAdminInfo/" + pathElement + "/By", info.getPath().getAlias()); + return; + } + } + fail("Complex attribute not found for: " + expClaimName); + } + + private void assertInherited(List act) { + for (final JPAProtectionInfo info : act) { + if (info.getAttribute().getExternalName().equals("Username")) { + assertEquals("UserId", info.getClaimName()); + assertEquals(1, info.getPath().getPath().size()); + assertEquals("Username", info.getPath().getAlias()); + return; + } + } + fail("Inherited not found"); } private class PostProcessorSetIgnore extends JPAEdmMetadataPostProcessor { @@ -392,7 +630,7 @@ public void processNavigationProperty(IntermediateNavigationPropertyAccess prope @Override public void processEntityType(IntermediateEntityTypeAccess entity) { if (entity.getExternalName().equals("PersonImage")) { - List items = new ArrayList(); + List items = new ArrayList<>(); CsdlCollection exp = new CsdlCollection(); exp.setItems(items); CsdlConstantExpression mimeType = new CsdlConstantExpression(ConstantExpressionType.String, "ogg"); @@ -400,7 +638,7 @@ public void processEntityType(IntermediateEntityTypeAccess entity) { CsdlAnnotation annotation = new CsdlAnnotation(); annotation.setExpression(exp); annotation.setTerm("Core.AcceptableMediaTypes"); - List annotations = new ArrayList(); + List annotations = new ArrayList<>(); annotations.add(annotation); entity.addAnnotations(annotations); } @@ -410,7 +648,7 @@ public void processEntityType(IntermediateEntityTypeAccess entity) { public void provideReferences(IntermediateReferenceList references) throws ODataJPAModelException {} } - private EntityType getEntityType(String typeName) { + private EntityType getEntityType(final String typeName) { for (EntityType entityType : etList) { if (entityType.getJavaType().getSimpleName().equals(typeName)) { return entityType; diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateEnumerationType.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateEnumerationType.java index 2fefe7b7f..b97aac239 100644 --- a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateEnumerationType.java +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateEnumerationType.java @@ -1,16 +1,157 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.MockitoAnnotations; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; import com.sap.olingo.jpa.metadata.core.edm.mapper.testobjects.DayOfWeek; +import com.sap.olingo.jpa.metadata.core.edm.mapper.testobjects.FileAccess; +import com.sap.olingo.jpa.metadata.core.edm.mapper.testobjects.WrongMember; +import com.sap.olingo.jpa.metadata.core.edm.mapper.testobjects.WrongType; public class TestIntermediateEnumerationType extends TestMappingRoot { + private IntermediateEnumerationType cut; + @BeforeEach + public void setup() { + MockitoAnnotations.initMocks(this); + } + @Test - public void checkGet() throws ODataJPAModelException { - cut = new IntermediateEnumerationType(new JPAEdmNameBuilder(PUNIT_NAME), DayOfWeek.class); + public void checkCsdlEnumTypeAccessable() throws ODataJPAModelException { + cut = new IntermediateEnumerationType(new JPADefaultEdmNameBuilder(PUNIT_NAME), DayOfWeek.class); + assertNotNull(cut.getEdmItem()); + } + + @Test + public void checkNameProvided() throws ODataJPAModelException { + cut = new IntermediateEnumerationType(new JPADefaultEdmNameBuilder(PUNIT_NAME), DayOfWeek.class); cut.getEdmItem(); + assertEquals("DayOfWeek", cut.getEdmItem().getName()); + } + + @Test + public void checkIsFlagProvidesFalse() throws ODataJPAModelException { + cut = new IntermediateEnumerationType(new JPADefaultEdmNameBuilder(PUNIT_NAME), DayOfWeek.class); + cut.getEdmItem(); + assertFalse(cut.getEdmItem().isFlags()); + } + + @Test + public void checkIsFlagProvidesTrue() throws ODataJPAModelException { + cut = new IntermediateEnumerationType(new JPADefaultEdmNameBuilder(PUNIT_NAME), FileAccess.class); + cut.getEdmItem(); + assertTrue(cut.getEdmItem().isFlags()); + } + + @Test + public void checkUnderlyingTypeIntAsDefault() throws ODataJPAModelException { + cut = new IntermediateEnumerationType(new JPADefaultEdmNameBuilder(PUNIT_NAME), DayOfWeek.class); + cut.getEdmItem(); + assertEquals(EdmPrimitiveTypeKind.Int32.getFullQualifiedName().getFullQualifiedNameAsString(), cut.getEdmItem() + .getUnderlyingType()); + } + + @Test + public void checkUnderlyingTypeFromConverter() throws ODataJPAModelException { + cut = new IntermediateEnumerationType(new JPADefaultEdmNameBuilder(PUNIT_NAME), FileAccess.class); + cut.getEdmItem(); + assertEquals(EdmPrimitiveTypeKind.Int16.getFullQualifiedName().getFullQualifiedNameAsString(), cut.getEdmItem() + .getUnderlyingType()); + } + + @Test + public void checkReturnsRightNumberOfMember4() throws ODataJPAModelException { + cut = new IntermediateEnumerationType(new JPADefaultEdmNameBuilder(PUNIT_NAME), FileAccess.class); + cut.getEdmItem(); + assertEquals(4, cut.getEdmItem().getMembers().size()); + } + + @Test + public void checkReturnsRightNumberOfMember7() throws ODataJPAModelException { + cut = new IntermediateEnumerationType(new JPADefaultEdmNameBuilder(PUNIT_NAME), DayOfWeek.class); + cut.getEdmItem(); + assertEquals(7, cut.getEdmItem().getMembers().size()); + } + + @Test + public void checkReturnsRightNameForMembersOfDayOfWeek() throws ODataJPAModelException { + cut = new IntermediateEnumerationType(new JPADefaultEdmNameBuilder(PUNIT_NAME), DayOfWeek.class); + cut.getEdmItem(); + assertEquals("MONDAY", cut.getEdmItem().getMembers().get(0).getName()); + assertEquals("SUNDAY", cut.getEdmItem().getMembers().get(6).getName()); + } + + @Test + public void checkReturnsRightValueForMembersOfDayOfWeek() throws ODataJPAModelException { + cut = new IntermediateEnumerationType(new JPADefaultEdmNameBuilder(PUNIT_NAME), DayOfWeek.class); + cut.getEdmItem(); + assertEquals("0", cut.getEdmItem().getMembers().get(0).getValue()); + assertEquals("6", cut.getEdmItem().getMembers().get(6).getValue()); + } + + @Test + public void checkReturnsRightNameForMembersOfFileAccess() throws ODataJPAModelException { + cut = new IntermediateEnumerationType(new JPADefaultEdmNameBuilder(PUNIT_NAME), FileAccess.class); + cut.getEdmItem(); + assertEquals("Read", cut.getEdmItem().getMembers().get(0).getName()); + assertEquals("Delete", cut.getEdmItem().getMembers().get(3).getName()); + } + + @Test + public void checkReturnsRightValueForMembersOfFileAccess() throws ODataJPAModelException { + cut = new IntermediateEnumerationType(new JPADefaultEdmNameBuilder(PUNIT_NAME), FileAccess.class); + cut.getEdmItem(); + assertEquals("1", cut.getEdmItem().getMembers().get(0).getValue()); + assertEquals("8", cut.getEdmItem().getMembers().get(3).getValue()); + } + + @Test + public void checkThrowsErrorOnIsFlagTrueAndNegativeValue() throws ODataJPAModelException { + cut = new IntermediateEnumerationType(new JPADefaultEdmNameBuilder(PUNIT_NAME), WrongMember.class); + assertThrows(ODataJPAModelException.class, () -> { + cut.getEdmItem(); + }); + } + + @Test + public void checkThrowsErrorOnNotSupportedUnderlyingType() throws ODataJPAModelException { + cut = new IntermediateEnumerationType(new JPADefaultEdmNameBuilder(PUNIT_NAME), WrongType.class); + assertThrows(ODataJPAModelException.class, () -> { + cut.getEdmItem(); + }); + } + + @Test + public void checkOrdinalMemberProvidedFromStringWOConverter() throws ODataJPAModelException { + cut = new IntermediateEnumerationType(new JPADefaultEdmNameBuilder(PUNIT_NAME), DayOfWeek.class); + assertEquals(DayOfWeek.SUNDAY, cut.enumOf("SUNDAY")); + } + + @Test + public void checkOrdinalMemberProvidedFromNumberWOConverter() throws ODataJPAModelException { + cut = new IntermediateEnumerationType(new JPADefaultEdmNameBuilder(PUNIT_NAME), DayOfWeek.class); + assertEquals(DayOfWeek.TUESDAY, cut.enumOf(1)); + } + + @Test + public void checkOrdinalMemberProvidedFromStringWithConverter() throws ODataJPAModelException { + cut = new IntermediateEnumerationType(new JPADefaultEdmNameBuilder(PUNIT_NAME), FileAccess.class); + assertEquals(FileAccess.Create, cut.enumOf("Create")); + } + + @Test + public void checkOrdinalMemberProvidedFromNumberWithConverter() throws ODataJPAModelException { + cut = new IntermediateEnumerationType(new JPADefaultEdmNameBuilder(PUNIT_NAME), FileAccess.class); + assertEquals(FileAccess.Write, cut.enumOf((short) 2)); } } diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateFunctionFactory.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateFunctionFactory.java index 1f80c1e73..9ea87b6cb 100644 --- a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateFunctionFactory.java +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateFunctionFactory.java @@ -1,7 +1,7 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -9,8 +9,8 @@ import java.util.Map; import java.util.Set; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.reflections.Reflections; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; @@ -25,31 +25,31 @@ public class TestIntermediateFunctionFactory extends TestMappingRoot { private IntermediateFunctionFactory cut; private Set> javaFunctions; - @Before + @BeforeEach public void setUp() throws ODataJPAModelException { helper = new TestHelper(emf.getMetamodel(), PUNIT_NAME); reflections = mock(Reflections.class); cut = new IntermediateFunctionFactory(); - javaFunctions = new HashSet>(); + javaFunctions = new HashSet<>(); when(reflections.getSubTypesOf(ODataFunction.class)).thenReturn(javaFunctions); } @Test public void checkReturnEmptyMapIfReflectionsNull() throws ODataJPAModelException { Reflections r = null; - assertNotNull(cut.create(new JPAEdmNameBuilder(PUNIT_NAME), r, helper.schema)); + assertNotNull(cut.create(new JPADefaultEdmNameBuilder(PUNIT_NAME), r, helper.schema)); } @Test public void checkReturnEmptyMapIfNoJavaFunctionsFound() throws ODataJPAModelException { - assertNotNull(cut.create(new JPAEdmNameBuilder(PUNIT_NAME), reflections, helper.schema)); + assertNotNull(cut.create(new JPADefaultEdmNameBuilder(PUNIT_NAME), reflections, helper.schema)); } @Test public void checkReturnMapWithOneIfOneJavaFunctionsFound() throws ODataJPAModelException { javaFunctions.add(ExampleJavaOneFunction.class); - Map act = cut.create(new JPAEdmNameBuilder(PUNIT_NAME), + Map act = cut.create(new JPADefaultEdmNameBuilder(PUNIT_NAME), reflections, helper.schema); assertEquals(1, act.size()); } @@ -57,7 +57,7 @@ public void checkReturnMapWithOneIfOneJavaFunctionsFound() throws ODataJPAModelE @Test public void checkReturnMapWithTwoIfTwoJavaFunctionsFound() throws ODataJPAModelException { javaFunctions.add(ExampleJavaTwoFunctions.class); - Map act = cut.create(new JPAEdmNameBuilder(PUNIT_NAME), + Map act = cut.create(new JPADefaultEdmNameBuilder(PUNIT_NAME), reflections, helper.schema); assertEquals(2, act.size()); } @@ -66,7 +66,7 @@ public void checkReturnMapWithTwoIfTwoJavaFunctionsFound() throws ODataJPAModelE public void checkReturnMapWithWithJavaFunctionsFromTwoClassesFound() throws ODataJPAModelException { javaFunctions.add(ExampleJavaOneFunction.class); javaFunctions.add(ExampleJavaTwoFunctions.class); - Map act = cut.create(new JPAEdmNameBuilder(PUNIT_NAME), + Map act = cut.create(new JPADefaultEdmNameBuilder(PUNIT_NAME), reflections, helper.schema); assertEquals(3, act.size()); } diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateJavaAction.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateJavaAction.java index 0f9ccf9c8..e5d8f20ce 100644 --- a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateJavaAction.java +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateJavaAction.java @@ -1,19 +1,23 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.lang.reflect.Method; +import java.lang.reflect.Parameter; import java.util.Arrays; +import java.util.List; import org.apache.olingo.commons.api.edm.geo.Geospatial.Dimension; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmAction; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAParameter; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.ODataAction; import com.sap.olingo.jpa.metadata.core.edm.mapper.testobjects.ExampleJavaActions; @@ -24,7 +28,7 @@ public class TestIntermediateJavaAction extends TestMappingRoot { private TestHelper helper; - @Before + @BeforeEach public void setup() throws ODataJPAModelException { helper = new TestHelper(emf.getMetamodel(), PUNIT_NAME); } @@ -85,6 +89,8 @@ public void checkReturnsGivenEntitySetTypeIfBound() throws ODataJPAModelExceptio assertTrue(act.getEdmItem().isBound()); assertEquals(PUNIT_NAME + ".Person", act.getEdmItem().getParameters().get(0).getTypeFQN() .getFullQualifiedNameAsString()); + assertEquals("Edm.Decimal", act.getEdmItem().getParameters().get(1).getTypeFQN() + .getFullQualifiedNameAsString()); } @Test @@ -140,6 +146,13 @@ public void checkReturnsEntityTypeAsReturnType() throws ODataJPAModelException { assertEquals("com.sap.olingo.jpa.Person", act.getEdmItem().getReturnType().getType()); } + @Test + public void checkReturnsEnumerationTypeAsReturnType() throws ODataJPAModelException { + IntermediateJavaAction act = createAction(ExampleJavaActions.class, "returnEnumeration"); + + assertEquals("com.sap.olingo.jpa.ABCClassifiaction", act.getEdmItem().getReturnType().getType()); + } + @Test public void checkReturnsReturnTypeCollectionOfPrimitive() throws ODataJPAModelException { IntermediateJavaAction act = createAction(ExampleJavaActions.class, "returnCollection"); @@ -233,6 +246,34 @@ public void checkReturnsParameterFacetForStringsAndGeo() throws ODataJPAModelExc assertEquals("4326", act.getEdmItem().getParameters().get(0).getSrid().toString()); } + @Test + public void checkReturnsEnumerationTypeAsParameter() throws ODataJPAModelException { + IntermediateJavaAction act = createAction(ExampleJavaActions.class, "returnEnumeration"); + + assertEquals("com.sap.olingo.jpa.AccessRights", act.getEdmItem().getParameters().get(0).getTypeFQN() + .getFullQualifiedNameAsString()); + } + + @Test + public void checkProvidesAllParameter() throws ODataJPAModelException { + IntermediateJavaAction act = createAction(ExampleJavaActions.class, "unboundWithImport"); + List actParams = act.getParameter(); + assertEquals(2, actParams.size()); + } + + @Test + public void checkProvidesParameterByDeclaired() throws ODataJPAModelException, NoSuchMethodException, + SecurityException { + + Method m = ExampleJavaActions.class.getMethod("unboundWithImport", short.class, int.class); + Parameter[] params = m.getParameters(); + IntermediateJavaAction act = createAction(ExampleJavaActions.class, "unboundWithImport"); + assertNotNull(act.getParameter(params[0])); + assertEquals("A", act.getParameter(params[0]).getName()); + assertNotNull(act.getParameter(params[1])); + assertEquals("B", act.getParameter(params[1]).getName()); + } + @Test public void checkExceptConstructorWithoutParameter() throws ODataJPAModelException { IntermediateJavaAction act = createAction(ExampleJavaActions.class, "unboundWithImport"); @@ -248,58 +289,74 @@ public void checkExceptConstructorWithEntityManagerParameter() throws ODataJPAMo assertEquals(1, act.getConstructor().getParameterTypes().length); } - @Test(expected = ODataJPAModelException.class) + @Test public void checkThrowsExcpetionForNonPrimitiveParameter() throws ODataJPAModelException { IntermediateJavaAction act = createAction(ExampleJavaActions.class, "errorNonPrimitiveParameter"); - act.getEdmItem(); + assertThrows(ODataJPAModelException.class, () -> { + act.getEdmItem(); + }); } - @Test(expected = ODataJPAModelException.class) + @Test public void checkThrowsExceptionIfCollectionAndReturnTypeEmpty() throws ODataJPAModelException { IntermediateJavaAction act = createAction(ExampleJavaActions.class, "returnCollectionWithoutReturnType"); - act.getEdmItem(); + assertThrows(ODataJPAModelException.class, () -> { + act.getEdmItem(); + }); } - @Test(expected = ODataJPAModelException.class) + @Test public void checkThrowsExcpetionOnPrivateConstructor() throws ODataJPAModelException { - IntermediateJavaAction act = createAction(ExampleJavaPrivateConstructor.class, "mul"); - act.getEdmItem(); + assertThrows(ODataJPAModelException.class, () -> { + createAction(ExampleJavaPrivateConstructor.class, "mul"); + }); } - @Test(expected = ODataJPAModelException.class) + @Test public void checkThrowsExcpetionOnNoConstructorAsSpecified() throws ODataJPAModelException { - IntermediateJavaAction act = createAction(ExampleJavaTwoParameterConstructor.class, "mul"); - act.getEdmItem(); + assertThrows(ODataJPAModelException.class, () -> { + createAction(ExampleJavaTwoParameterConstructor.class, "mul"); + }); } - @Test(expected = ODataJPAModelException.class) + @Test public void checkThrowsExcpetionOnIsBoundWithoutEntityTypeParameter() throws ODataJPAModelException { IntermediateJavaAction act = createAction(ExampleJavaActions.class, "boundWithOutBindingParameter"); - act.getEdmItem(); + assertThrows(ODataJPAModelException.class, () -> { + act.getEdmItem(); + }); } - @Test(expected = ODataJPAModelException.class) + @Test public void checkThrowsExcpetionOnIsBoundWithoutParameter() throws ODataJPAModelException { IntermediateJavaAction act = createAction(ExampleJavaActions.class, "boundWithOutParameter"); - act.getEdmItem(); + assertThrows(ODataJPAModelException.class, () -> { + act.getEdmItem(); + }); } - @Test(expected = ODataJPAModelException.class) + @Test public void checkThrowsExcpetionOnIsBoundBindingParameterNotFirst() throws ODataJPAModelException { IntermediateJavaAction act = createAction(ExampleJavaActions.class, "boundBindingParameterSecondParameter"); - act.getEdmItem(); + assertThrows(ODataJPAModelException.class, () -> { + act.getEdmItem(); + }); } - @Test(expected = ODataJPAModelException.class) + @Test public void checkThrowsExcpetionOnEntitySetGivenUnbound() throws ODataJPAModelException { IntermediateJavaAction act = createAction(ExampleJavaActions.class, "errorUnboundWithEntitySetPath"); - act.getEdmItem(); + assertThrows(ODataJPAModelException.class, () -> { + act.getEdmItem(); + }); } - @Test(expected = ODataJPAModelException.class) + @Test public void checkThrowsExcpetionOnEntitySetGivenNoEntityReturnType() throws ODataJPAModelException { IntermediateJavaAction act = createAction(ExampleJavaActions.class, "errorPrimitiveTypeWithEntitySetPath"); - act.getEdmItem(); + assertThrows(ODataJPAModelException.class, () -> { + act.getEdmItem(); + }); } private IntermediateJavaAction createAction(Class clazz, String method) @@ -307,7 +364,7 @@ private IntermediateJavaAction createAction(Class clazz, for (Method m : Arrays.asList(clazz.getMethods())) { EdmAction actionDescribtion = m.getAnnotation(EdmAction.class); if (actionDescribtion != null && method.equals(m.getName())) { - return new IntermediateJavaAction(new JPAEdmNameBuilder(PUNIT_NAME), actionDescribtion, m, helper.schema); + return new IntermediateJavaAction(new JPADefaultEdmNameBuilder(PUNIT_NAME), actionDescribtion, m, helper.schema); } } return null; diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateJavaFunction.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateJavaFunction.java index 0c5a3088d..6dc9a0e23 100644 --- a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateJavaFunction.java +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateJavaFunction.java @@ -1,18 +1,20 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.lang.reflect.Method; import java.util.Arrays; import org.apache.olingo.commons.api.edm.geo.Geospatial.Dimension; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmFunction; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAParameter; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.ODataFunction; import com.sap.olingo.jpa.metadata.core.edm.mapper.testobjects.ExampleJavaEmConstructor; @@ -24,7 +26,7 @@ public class TestIntermediateJavaFunction extends TestMappingRoot { private TestHelper helper; - @Before + @BeforeEach public void setup() throws ODataJPAModelException { helper = new TestHelper(emf.getMetamodel(), PUNIT_NAME); } @@ -45,7 +47,7 @@ public void checkExternalNameEqualMethodName() throws ODataJPAModelException { @Test public void checkReturnsConvertedPrimitiveReturnType() throws ODataJPAModelException { - IntermediateJavaFunction act = createFunction(ExampleJavaOneFunction.class, "sum"); + final IntermediateJavaFunction act = createFunction(ExampleJavaOneFunction.class, "sum"); assertNotNull(act.getEdmItem()); assertNotNull(act.getEdmItem().getReturnType()); @@ -54,7 +56,7 @@ public void checkReturnsConvertedPrimitiveReturnType() throws ODataJPAModelExcep @Test public void checkReturnsConvertedPrimitiveParameterTypes() throws ODataJPAModelException { - IntermediateJavaFunction act = createFunction(ExampleJavaOneFunction.class, "sum"); + final IntermediateJavaFunction act = createFunction(ExampleJavaOneFunction.class, "sum"); assertNotNull(act.getEdmItem()); assertNotNull(act.getEdmItem().getParameters()); @@ -65,15 +67,18 @@ public void checkReturnsConvertedPrimitiveParameterTypes() throws ODataJPAModelE assertEquals("Edm.Int32", act.getEdmItem().getParameter("B").getType()); } - @Test(expected = ODataJPAModelException.class) + @Test public void checkThrowsExcpetionForNonPrimitiveParameter() throws ODataJPAModelException { - IntermediateJavaFunction act = createFunction(ExampleJavaFunctions.class, "errorNonPrimitiveParameter"); - act.getEdmItem(); + final IntermediateJavaFunction act = createFunction(ExampleJavaFunctions.class, "errorNonPrimitiveParameter"); + + assertThrows(ODataJPAModelException.class, () -> { + act.getEdmItem(); + }); } @Test public void checkReturnsFalseForIsBound() throws ODataJPAModelException { - IntermediateJavaFunction act = createFunction(ExampleJavaOneFunction.class, "sum"); + final IntermediateJavaFunction act = createFunction(ExampleJavaOneFunction.class, "sum"); assertNotNull(act.getEdmItem()); assertEquals(false, act.getEdmItem().isBound()); @@ -81,21 +86,21 @@ public void checkReturnsFalseForIsBound() throws ODataJPAModelException { @Test public void checkReturnsTrueForHasFunctionImport() throws ODataJPAModelException { - IntermediateJavaFunction act = createFunction(ExampleJavaOneFunction.class, "sum"); + final IntermediateJavaFunction act = createFunction(ExampleJavaOneFunction.class, "sum"); assertTrue(act.hasImport()); } @Test public void checkReturnsAnnotatedName() throws ODataJPAModelException { - IntermediateJavaFunction act = createFunction(ExampleJavaFunctions.class, "sum"); + final IntermediateJavaFunction act = createFunction(ExampleJavaFunctions.class, "sum"); assertEquals("Add", act.getExternalName()); } @Test public void checkIgnoresGivenIsBound() throws ODataJPAModelException { - IntermediateJavaFunction act = createFunction(ExampleJavaFunctions.class, "sum"); + final IntermediateJavaFunction act = createFunction(ExampleJavaFunctions.class, "sum"); assertFalse(act.getEdmItem().isBound()); assertFalse(act.isBound()); @@ -103,14 +108,27 @@ public void checkIgnoresGivenIsBound() throws ODataJPAModelException { @Test public void checkIgnoresGivenHasFunctionImport() throws ODataJPAModelException { - IntermediateJavaFunction act = createFunction(ExampleJavaFunctions.class, "sum"); + final IntermediateJavaFunction act = createFunction(ExampleJavaFunctions.class, "sum"); assertTrue(act.hasImport()); } + @Test + public void checkReturnsEnumerationTypeAsParameter() throws ODataJPAModelException { + final IntermediateJavaFunction act = createFunction(ExampleJavaFunctions.class, "returnEnumerationType"); + + assertEquals("com.sap.olingo.jpa.AccessRights", act.getEdmItem().getParameters().get(0).getTypeFQN() + .getFullQualifiedNameAsString()); + JPAParameter param = act.getParameter("arg0"); + if (param == null) + param = act.getParameter("rights"); + assertNotNull(param); + assertEquals("com.sap.olingo.jpa.AccessRights", param.getTypeFQN().getFullQualifiedNameAsString()); + } + @Test public void checkIgnoresParameterAsPartFromEdmFunction() throws ODataJPAModelException { - IntermediateJavaFunction act = createFunction(ExampleJavaFunctions.class, "div"); + final IntermediateJavaFunction act = createFunction(ExampleJavaFunctions.class, "div"); assertNotNull(act.getEdmItem()); assertEquals(2, act.getEdmItem().getParameters().size()); @@ -118,15 +136,17 @@ public void checkIgnoresParameterAsPartFromEdmFunction() throws ODataJPAModelExc assertNotNull(act.getEdmItem().getParameter("B")); } - @Test(expected = ODataJPAModelException.class) + @Test public void checkThrowsExceptionIfAnnotatedReturnTypeNEDeclairedType() throws ODataJPAModelException { - IntermediateJavaFunction act = createFunction(ExampleJavaFunctions.class, "errorReturnType"); - act.getEdmItem(); + final IntermediateJavaFunction act = createFunction(ExampleJavaFunctions.class, "errorReturnType"); + assertThrows(ODataJPAModelException.class, () -> { + act.getEdmItem(); + }); } @Test public void checkReturnsFacetForNumbersOfReturnType() throws ODataJPAModelException { - IntermediateJavaFunction act = createFunction(ExampleJavaFunctions.class, "now"); + final IntermediateJavaFunction act = createFunction(ExampleJavaFunctions.class, "now"); assertFalse(act.getEdmItem().getReturnType().isNullable()); assertEquals(Integer.valueOf(9), act.getEdmItem().getReturnType().getPrecision()); assertEquals(Integer.valueOf(3), act.getEdmItem().getReturnType().getScale()); @@ -134,7 +154,7 @@ public void checkReturnsFacetForNumbersOfReturnType() throws ODataJPAModelExcept @Test public void checkReturnsFacetForStringsAndGeoOfReturnType() throws ODataJPAModelException { - IntermediateJavaFunction act = createFunction(ExampleJavaFunctions.class, "determineLocation"); + final IntermediateJavaFunction act = createFunction(ExampleJavaFunctions.class, "determineLocation"); assertEquals(Integer.valueOf(60), act.getEdmItem().getReturnType().getMaxLength()); assertEquals(Dimension.GEOGRAPHY, act.getEdmItem().getReturnType().getSrid().getDimension()); assertEquals("4326", act.getEdmItem().getReturnType().getSrid().toString()); @@ -142,28 +162,31 @@ public void checkReturnsFacetForStringsAndGeoOfReturnType() throws ODataJPAModel @Test public void checkReturnsIsCollectionIfDefinedReturnTypeIsSubclassOfCollection() throws ODataJPAModelException { - IntermediateJavaFunction act = createFunction(ExampleJavaFunctions.class, "returnCollection"); + final IntermediateJavaFunction act = createFunction(ExampleJavaFunctions.class, "returnCollection"); assertTrue(act.getEdmItem().getReturnType().isCollection()); assertEquals("Edm.String", act.getEdmItem().getReturnType().getType()); } - @Test(expected = ODataJPAModelException.class) + @Test public void checkThrowsExceptionIfCollectionAndReturnTypeEmpty() throws ODataJPAModelException { - IntermediateJavaFunction act = createFunction(ExampleJavaFunctions.class, "returnCollectionWithoutReturnType"); - act.getEdmItem(); + final IntermediateJavaFunction act = createFunction(ExampleJavaFunctions.class, + "returnCollectionWithoutReturnType"); + assertThrows(ODataJPAModelException.class, () -> { + act.getEdmItem(); + }); } @Test public void checkReturnsEmbeddableTypeAsReturnType() throws ODataJPAModelException { - IntermediateJavaFunction act = createFunction(ExampleJavaFunctions.class, "returnEmbeddable"); + final IntermediateJavaFunction act = createFunction(ExampleJavaFunctions.class, "returnEmbeddable"); assertEquals("com.sap.olingo.jpa.ChangeInformation", act.getEdmItem().getReturnType().getType()); } @Test public void checkReturnsEmbeddableCollectionTypeAsReturnType() throws ODataJPAModelException { - IntermediateJavaFunction act = createFunction(ExampleJavaFunctions.class, "returnEmbeddableCollection"); + final IntermediateJavaFunction act = createFunction(ExampleJavaFunctions.class, "returnEmbeddableCollection"); assertEquals("com.sap.olingo.jpa.ChangeInformation", act.getEdmItem().getReturnType().getType()); assertTrue(act.getEdmItem().getReturnType().isCollection()); @@ -171,38 +194,57 @@ public void checkReturnsEmbeddableCollectionTypeAsReturnType() throws ODataJPAMo @Test public void checkReturnsEntityTypeAsReturnType() throws ODataJPAModelException { - IntermediateJavaFunction act = createFunction(ExampleJavaFunctions.class, "returnEntity"); + final IntermediateJavaFunction act = createFunction(ExampleJavaFunctions.class, "returnEntity"); assertEquals("com.sap.olingo.jpa.Person", act.getEdmItem().getReturnType().getType()); } - @Test(expected = ODataJPAModelException.class) + @Test + public void checkReturnsEnumerationTypeAsReturnType() throws ODataJPAModelException { + + final IntermediateJavaFunction act = createFunction(ExampleJavaFunctions.class, "returnEnumerationType"); + assertEquals("com.sap.olingo.jpa.ABCClassifiaction", act.getEdmItem().getReturnType().getType()); + } + + @Test + public void checkReturnsEnumerationCollectionTypeAsReturnType() throws ODataJPAModelException { + final IntermediateJavaFunction act = createFunction(ExampleJavaFunctions.class, "returnEnumerationCollection"); + + assertEquals("com.sap.olingo.jpa.ABCClassifiaction", act.getEdmItem().getReturnType().getType()); + assertTrue(act.getEdmItem().getReturnType().isCollection()); + } + + @Test public void checkThrowsExcpetionOnNotSupportedReturnType() throws ODataJPAModelException { - IntermediateJavaFunction act = createFunction(ExampleJavaFunctions.class, "wrongReturnType"); - act.getEdmItem(); + final IntermediateJavaFunction act = createFunction(ExampleJavaFunctions.class, "wrongReturnType"); + assertThrows(ODataJPAModelException.class, () -> { + act.getEdmItem(); + }); } @Test public void checkExceptConstructorWithoutParameter() throws ODataJPAModelException { - IntermediateJavaFunction act = createFunction(ExampleJavaFunctions.class, "sum"); + final IntermediateJavaFunction act = createFunction(ExampleJavaFunctions.class, "sum"); act.getEdmItem(); } @Test public void checkExceptConstructorWithEntityManagerParameter() throws ODataJPAModelException { - IntermediateJavaFunction act = createFunction(ExampleJavaEmConstructor.class, "sum"); + final IntermediateJavaFunction act = createFunction(ExampleJavaEmConstructor.class, "sum"); act.getEdmItem(); } - @Test(expected = ODataJPAModelException.class) + @Test public void checkThrowsExcpetionOnPrivateConstructor() throws ODataJPAModelException { - IntermediateJavaFunction act = createFunction(ExampleJavaPrivateConstructor.class, "sum"); - act.getEdmItem(); + assertThrows(ODataJPAModelException.class, () -> { + createFunction(ExampleJavaPrivateConstructor.class, "sum"); + }); } - @Test(expected = ODataJPAModelException.class) + @Test public void checkThrowsExcpetionOnNoConstructorAsSpecified() throws ODataJPAModelException { - IntermediateJavaFunction act = createFunction(ExampleJavaTwoParameterConstructor.class, "sum"); - act.getEdmItem(); + assertThrows(ODataJPAModelException.class, () -> { + createFunction(ExampleJavaTwoParameterConstructor.class, "sum"); + }); } private IntermediateJavaFunction createFunction(Class clazz, String method) @@ -210,7 +252,8 @@ private IntermediateJavaFunction createFunction(Class c for (Method m : Arrays.asList(clazz.getMethods())) { EdmFunction functionDescribtion = m.getAnnotation(EdmFunction.class); if (functionDescribtion != null && method.equals(m.getName())) { - return new IntermediateJavaFunction(new JPAEdmNameBuilder(PUNIT_NAME), functionDescribtion, m, helper.schema); + return new IntermediateJavaFunction(new JPADefaultEdmNameBuilder(PUNIT_NAME), functionDescribtion, m, + helper.schema); } } return null; diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateModelElement.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateModelElement.java new file mode 100644 index 000000000..c7ad0311a --- /dev/null +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateModelElement.java @@ -0,0 +1,82 @@ +package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.params.provider.Arguments.arguments; + +import java.util.HashMap; +import java.util.stream.Stream; + +import org.apache.olingo.commons.api.edm.provider.CsdlAbstractEdmItem; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; + +public class TestIntermediateModelElement { + private IntermediateModelElementTest cut; + + static Stream boxPrimitive() { + return Stream.of( + arguments(int.class, Integer.class), + arguments(Integer.class, Integer.class), + arguments(long.class, Long.class), + arguments(Long.class, Long.class), + arguments(short.class, Short.class), + arguments(Short.class, Short.class), + arguments(float.class, Float.class), + arguments(Float.class, Float.class), + arguments(double.class, Double.class), + arguments(Double.class, Double.class), + arguments(byte.class, Byte.class), + arguments(Byte.class, Byte.class), + arguments(boolean.class, Boolean.class), + arguments(Boolean.class, Boolean.class), + arguments(char.class, Character.class), + arguments(Character.class, Character.class)); + } + + @BeforeEach + public void setup() { + cut = new IntermediateModelElementTest(new JPADefaultEdmNameBuilder("Dummy"), "Test"); + } + + @ParameterizedTest + @MethodSource("boxPrimitive") + public void checkBoxPrimitive(final Class type, final Class result) { + assertEquals(result, cut.boxPrimitive(type)); + } + + @Test + public void checkToString() { + assertTrue(cut.toString().contains("Test")); + } + + @Test + public void checkFindModelElementByEdmItemReturnsNull() { + assertNull(cut.findModelElementByEdmItem("Willi", new HashMap<>())); + } + + private class IntermediateModelElementTest extends IntermediateModelElement { + + public IntermediateModelElementTest(JPADefaultEdmNameBuilder nameBuilder, String internalName) { + super(nameBuilder, internalName); + } + + @Override + protected void lazyBuildEdmItem() throws ODataJPAModelException { + // TODO Auto-generated method stub + + } + + @Override + CsdlAbstractEdmItem getEdmItem() throws ODataJPAModelException { + return null; + } + + } +} diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateNavigationProperty.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateNavigationProperty.java index f16352924..eebde79dc 100644 --- a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateNavigationProperty.java +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateNavigationProperty.java @@ -1,95 +1,125 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.withSettings; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Member; +import java.util.Arrays; +import java.util.HashSet; import java.util.List; import javax.persistence.metamodel.Attribute; import javax.persistence.metamodel.EmbeddableType; import javax.persistence.metamodel.EntityType; +import javax.persistence.metamodel.ManagedType; import org.apache.olingo.commons.api.edm.provider.CsdlOnDelete; import org.apache.olingo.commons.api.edm.provider.CsdlOnDeleteAction; import org.apache.olingo.commons.api.edm.provider.CsdlReferentialConstraint; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; import org.reflections.Reflections; import com.sap.olingo.jpa.metadata.api.JPAEdmMetadataPostProcessor; +import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmEnumeration; +import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmProtectedBy; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAAssociationAttribute; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAAssociationPath; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAOnConditionItem; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediateEntityTypeAccess; import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediateNavigationPropertyAccess; import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediatePropertyAccess; import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediateReferenceList; +import com.sap.olingo.jpa.processor.core.testmodel.ABCClassifiaction; import com.sap.olingo.jpa.processor.core.testmodel.AdministrativeDivision; import com.sap.olingo.jpa.processor.core.testmodel.BusinessPartner; import com.sap.olingo.jpa.processor.core.testmodel.BusinessPartnerRole; +import com.sap.olingo.jpa.processor.core.testmodel.DummyToBeIgnored; +import com.sap.olingo.jpa.processor.core.testmodel.JoinSource; +import com.sap.olingo.jpa.processor.core.testmodel.Organization; +import com.sap.olingo.jpa.processor.core.testmodel.Person; public class TestIntermediateNavigationProperty extends TestMappingRoot { private IntermediateSchema schema; private TestHelper helper; private JPAEdmMetadataPostProcessor processor; - @Before + @BeforeEach public void setup() throws ODataJPAModelException { - schema = new IntermediateSchema(new JPAEdmNameBuilder(PUNIT_NAME), emf.getMetamodel(), mock(Reflections.class)); + final Reflections r = mock(Reflections.class); + when(r.getTypesAnnotatedWith(EdmEnumeration.class)).thenReturn(new HashSet<>(Arrays.asList(new Class[] { + ABCClassifiaction.class }))); + + schema = new IntermediateSchema(new JPADefaultEdmNameBuilder(PUNIT_NAME), emf.getMetamodel(), r); helper = new TestHelper(emf.getMetamodel(), PUNIT_NAME); processor = mock(JPAEdmMetadataPostProcessor.class); } @Test public void checkNaviProptertyCanBeCreated() throws ODataJPAModelException { - EntityType et = helper.getEntityType("BusinessPartner"); - Attribute jpaAttribute = helper.getDeclaredAttribute(et, "roles"); - new IntermediateNavigationProperty(new JPAEdmNameBuilder(PUNIT_NAME), schema.getStructuredType(jpaAttribute), - jpaAttribute, schema); + final EntityType et = helper.getEntityType(BusinessPartner.class); + final Attribute jpaAttribute = helper.getDeclaredAttribute(et, "roles"); + final JPAAssociationAttribute act = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), + schema.getStructuredType(jpaAttribute), jpaAttribute, schema); + assertNotNull(act); } @Test public void checkGetName() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType("BusinessPartner"), "roles"); - IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPAEdmNameBuilder(PUNIT_NAME), + Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType(BusinessPartner.class), "roles"); + IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(BusinessPartner.class), jpaAttribute, schema); - assertEquals("Wrong name", "Roles", property.getEdmItem().getName()); + assertEquals("Roles", property.getEdmItem().getName(), "Wrong name"); } @Test - public void checkGetType() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType("BusinessPartner"), "roles"); - IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPAEdmNameBuilder(PUNIT_NAME), + public void checkGetEdmType() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType(BusinessPartner.class), "roles"); + IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(BusinessPartner.class), jpaAttribute, schema); - assertEquals("Wrong name", PUNIT_NAME + ".BusinessPartnerRole", property.getEdmItem().getType()); + assertEquals(PUNIT_NAME + ".BusinessPartnerRole", property.getEdmItem().getType(), "Wrong name"); } @Test public void checkGetIgnoreFalse() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType("BusinessPartner"), "roles"); - IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPAEdmNameBuilder(PUNIT_NAME), + Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType(BusinessPartner.class), "roles"); + IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getStructuredType(jpaAttribute), jpaAttribute, schema); assertFalse(property.ignore()); } @Test public void checkGetIgnoreTrue() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType("DummyToBeIgnored"), + Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType(DummyToBeIgnored.class), "businessPartner"); - IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPAEdmNameBuilder(PUNIT_NAME), + IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getStructuredType(jpaAttribute), jpaAttribute, schema); assertTrue(property.ignore()); } @Test public void checkGetProptertyFacetsNullableTrue() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType("BusinessPartner"), "roles"); - IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPAEdmNameBuilder(PUNIT_NAME), + Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType(BusinessPartner.class), "roles"); + IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(BusinessPartner.class), jpaAttribute, schema); assertTrue(property.getEdmItem().isNullable()); @@ -97,8 +127,9 @@ public void checkGetProptertyFacetsNullableTrue() throws ODataJPAModelException @Test public void checkGetPropertyOnDelete() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType("BusinessPartner"), "roles"); - IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPAEdmNameBuilder(PUNIT_NAME), + Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType(BusinessPartner.class), "roles"); + IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(BusinessPartner.class), jpaAttribute, schema); assertEquals(CsdlOnDeleteAction.Cascade, property.getEdmItem().getOnDelete().getAction()); @@ -106,9 +137,10 @@ public void checkGetPropertyOnDelete() throws ODataJPAModelException { @Test public void checkGetProptertyFacetsNullableFalse() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType("BusinessPartnerRole"), + Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType(BusinessPartnerRole.class), "businessPartner"); - IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPAEdmNameBuilder(PUNIT_NAME), + IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(BusinessPartnerRole.class), jpaAttribute, schema); assertFalse(property.getEdmItem().isNullable()); @@ -116,8 +148,9 @@ public void checkGetProptertyFacetsNullableFalse() throws ODataJPAModelException @Test public void checkGetProptertyFacetsCollectionTrue() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType("BusinessPartner"), "roles"); - IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPAEdmNameBuilder(PUNIT_NAME), + Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType(BusinessPartner.class), "roles"); + IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(BusinessPartner.class), jpaAttribute, schema); assertTrue(property.getEdmItem().isNullable()); @@ -125,70 +158,86 @@ public void checkGetProptertyFacetsCollectionTrue() throws ODataJPAModelExceptio @Test public void checkGetProptertyFacetsColletionFalse() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType("BusinessPartnerRole"), + Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType(BusinessPartnerRole.class), "businessPartner"); - IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPAEdmNameBuilder(PUNIT_NAME), - schema.getEntityType(BusinessPartnerRole.class), jpaAttribute, schema); + IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(BusinessPartnerRole.class), jpaAttribute, schema); + + assertFalse(property.getEdmItem().isCollection()); + } + + @Test + public void checkGetProptertyFacetsColletionFalseOnToOne() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType(Person.class), + "image"); + IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(Person.class), jpaAttribute, schema); assertFalse(property.getEdmItem().isCollection()); } @Test public void checkGetJoinColumnsSize1BP() throws ODataJPAModelException { - EntityType et = helper.getEntityType("BusinessPartner"); + EntityType et = helper.getEntityType(BusinessPartner.class); Attribute jpaAttribute = helper.getDeclaredAttribute(et, "roles"); - IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPAEdmNameBuilder(PUNIT_NAME), + IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(et.getJavaType()), jpaAttribute, schema); assertEquals(1, property.getJoinColumns().size()); } @Test public void checkGetPartnerAdmin_Parent() throws ODataJPAModelException { - EntityType et = helper.getEntityType("AdministrativeDivision"); + EntityType et = helper.getEntityType(AdministrativeDivision.class); Attribute jpaAttribute = helper.getDeclaredAttribute(et, "parent"); - IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPAEdmNameBuilder(PUNIT_NAME), + IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(et.getJavaType()), jpaAttribute, schema); assertEquals("Children", property.getEdmItem().getPartner()); } @Test public void checkGetPartnerAdmin_Children() throws ODataJPAModelException { - EntityType et = helper.getEntityType("AdministrativeDivision"); + EntityType et = helper.getEntityType(AdministrativeDivision.class); Attribute jpaAttribute = helper.getDeclaredAttribute(et, "children"); - IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPAEdmNameBuilder(PUNIT_NAME), + IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(et.getJavaType()), jpaAttribute, schema); assertEquals("Parent", property.getEdmItem().getPartner()); } @Test public void checkGetPartnerBP_Roles() throws ODataJPAModelException { - EntityType et = helper.getEntityType("BusinessPartner"); + EntityType et = helper.getEntityType(BusinessPartner.class); Attribute jpaAttribute = helper.getDeclaredAttribute(et, "roles"); - IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPAEdmNameBuilder(PUNIT_NAME), + IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(et.getJavaType()), jpaAttribute, schema); assertEquals("BusinessPartner", property.getEdmItem().getPartner()); } @Test public void checkGetPartnerRole_BP() throws ODataJPAModelException { - EntityType et = helper.getEntityType("BusinessPartnerRole"); + EntityType et = helper.getEntityType(BusinessPartnerRole.class); Attribute jpaAttribute = helper.getDeclaredAttribute(et, "businessPartner"); - IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPAEdmNameBuilder(PUNIT_NAME), + IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(et.getJavaType()), jpaAttribute, schema); assertEquals("Roles", property.getEdmItem().getPartner()); } @Test public void checkGetJoinColumnFilledCompletely() throws ODataJPAModelException { - EntityType et = helper.getEntityType("BusinessPartner"); + EntityType et = helper.getEntityType(BusinessPartner.class); Attribute jpaAttribute = helper.getDeclaredAttribute(et, "roles"); - IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPAEdmNameBuilder(PUNIT_NAME), + IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(et.getJavaType()), jpaAttribute, schema); IntermediateJoinColumn act = property.getJoinColumns().get(0); @@ -198,10 +247,11 @@ public void checkGetJoinColumnFilledCompletely() throws ODataJPAModelException { @Test public void checkGetJoinColumnFilledCompletelyInvert() throws ODataJPAModelException { - EntityType et = helper.getEntityType("BusinessPartnerRole"); + EntityType et = helper.getEntityType(BusinessPartnerRole.class); Attribute jpaAttribute = helper.getDeclaredAttribute(et, "businessPartner"); - IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPAEdmNameBuilder(PUNIT_NAME), + IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(et.getJavaType()), jpaAttribute, schema); IntermediateJoinColumn act = property.getJoinColumns().get(0); @@ -211,10 +261,11 @@ public void checkGetJoinColumnFilledCompletelyInvert() throws ODataJPAModelExcep @Test public void checkGetJoinColumnsSize1Roles() throws ODataJPAModelException { - EntityType et = helper.getEntityType("BusinessPartnerRole"); + EntityType et = helper.getEntityType(BusinessPartnerRole.class); Attribute jpaAttribute = helper.getDeclaredAttribute(et, "businessPartner"); - IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPAEdmNameBuilder(PUNIT_NAME), + IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(et.getJavaType()), jpaAttribute, schema); assertEquals(1, property.getJoinColumns().size()); } @@ -223,7 +274,8 @@ public void checkGetJoinColumnsSize1Roles() throws ODataJPAModelException { public void checkGetJoinColumnsSize2() throws ODataJPAModelException { EmbeddableType et = helper.getEmbeddedableType("PostalAddressData"); Attribute jpaAttribute = helper.getDeclaredAttribute(et, "administrativeDivision"); - IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPAEdmNameBuilder(PUNIT_NAME), + IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getComplexType(et.getJavaType()), jpaAttribute, schema); List columns = property.getJoinColumns(); assertEquals(3, columns.size()); @@ -231,16 +283,18 @@ public void checkGetJoinColumnsSize2() throws ODataJPAModelException { @Test public void checkGetReferentialConstraintSize() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType("BusinessPartner"), "roles"); - IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPAEdmNameBuilder(PUNIT_NAME), + Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType(BusinessPartner.class), "roles"); + IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(BusinessPartner.class), jpaAttribute, schema); assertEquals(1, property.getProperty().getReferentialConstraints().size()); } @Test public void checkGetReferentialConstraintBuPaRole() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType("BusinessPartner"), "roles"); - IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPAEdmNameBuilder(PUNIT_NAME), + Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType(BusinessPartner.class), "roles"); + IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(BusinessPartner.class), jpaAttribute, schema); List constraints = property.getProperty().getReferentialConstraints(); @@ -252,9 +306,10 @@ public void checkGetReferentialConstraintBuPaRole() throws ODataJPAModelExceptio @Test public void checkGetReferentialConstraintRoleBuPa() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType("BusinessPartnerRole"), + Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType(BusinessPartnerRole.class), "businessPartner"); - IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPAEdmNameBuilder(PUNIT_NAME), + IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(BusinessPartnerRole.class), jpaAttribute, schema); List constraints = property.getProperty().getReferentialConstraints(); @@ -266,9 +321,10 @@ public void checkGetReferentialConstraintRoleBuPa() throws ODataJPAModelExceptio @Test public void checkGetReferentialConstraintViaEmbeddedId() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType("AdministrativeDivision"), + Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType(AdministrativeDivision.class), "allDescriptions"); - IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPAEdmNameBuilder(PUNIT_NAME), + IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(AdministrativeDivision.class), jpaAttribute, schema); List constraints = property.getProperty().getReferentialConstraints(); @@ -283,8 +339,9 @@ public void checkPostProcessorCalled() throws ODataJPAModelException { IntermediateModelElement.setPostProcessor(processor); Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType( - "BusinessPartner"), "roles"); - IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPAEdmNameBuilder(PUNIT_NAME), + BusinessPartner.class), "roles"); + IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(BusinessPartner.class), jpaAttribute, schema); property.getEdmItem(); @@ -296,11 +353,12 @@ public void checkPostProcessorNameChanged() throws ODataJPAModelException { PostProcessorSetName pPDouble = new PostProcessorSetName(); IntermediateModelElement.setPostProcessor(pPDouble); - Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType("BusinessPartner"), "roles"); - IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPAEdmNameBuilder(PUNIT_NAME), + Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType(BusinessPartner.class), "roles"); + IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(BusinessPartner.class), jpaAttribute, schema); - assertEquals("Wrong name", "RoleAssignment", property.getEdmItem().getName()); + assertEquals("RoleAssignment", property.getEdmItem().getName(), "Wrong name"); } @Test @@ -308,11 +366,11 @@ public void checkPostProcessorExternalNameChanged() throws ODataJPAModelExceptio PostProcessorSetName pPDouble = new PostProcessorSetName(); IntermediateModelElement.setPostProcessor(pPDouble); - Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType("BusinessPartner"), "roles"); - JPAAssociationAttribute property = new IntermediateNavigationProperty(new JPAEdmNameBuilder(PUNIT_NAME), + Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType(BusinessPartner.class), "roles"); + JPAAssociationAttribute property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), schema.getStructuredType(jpaAttribute), jpaAttribute, schema); - assertEquals("Wrong name", "RoleAssignment", property.getExternalName()); + assertEquals("RoleAssignment", property.getExternalName(), "Wrong name"); } @Test @@ -320,14 +378,237 @@ public void checkPostProcessorSetOnDelete() throws ODataJPAModelException { PostProcessorOneDelete pPDouble = new PostProcessorOneDelete(); IntermediateModelElement.setPostProcessor(pPDouble); - Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType("AdministrativeDivision"), + Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType(AdministrativeDivision.class), "children"); - IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPAEdmNameBuilder(PUNIT_NAME), + IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(AdministrativeDivision.class), jpaAttribute, schema); assertEquals(CsdlOnDeleteAction.None, property.getProperty().getOnDelete().getAction()); } + @Test + public void checkGetJoinTable() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType(Person.class), + "supportedOrganizations"); + IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), + schema.getEntityType(BusinessPartner.class), jpaAttribute, schema); + + assertNotNull(property.getJoinTable()); + } + + @Test + public void checkGetJoinTableName() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType(Person.class), + "supportedOrganizations"); + IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), + schema.getEntityType(BusinessPartner.class), jpaAttribute, schema); + + assertEquals("\"OLINGO\".\"SupportRelationship\"", property.getJoinTable().getTableName()); + } + + @Test + public void checkGetNullIfNoJoinTableGiven() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType(AdministrativeDivision.class), + "parent"); + IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(BusinessPartner.class), jpaAttribute, schema); + + assertNull(property.getJoinTable()); + } + + @Test + public void checkGetJoinTableJoinColumns() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType(Person.class), + "supportedOrganizations"); + IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), + schema.getEntityType(BusinessPartner.class), jpaAttribute, schema); + + assertFalse(property.getJoinColumns().isEmpty()); + } + + @Test + public void checkGetJoinTableEntityType() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType(Person.class), + "supportedOrganizations"); + IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), + schema.getEntityType(BusinessPartner.class), jpaAttribute, schema); + + assertNotNull(property.getJoinTable().getEntityType()); + } + + @Test + public void checkGetJoinTableJoinColumnsNotMapped() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType(JoinSource.class), + "oneToMany"); + IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(JoinSource.class), jpaAttribute, schema); + + assertFalse(property.getJoinColumns().isEmpty()); + assertNotNull(property.getJoinTable()); + IntermediateJoinTable act = (IntermediateJoinTable) property.getJoinTable(); + for (JPAOnConditionItem item : act.getJoinColumns()) { + assertNotNull(item.getLeftPath()); + assertNotNull(item.getRightPath()); + } + } + + @Test + public void checkGetJoinTableJoinColumnsMapped() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType(Organization.class), + "supportEngineers"); + IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(BusinessPartner.class), jpaAttribute, schema); + + assertFalse(property.getJoinColumns().isEmpty()); + } + + @Test + public void checkGetJoinTableJoinColumnsMissingInvers() throws ODataJPAModelException { + final EmbeddableType jpaEmbeddedable = helper.getEmbeddedableType("JoinComplex"); + // helper.getEmbeddedableType(typeName) + final IntermediateComplexType property = new IntermediateComplexType(new JPADefaultEdmNameBuilder( + PUNIT_NAME), jpaEmbeddedable, schema); + final JPAAssociationAttribute assoziation = property.getAssociation("oneToManyComplex"); + final JPAAssociationPath path = assoziation.getPath(); + assertNotNull(path.getJoinTable()); + // assertNotNull(path.getInverseLeftJoinColumnsList()); + assertEquals(1, path.getJoinTable().getInversJoinColumns().size()); + assertNotNull(path.getJoinTable().getInversJoinColumns().get(0).getLeftPath()); + assertNotNull(path.getJoinTable().getInversJoinColumns().get(0).getRightPath()); + } + + @Test + public void checkGetConverterReturnsNull() throws ODataJPAModelException { + final IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(JoinSource.class), createDummyAttribute(), schema); + assertNull(property.getConverter()); + } + + @Test + public void checkGetEdmTypeReturnsNull() throws ODataJPAModelException { + final IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(JoinSource.class), createDummyAttribute(), schema); + assertNull(property.getEdmType()); + } + + @Test + public void checkHasProtectionReturnsFalse() throws ODataJPAModelException { + final IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(JoinSource.class), createDummyAttribute(), schema); + assertFalse(property.hasProtection()); + } + + @Test + public void checkIsAssocationReturnsTrue() throws ODataJPAModelException { + final IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(JoinSource.class), createDummyAttribute(), schema); + assertTrue(property.isAssociation()); + } + + @Test + public void checkIsComplexReturnsFalse() throws ODataJPAModelException { + final IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(JoinSource.class), createDummyAttribute(), schema); + assertFalse(property.isComplex()); + } + + @Test + public void checkIsEnumReturnsFalse() throws ODataJPAModelException { + final IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(JoinSource.class), createDummyAttribute(), schema); + assertFalse(property.isEnum()); + } + + @Test + public void checkIsKeyReturnsFalse() throws ODataJPAModelException { + final IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(JoinSource.class), createDummyAttribute(), schema); + assertFalse(property.isKey()); + } + + @Test + public void checkIsSearchableReturnsFalse() throws ODataJPAModelException { + final IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(JoinSource.class), createDummyAttribute(), schema); + assertFalse(property.isSearchable()); + } + + @Test + public void checkGetProtectionPathReturnsEmptyList() throws ODataJPAModelException { + final IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(JoinSource.class), createDummyAttribute(), schema); + assertTrue(property.getProtectionPath("Bla").isEmpty()); + } + + @Test + public void checkGetProtectionClaimNamesReturnsEmptySet() throws ODataJPAModelException { + final IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(JoinSource.class), createDummyAttribute(), schema); + assertTrue(property.getProtectionClaimNames().isEmpty()); + } + + @Test + public void checkGetType() throws ODataJPAModelException { + final IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(JoinSource.class), createDummyAttribute(), schema); + assertEquals(BusinessPartner.class, property.getType()); + } + + @Test + public void checkIsTransientIsFalse() throws ODataJPAModelException { + final IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(JoinSource.class), createDummyAttribute(), schema); + assertFalse(property.isTransient()); + } + + @Test + public void checkIsEtagIsFalse() throws ODataJPAModelException { + final IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder( + PUNIT_NAME), schema.getEntityType(JoinSource.class), createDummyAttribute(), schema); + assertFalse(property.isEtag()); + } + +// @Test +// public void checkSetAnnotations() throws ODataJPAModelException { +// final IntermediateNavigationProperty property = new IntermediateNavigationProperty(new JPAEdmNameBuilder( +// PUNIT_NAME), schema.getEntityType(JoinSource.class), createDummyAttribute(), schema); +// property.getAnnotations(edmAnnotations, member, internalName, property); +// } + + private Attribute createDummyAttribute() { + final Attribute jpaAttribute = mock(Attribute.class); + final ManagedType mgrType = mock(ManagedType.class); + final Member member = mock(Member.class, withSettings().extraInterfaces(AnnotatedElement.class)); + when(jpaAttribute.getName()).thenReturn("willi"); + when(jpaAttribute.isCollection()).thenReturn(false); + when(jpaAttribute.getJavaType()).thenAnswer(new Answer>() { + @Override + public Class answer(InvocationOnMock invocation) throws Throwable { + return BusinessPartner.class; + } + }); + when(jpaAttribute.getDeclaringType()).thenAnswer(new Answer>() { + @Override + public ManagedType answer(InvocationOnMock invocation) throws Throwable { + return mgrType; + } + }); + when(mgrType.getJavaType()).thenAnswer(new Answer>() { + @Override + public Class answer(InvocationOnMock invocation) throws Throwable { + return BusinessPartner.class; + } + }); + when(jpaAttribute.getJavaMember()).thenReturn(member); + when(((AnnotatedElement) member).getAnnotation(EdmProtectedBy.class)).thenReturn(null); + return jpaAttribute; + } + private class PostProcessorSetName extends JPAEdmMetadataPostProcessor { @Override public void processNavigationProperty(IntermediateNavigationPropertyAccess property, diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateProperty.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateProperty.java deleted file mode 100644 index 7046388b7..000000000 --- a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateProperty.java +++ /dev/null @@ -1,384 +0,0 @@ -package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.Mockito.withSettings; - -import java.lang.reflect.AnnotatedElement; -import java.lang.reflect.Member; -import java.sql.Date; -import java.sql.Timestamp; - -import javax.persistence.Column; -import javax.persistence.metamodel.Attribute; -import javax.persistence.metamodel.Attribute.PersistentAttributeType; -import javax.persistence.metamodel.EmbeddableType; -import javax.persistence.metamodel.ManagedType; - -import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - -import com.sap.olingo.jpa.metadata.api.JPAEdmMetadataPostProcessor; -import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; -import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediateEntityTypeAccess; -import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediateNavigationPropertyAccess; -import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediatePropertyAccess; -import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediateReferenceList; -import com.sap.olingo.jpa.processor.core.testmodel.DummyToBeIgnored; - -public class TestIntermediateProperty extends TestMappingRoot { - private TestHelper helper; - private JPAEdmMetadataPostProcessor processor; - - @Before - public void setup() throws ODataJPAModelException { - helper = new TestHelper(emf.getMetamodel(), PUNIT_NAME); - processor = mock(JPAEdmMetadataPostProcessor.class); - } - - @Test - public void checkProptertyCanBeCreated() throws ODataJPAModelException { - EmbeddableType et = helper.getEmbeddedableType("CommunicationData"); - Attribute jpaAttribute = helper.getAttribute(et, "landlinePhoneNumber"); - new IntermediateProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, helper.schema); - } - - @Test - public void checkGetProptertyName() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getAttribute(helper.getEntityType("BusinessPartner"), "type"); - IntermediateProperty property = new IntermediateProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); - assertEquals("Wrong name", "Type", property.getEdmItem().getName()); - } - - @Test - public void checkGetProptertyDBFieldName() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getAttribute(helper.getEntityType("BusinessPartner"), "type"); - IntermediateProperty property = new IntermediateProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); - assertEquals("Wrong name", "\"Type\"", property.getDBFieldName()); - } - - @Test - public void checkGetProptertyType() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getAttribute(helper.getEntityType("BusinessPartner"), "type"); - IntermediateProperty property = new IntermediateProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); - assertEquals("Wrong type", EdmPrimitiveTypeKind.String.getFullQualifiedName().getFullQualifiedNameAsString(), - property.getEdmItem().getType()); - } - - @Test - public void checkGetProptertyComplexType() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getAttribute(helper.getEntityType("BusinessPartner"), "communicationData"); - IntermediateProperty property = new IntermediateProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); - assertEquals("Wrong type", PUNIT_NAME + ".CommunicationData", property.getEdmItem().getType()); - } - - @Test - public void checkGetProptertyIgnoreFalse() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getAttribute(helper.getEntityType("BusinessPartner"), "type"); - IntermediatePropertyAccess property = new IntermediateProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); - assertFalse(property.ignore()); - } - - @Test - public void checkGetProptertyIgnoreTrue() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getAttribute(helper.getEntityType("BusinessPartner"), "customString1"); - IntermediatePropertyAccess property = new IntermediateProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); - assertTrue(property.ignore()); - } - - @Test - public void checkGetProptertyFacetsNullableTrue() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getAttribute(helper.getEntityType("BusinessPartner"), "customString1"); - IntermediateProperty property = new IntermediateProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); - assertTrue(property.getEdmItem().isNullable()); - } - - @Test - public void checkGetProptertyFacetsNullableTrueComplex() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getAttribute(helper.getEmbeddedableType("PostalAddressData"), "POBox"); - IntermediateProperty property = new IntermediateProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); - assertTrue(property.getEdmItem().isNullable()); - } - - @Test - public void checkGetProptertyFacetsNullableFalse() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getAttribute(helper.getEntityType("BusinessPartner"), "eTag"); - IntermediateProperty property = new IntermediateProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); - assertFalse(property.getEdmItem().isNullable()); - } - - @Test - public void checkGetProptertyIsETagTrue() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getAttribute(helper.getEntityType("BusinessPartner"), "eTag"); - IntermediateProperty property = new IntermediateProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); - assertTrue(property.isEtag()); - } - - @Test - public void checkGetProptertyIsETagFalse() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getAttribute(helper.getEntityType("BusinessPartner"), "type"); - IntermediateProperty property = new IntermediateProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); - assertFalse(property.isEtag()); - } - - @Test - public void checkGetProptertyMaxLength() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getAttribute(helper.getEntityType("BusinessPartner"), "type"); - IntermediateProperty property = new IntermediateProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); - assertEquals(new Integer(1), property.getEdmItem().getMaxLength()); - } - - @Test - public void checkGetProptertyMaxLengthNullForClob() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getAttribute(helper.getComplexType("DummyEmbeddedToIgnore"), "command"); - IntermediateProperty property = new IntermediateProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); - assertNull(property.getEdmItem().getMaxLength()); - } - - @Test - public void checkGetProptertyPrecisionDecimal() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getAttribute(helper.getEntityType("BusinessPartner"), "customNum1"); - IntermediateProperty property = new IntermediateProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); - assertEquals(new Integer(16), property.getEdmItem().getPrecision()); - } - - @Test - public void checkGetProptertyScaleDecimal() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getAttribute(helper.getEntityType("BusinessPartner"), "customNum1"); - IntermediateProperty property = new IntermediateProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); - assertEquals(new Integer(5), property.getEdmItem().getScale()); - } - - @Test - public void checkGetProptertyPrecisionTime() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getAttribute(helper.getEntityType("BusinessPartner"), "creationDateTime"); - IntermediateProperty property = new IntermediateProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); - assertEquals(new Integer(3), property.getEdmItem().getPrecision()); - } - - @Test - public void checkGetProptertyMapper() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getAttribute(helper.getEntityType("BusinessPartner"), "creationDateTime"); - IntermediateProperty property = new IntermediateProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); - assertNotNull(property.getEdmItem().getMapping()); - assertEquals(Timestamp.class, property.getEdmItem().getMapping().getMappedJavaClass()); - } - - @Test - public void checkGetProptertyMapperWithConverter() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getAttribute(helper.getEntityType("Person"), "birthDay"); - IntermediateProperty property = new IntermediateProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); - assertNotNull(property.getEdmItem().getMapping()); - assertEquals(Date.class, property.getEdmItem().getMapping().getMappedJavaClass()); - } - - @Test - public void checkGetNoProptertyMapperForClob() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getAttribute(helper.getEntityType("Comment"), "text"); - IntermediateProperty property = new IntermediateProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); - assertNull(property.getEdmItem().getMapping()); - } - - @Test - public void checkPostProcessorCalled() throws ODataJPAModelException { - IntermediateProperty.setPostProcessor(processor); - Attribute jpaAttribute = helper.getAttribute(helper.getEntityType("BusinessPartner"), "creationDateTime"); - IntermediateProperty property = new IntermediateProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); - - property.getEdmItem(); - verify(processor, atLeastOnce()).processProperty(property, BUPA_CANONICAL_NAME); - } - - @Test - public void checkPostProcessorNameChanged() throws ODataJPAModelException { - PostProcessorSetName pPDouble = new PostProcessorSetName(); - IntermediateProperty.setPostProcessor(pPDouble); - - Attribute jpaAttribute = helper.getAttribute(helper.getEntityType("BusinessPartner"), "customString1"); - IntermediateProperty property = new IntermediateProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); - - assertEquals("Wrong name", "ContactPersonName", property.getEdmItem().getName()); - } - - @Test - public void checkPostProcessorExternalNameChanged() throws ODataJPAModelException { - PostProcessorSetName pPDouble = new PostProcessorSetName(); - IntermediateModelElement.setPostProcessor(pPDouble); - - Attribute jpaAttribute = helper.getAttribute(helper.getEntityType("BusinessPartner"), "customString1"); - IntermediatePropertyAccess property = new IntermediateProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); - - assertEquals("Wrong name", "ContactPersonName", property.getExternalName()); - } - - @Test - public void checkConverterGetConverterReturned() throws ODataJPAModelException { - PostProcessorSetName pPDouble = new PostProcessorSetName(); - IntermediateModelElement.setPostProcessor(pPDouble); - - Attribute jpaAttribute = helper.getAttribute(helper.getEntityType("Person"), "birthDay"); - IntermediateProperty property = new IntermediateProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); - - assertNotNull(property.getConverter()); - } - - @Test - public void checkConverterGetConverterNotReturned() throws ODataJPAModelException { - PostProcessorSetName pPDouble = new PostProcessorSetName(); - IntermediateModelElement.setPostProcessor(pPDouble); - - Attribute jpaAttribute = helper.getAttribute(helper.getEntityType("Person"), "customString1"); - IntermediateProperty property = new IntermediateProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); - - assertNull(property.getConverter()); - } - - @Test - public void checkConverterGetConverterNotReturnedDiffernt() throws ODataJPAModelException { - PostProcessorSetName pPDouble = new PostProcessorSetName(); - IntermediateModelElement.setPostProcessor(pPDouble); - - Attribute jpaAttribute = helper.getAttribute(helper.getEntityType("DummyToBeIgnored"), "uuid"); - IntermediateProperty property = new IntermediateProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); - - assertNull(property.getConverter()); - } - - @Test - public void checkGetProptertyDefaultValue() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getAttribute(helper.getEmbeddedableType("PostalAddressData"), - "regionCodePublisher"); - IntermediateProperty property = new IntermediateProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); - assertEquals("ISO", property.getEdmItem().getDefaultValue()); - } - - @Test - public void checkGetPropertyIsStream() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getAttribute(helper.getEntityType("PersonImage"), - "image"); - IntermediateProperty property = new IntermediateProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); - assertTrue(property.isStream()); - } - - @Test - public void checkGetTypeBoxedForPrimitive() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getAttribute(helper.getEntityType("AdministrativeDivision"), - "population"); - IntermediateProperty property = new IntermediateProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); - assertEquals(Long.class, property.getType()); - } - - @Test - public void checkGetTypeBoxed() throws ODataJPAModelException { - Attribute jpaAttribute = helper.getAttribute(helper.getEntityType("AdministrativeDivision"), - "area"); - IntermediateProperty property = new IntermediateProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); - assertEquals(Integer.class, property.getType()); - } - - @Test(expected = ODataJPAModelException.class) - public void checkThrowsAnExceptionTimestampWithoutPrecision() throws ODataJPAModelException { - // If Precision missing EdmDateTimeOffset.internalValueToString throws an exception => pre-check - final Attribute jpaAttribute = mock(Attribute.class); - final ManagedType jpaManagedType = mock(ManagedType.class); - when(jpaAttribute.getName()).thenReturn("start"); - when(jpaAttribute.getPersistentAttributeType()).thenReturn(PersistentAttributeType.BASIC); - when(jpaAttribute.getDeclaringType()).thenAnswer(new Answer>() { - @Override - public ManagedType answer(InvocationOnMock invocation) throws Throwable { - return jpaManagedType; - } - }); - when(jpaAttribute.getJavaType()).thenAnswer(new Answer>() { - @Override - public Class answer(InvocationOnMock invocation) throws Throwable { - return Timestamp.class; - } - }); - when(jpaManagedType.getJavaType()).thenAnswer(new Answer>() { - @Override - public Class answer(InvocationOnMock invocation) throws Throwable { - return DummyToBeIgnored.class; - } - }); - - Column column = mock(Column.class); - AnnotatedElement annotations = mock(AnnotatedElement.class, withSettings().extraInterfaces(Member.class)); - when(annotations.getAnnotation(Column.class)).thenReturn(column); - when(jpaAttribute.getJavaMember()).thenReturn((Member) annotations); - when(column.name()).thenReturn("Test"); - - IntermediateProperty property = new IntermediateProperty(new JPAEdmNameBuilder(PUNIT_NAME), jpaAttribute, - helper.schema); - property.getEdmItem(); - } - - @Ignore - @Test - public void checkGetSRID() { - // Test for spatial data missing - } - - private class PostProcessorSetName extends JPAEdmMetadataPostProcessor { - - @Override - public void processProperty(IntermediatePropertyAccess property, String jpaManagedTypeClassName) { - if (jpaManagedTypeClassName.equals( - "com.sap.olingo.jpa.processor.core.testmodel.BusinessPartner")) { - if (property.getInternalName().equals("customString1")) { - property.setExternalName("ContactPersonName"); - } - } - } - - @Override - public void processNavigationProperty(IntermediateNavigationPropertyAccess property, - String jpaManagedTypeClassName) {} - - @Override - public void provideReferences(IntermediateReferenceList references) throws ODataJPAModelException {} - - @Override - public void processEntityType(IntermediateEntityTypeAccess entity) {} - } -} diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateReferences.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateReferences.java index c3aeb4612..7a11e639c 100644 --- a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateReferences.java +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateReferences.java @@ -1,8 +1,9 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.fail; import java.net.URISyntaxException; import java.util.List; @@ -10,8 +11,8 @@ import org.apache.olingo.commons.api.edm.FullQualifiedName; import org.apache.olingo.commons.api.edm.provider.CsdlSchema; import org.apache.olingo.commons.api.edmx.EdmxReference; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import com.sap.olingo.jpa.metadata.api.JPAEdmMetadataPostProcessor; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAServiceDocument; @@ -25,7 +26,7 @@ public class TestIntermediateReferences extends TestMappingRoot { private IntermediateReferences cut; - @Before + @BeforeEach public void setup() throws ODataJPAModelException { cut = new IntermediateReferences(); } @@ -35,7 +36,7 @@ public void checkAddOnlyURI() throws ODataJPAModelException, URISyntaxException String uri = "http://docs.oasisopen.org/odata/odata/v4.0/os/vocabularies/Org.OData.Core.V1.xml"; cut.addReference(uri); List act = cut.getEdmReferences(); - assertEquals(act.size(), 1); + assertEquals(1, act.size()); assertEquals(act.get(0).getUri().toString(), uri); } @@ -109,6 +110,24 @@ public void checkGetTermByAlias() throws ODataJPAModelException { assertNotNull(cut.getTerm(fqn)); } + @Test + public void checkReturnNullOnUnknowTerm() throws ODataJPAModelException { + String uri = "http://docs.oasisopen.org/odata/odata/v4.0/os/vocabularies/Org.OData.Measures.V1.xml"; + IntermediateReferenceAccess ref = cut.addReference(uri, "annotations/Org.OData.Measures.V1.xml"); + ref.addInclude("Org.OData.Measures.V1", "Measures"); + FullQualifiedName fqn = new FullQualifiedName("Measures", "Dummy"); + assertNull(cut.getTerm(fqn)); + } + + @Test + public void checkReturnNullOnUnknowNamespace() throws ODataJPAModelException { + String uri = "http://docs.oasisopen.org/odata/odata/v4.0/os/vocabularies/Org.OData.Measures.V1.xml"; + IntermediateReferenceAccess ref = cut.addReference(uri, "annotations/Org.OData.Measures.V1.xml"); + ref.addInclude("Org.OData.Measures.V1", "Measures"); + FullQualifiedName fqn = new FullQualifiedName("Dummy", "ISOCurrency"); + assertNull(cut.getTerm(fqn)); + } + class PostProcessor extends JPAEdmMetadataPostProcessor { @Override public void processNavigationProperty(final IntermediateNavigationPropertyAccess property, diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateSchema.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateSchema.java index 0206b42d9..8738f9e85 100644 --- a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateSchema.java +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateSchema.java @@ -1,70 +1,80 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; -import org.junit.Test; +import java.util.Arrays; +import java.util.HashSet; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.reflections.Reflections; +import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmEnumeration; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; +import com.sap.olingo.jpa.processor.core.testmodel.ABCClassifiaction; +import com.sap.olingo.jpa.processor.core.testmodel.AccessRights; import com.sap.olingo.jpa.processor.core.testmodel.TestDataConstants; public class TestIntermediateSchema extends TestMappingRoot { + private Reflections r; + + @BeforeEach + public void setup() { + r = mock(Reflections.class); + when(r.getTypesAnnotatedWith(EdmEnumeration.class)).thenReturn(new HashSet<>(Arrays.asList(new Class[] { + ABCClassifiaction.class, AccessRights.class }))); + } @Test public void checkSchemaCanBeCreated() throws ODataJPAModelException { - new IntermediateSchema(new JPAEdmNameBuilder(PUNIT_NAME), emf.getMetamodel(), mock(Reflections.class)); + + new IntermediateSchema(new JPADefaultEdmNameBuilder(PUNIT_NAME), emf.getMetamodel(), r); } @Test public void checkSchemaGetAllEntityTypes() throws ODataJPAModelException { - IntermediateSchema schema = new IntermediateSchema(new JPAEdmNameBuilder(PUNIT_NAME), emf.getMetamodel(), mock( - Reflections.class)); - assertEquals("Wrong number of entities", TestDataConstants.NO_ENTITY_TYPES, schema.getEdmItem().getEntityTypes() - .size()); + IntermediateSchema schema = new IntermediateSchema(new JPADefaultEdmNameBuilder(PUNIT_NAME), emf.getMetamodel(), r); + assertEquals(TestDataConstants.NO_ENTITY_TYPES, schema.getEdmItem().getEntityTypes().size(), + "Wrong number of entities"); } @Test public void checkSchemaGetEntityTypeByNameNotNull() throws ODataJPAModelException { - IntermediateSchema schema = new IntermediateSchema(new JPAEdmNameBuilder(PUNIT_NAME), emf.getMetamodel(), mock( - Reflections.class)); + IntermediateSchema schema = new IntermediateSchema(new JPADefaultEdmNameBuilder(PUNIT_NAME), emf.getMetamodel(), r); assertNotNull(schema.getEdmItem().getEntityType("BusinessPartner")); } @Test public void checkSchemaGetEntityTypeByNameRightEntity() throws ODataJPAModelException { - IntermediateSchema schema = new IntermediateSchema(new JPAEdmNameBuilder(PUNIT_NAME), emf.getMetamodel(), mock( - Reflections.class)); + IntermediateSchema schema = new IntermediateSchema(new JPADefaultEdmNameBuilder(PUNIT_NAME), emf.getMetamodel(), r); assertEquals("BusinessPartner", schema.getEdmItem().getEntityType("BusinessPartner").getName()); } @Test public void checkSchemaGetAllComplexTypes() throws ODataJPAModelException { - IntermediateSchema schema = new IntermediateSchema(new JPAEdmNameBuilder(PUNIT_NAME), emf.getMetamodel(), mock( - Reflections.class)); + IntermediateSchema schema = new IntermediateSchema(new JPADefaultEdmNameBuilder(PUNIT_NAME), emf.getMetamodel(), r); // ChangeInformation,CommunicationData,AdministrativeInformation,PostalAddressData - assertEquals("Wrong number of entities", 5, schema.getEdmItem().getComplexTypes().size()); + assertEquals(21, schema.getEdmItem().getComplexTypes().size(), "Wrong number of complex types"); } @Test public void checkSchemaGetComplexTypeByNameNotNull() throws ODataJPAModelException { - IntermediateSchema schema = new IntermediateSchema(new JPAEdmNameBuilder(PUNIT_NAME), emf.getMetamodel(), mock( - Reflections.class)); + IntermediateSchema schema = new IntermediateSchema(new JPADefaultEdmNameBuilder(PUNIT_NAME), emf.getMetamodel(), r); assertNotNull(schema.getEdmItem().getComplexType("CommunicationData")); } @Test public void checkSchemaGetComplexTypeByNameRightEntity() throws ODataJPAModelException { - IntermediateSchema schema = new IntermediateSchema(new JPAEdmNameBuilder(PUNIT_NAME), emf.getMetamodel(), mock( - Reflections.class)); + IntermediateSchema schema = new IntermediateSchema(new JPADefaultEdmNameBuilder(PUNIT_NAME), emf.getMetamodel(), r); assertEquals("CommunicationData", schema.getEdmItem().getComplexType("CommunicationData").getName()); } @Test public void checkSchemaGetAllFunctions() throws ODataJPAModelException { - IntermediateSchema schema = new IntermediateSchema(new JPAEdmNameBuilder(PUNIT_NAME), emf.getMetamodel(), mock( - Reflections.class)); - assertEquals("Wrong number of entities", 6, schema.getEdmItem().getFunctions().size()); + IntermediateSchema schema = new IntermediateSchema(new JPADefaultEdmNameBuilder(PUNIT_NAME), emf.getMetamodel(), r); + assertEquals(10, schema.getEdmItem().getFunctions().size(), "Wrong number of entities"); } } diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateServiceDocument.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateServiceDocument.java index 63e1c1f52..d7aadd840 100644 --- a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateServiceDocument.java +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateServiceDocument.java @@ -1,56 +1,94 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.params.provider.Arguments.arguments; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.util.List; +import java.util.stream.Stream; +import org.apache.olingo.commons.api.edm.EdmAction; import org.apache.olingo.commons.api.edm.EdmBindingTarget; +import org.apache.olingo.commons.api.edm.EdmComplexType; import org.apache.olingo.commons.api.edm.EdmEntityType; +import org.apache.olingo.commons.api.edm.EdmFunction; +import org.apache.olingo.commons.api.edm.EdmType; import org.apache.olingo.commons.api.edm.FullQualifiedName; import org.apache.olingo.commons.api.edm.provider.CsdlEntityContainer; import org.apache.olingo.commons.api.edm.provider.CsdlSchema; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAServiceDocument; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; public class TestIntermediateServiceDocument extends TestMappingRoot { + private JPAServiceDocument cut; + + static Stream getEntityTypeByFqn() { + return Stream.of( + arguments(new FullQualifiedName("com.sap.olingo.jpa.BusinessPartner"), false), + arguments(new FullQualifiedName("com.sap.olingo.jpa.Dummy"), true), + arguments(new FullQualifiedName("dummy.BusinessPartner"), true)); + } + + static Stream getEntityTypeByEsName() { + return Stream.of( + arguments("BusinessPartners", false), + arguments("Dummy", true)); + } + + static Stream getEnumType() { + return Stream.of( + arguments("com.sap.olingo.jpa.AccessRights", false), + arguments("com.sap.olingo.jpa.Dummy", true), + arguments("Unknown.AccessRights", true)); + + } + + @BeforeEach + public void setup() throws ODataJPAModelException { + cut = new IntermediateServiceDocument(PUNIT_NAME, emf.getMetamodel(), null, + new String[] { "com.sap.olingo.jpa.processor.core.testmodel" }); + } + @Test public void checkServiceDocumentCanBeCreated() throws ODataJPAModelException { - new IntermediateServiceDocument(PUNIT_NAME, emf.getMetamodel(), null, null); + new IntermediateServiceDocument(PUNIT_NAME, emf.getMetamodel(), null, + new String[] { "com.sap.olingo.jpa.processor.core.testmodel" }); } @Test public void checkServiceDocumentGetSchemaList() throws ODataJPAModelException { - JPAServiceDocument svc = new IntermediateServiceDocument(PUNIT_NAME, emf.getMetamodel(), null, null); - assertEquals("Wrong number of schemas", 1, svc.getEdmSchemas().size()); + assertEquals(1, cut.getEdmSchemas().size(), "Wrong number of schemas"); } @Test public void checkServiceDocumentGetContainer() throws ODataJPAModelException { - JPAServiceDocument svc = new IntermediateServiceDocument(PUNIT_NAME, emf.getMetamodel(), null, null); - assertNotNull("Entity Container not found", svc.getEdmEntityContainer()); + assertNotNull(cut.getEdmEntityContainer(), "Entity Container not found"); } @Test public void checkServiceDocumentGetContainerFromSchema() throws ODataJPAModelException { - JPAServiceDocument svc = new IntermediateServiceDocument(PUNIT_NAME, emf.getMetamodel(), null, null); - List schemas = svc.getEdmSchemas(); + + List schemas = cut.getEdmSchemas(); CsdlSchema schema = schemas.get(0); - assertNotNull("Entity Container not found", schema.getEntityContainer()); + assertNotNull(schema.getEntityContainer(), "Entity Container not found"); } @Test public void checkServiceDocumentGetEntitySetsFromContainer() throws ODataJPAModelException { - JPAServiceDocument svc = new IntermediateServiceDocument(PUNIT_NAME, emf.getMetamodel(), null, null); - CsdlEntityContainer container = svc.getEdmEntityContainer(); - assertNotNull("Entity Container not found", container.getEntitySets()); + CsdlEntityContainer container = cut.getEdmEntityContainer(); + assertNotNull(container.getEntitySets(), "Entity Container not found"); } @Test @@ -60,8 +98,7 @@ public void checkHasEtagReturnsTrueOnVersion() throws ODataJPAModelException { when(target.getEntityType()).thenReturn(et); when(et.getFullQualifiedName()).thenReturn(new FullQualifiedName(PUNIT_NAME, "BusinessPartner")); - JPAServiceDocument svc = new IntermediateServiceDocument(PUNIT_NAME, emf.getMetamodel(), null, null); - assertTrue(svc.hasETag(target)); + assertTrue(cut.hasETag(target)); } @Test @@ -74,4 +111,207 @@ public void checkHasEtagReturnsFalseWithoutVersion() throws ODataJPAModelExcepti JPAServiceDocument svc = new IntermediateServiceDocument(PUNIT_NAME, emf.getMetamodel(), null, null); assertFalse(svc.hasETag(target)); } + + @ParameterizedTest + @MethodSource("getEnumType") + public void checkGetEnumType(final String enumName, final boolean isNull) throws ODataJPAModelException { + if (isNull) + assertNull(cut.getEnumType(enumName)); + else + assertNotNull(cut.getEnumType(enumName)); + } + + @ParameterizedTest + @MethodSource("getEntityTypeByEsName") + public void checkGetEntityTypeByEsName(final String esName, final boolean isNull) throws ODataJPAModelException { + if (isNull) + assertNull(cut.getEntity(esName)); + else + assertNotNull(cut.getEntity(esName)); + } + + @ParameterizedTest + @MethodSource("getEntityTypeByFqn") + public void checkGetEntityTypeByFqn(final FullQualifiedName etFqn, final boolean isNull) + throws ODataJPAModelException { + if (isNull) + assertNull(cut.getEntity(etFqn)); + else + assertNotNull(cut.getEntity(etFqn)); + } + + @Test + public void checkGetEntityTypeByEdmType() throws ODataJPAModelException { + final EdmEntityType type = mock(EdmEntityType.class); + when(type.getNamespace()).thenReturn("com.sap.olingo.jpa"); + when(type.getName()).thenReturn("BusinessPartner"); + assertNotNull(cut.getEntity(type)); + } + + @Test + public void checkGetEntityTypeByEdmTypeReturnNullOnUnkown() throws ODataJPAModelException { + final EdmEntityType type = mock(EdmEntityType.class); + when(type.getNamespace()).thenReturn("com.sap.olingo.jpa"); + when(type.getName()).thenReturn("Unknown"); + assertNull(cut.getEntity(type)); + } + + @Test + public void checkGetEntityTypeByEdmTypeReturnNullOnUnkownSchema() throws ODataJPAModelException { + final EdmEntityType type = mock(EdmEntityType.class); + when(type.getNamespace()).thenReturn("Unknown"); + when(type.getName()).thenReturn("BoundNoImport"); + assertNull(cut.getEntity(type)); + } + + @Test + public void checkGetComplexTypeByEdmType() throws ODataJPAModelException { + final EdmComplexType type = mock(EdmComplexType.class); + when(type.getNamespace()).thenReturn("com.sap.olingo.jpa"); + when(type.getName()).thenReturn("CommunicationData"); + assertNotNull(cut.getComplexType(type)); + } + + @Test + public void checkGetComplexTypeByEdmTypeReturnNullOnUnkown() throws ODataJPAModelException { + final EdmComplexType type = mock(EdmComplexType.class); + when(type.getNamespace()).thenReturn("com.sap.olingo.jpa"); + when(type.getName()).thenReturn("Unknown"); + assertNull(cut.getComplexType(type)); + } + + @Test + public void checkGetComplexTypeByEdmTypeReturnNullOnUnkownSchema() throws ODataJPAModelException { + final EdmComplexType type = mock(EdmComplexType.class); + when(type.getNamespace()).thenReturn("Unknown"); + when(type.getName()).thenReturn("BoundNoImport"); + assertNull(cut.getComplexType(type)); + } + + @Test + public void checkGetAction() throws ODataJPAModelException { + final EdmAction action = mock(EdmAction.class); + when(action.getNamespace()).thenReturn("com.sap.olingo.jpa"); + when(action.getName()).thenReturn("BoundNoImport"); + final JPAServiceDocument svc = new IntermediateServiceDocument(PUNIT_NAME, emf.getMetamodel(), null, + new String[] { "com.sap.olingo.jpa.metadata.core.edm.mapper.testaction" }); + assertNotNull(svc.getAction(action)); + } + + @Test + public void checkGetActionReturnNullOnUnkownAction() throws ODataJPAModelException { + final EdmAction action = mock(EdmAction.class); + when(action.getNamespace()).thenReturn("com.sap.olingo.jpa"); + when(action.getName()).thenReturn("Unknown"); + + assertNull(cut.getAction(action)); + } + + @Test + public void checkGetActionReturnNullOnUnkownSchema() throws ODataJPAModelException { + final EdmAction action = mock(EdmAction.class); + when(action.getNamespace()).thenReturn("Unknown"); + when(action.getName()).thenReturn("BoundNoImport"); + + assertNull(cut.getAction(action)); + } + + @Test + public void checkGetFunction() throws ODataJPAModelException { + final EdmFunction function = mock(EdmFunction.class); + when(function.getNamespace()).thenReturn("com.sap.olingo.jpa"); + when(function.getName()).thenReturn("ConvertToQkm"); + assertNotNull(cut.getFunction(function)); + } + + @Test + public void checkGetFunctionReturnNullOnUnkownFunction() throws ODataJPAModelException { + final EdmFunction function = mock(EdmFunction.class); + when(function.getNamespace()).thenReturn("com.sap.olingo.jpa"); + when(function.getName()).thenReturn("Unknown"); + assertNull(cut.getFunction(function)); + } + + @Test + public void checkGetFunctionReturnNullOnUnkownSchema() throws ODataJPAModelException { + final EdmFunction function = mock(EdmFunction.class); + when(function.getNamespace()).thenReturn("Unknown"); + when(function.getName()).thenReturn("BoundNoImport"); + assertNull(cut.getFunction(function)); + } + + @Test + public void checkHasMediaETagNotSupported() { + final EdmBindingTarget target = mock(EdmBindingTarget.class); + assertFalse(cut.hasMediaETag(target)); + } + + @Test + public void checkGetEntityTypeReturnsSetCustomName() throws ODataJPAModelException { + cut = createCutWithCustomNameBuilder(); + assertNotNull(cut.getEntity("Business_Partner".toUpperCase())); + } + + @Test + public void checkGetEntityTypeReturnsEdmTypCustomName() throws ODataJPAModelException { + cut = createCutWithCustomNameBuilder(); + final EdmType edmType = mock(EdmType.class); + when(edmType.getName()).thenReturn("Business_Partner"); + when(edmType.getNamespace()).thenReturn("test"); + + assertNotNull(cut.getEntity(edmType)); + } + + @Test + public void checkGetPropertyReturnsCustomName() throws ODataJPAModelException { + cut = createCutWithCustomNameBuilder(); + assertEquals("creationDateTime", cut.getEntity("Business_Partner".toUpperCase()).getAttribute("creationDateTime") + .get().getExternalName()); + } + + @Test + public void checkGetComplexTypeReturnsCustomName() throws ODataJPAModelException { + cut = createCutWithCustomNameBuilder(); + final EdmComplexType type = mock(EdmComplexType.class); + when(type.getNamespace()).thenReturn("test"); + when(type.getName()).thenReturn("T_CommunicationData"); + assertNotNull(cut.getComplexType(type)); + } + + @Test + public void checkGetContainerReturnsCustomName() throws ODataJPAModelException { + cut = createCutWithCustomNameBuilder(); + assertEquals("service_container", cut.getEdmEntityContainer().getName()); + } + + @Test + public void checkGetEnumReturnsCustomName() throws ODataJPAModelException { + cut = createCutWithCustomNameBuilder(); + assertNotNull(cut.getEnumType("test.E_AccessRights")); + } + + @Test + public void checkGetActionCustomName() throws ODataJPAModelException { + cut = createCutWithCustomNameBuilder(); + final EdmAction action = mock(EdmAction.class); + when(action.getNamespace()).thenReturn("test"); + when(action.getName()).thenReturn("O_BoundNoImport"); + assertNotNull(cut.getAction(action)); + } + + @Test + public void checkGetFunctionCustomName() throws ODataJPAModelException { + cut = createCutWithCustomNameBuilder(); + final EdmFunction function = mock(EdmFunction.class); + when(function.getNamespace()).thenReturn("test"); + when(function.getName()).thenReturn("O_sum"); + assertNotNull(cut.getFunction(function)); + } + + private IntermediateServiceDocument createCutWithCustomNameBuilder() throws ODataJPAModelException { + return new IntermediateServiceDocument(new CustomJPANameBuilder(), emf.getMetamodel(), null, + new String[] { "com.sap.olingo.jpa.processor.core.testmodel", + "com.sap.olingo.jpa.metadata.core.edm.mapper.testaction" }); + } + } diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateSimpleProperty.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateSimpleProperty.java new file mode 100644 index 000000000..9563dc4b8 --- /dev/null +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateSimpleProperty.java @@ -0,0 +1,706 @@ +package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; + +import static com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException.MessageKeys.TRANSIENT_CALCULATOR_TOO_MANY_CONSTRUCTORS; +import static com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException.MessageKeys.TRANSIENT_CALCULATOR_WRONG_PARAMETER; +import static com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException.MessageKeys.TRANSIENT_KEY_NOT_SUPPORTED; +import static com.sap.olingo.jpa.processor.core.util.Assertions.assertException; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.withSettings; + +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Member; +import java.sql.Date; +import java.sql.Timestamp; +import java.util.List; + +import javax.persistence.Column; +import javax.persistence.metamodel.Attribute; +import javax.persistence.metamodel.Attribute.PersistentAttributeType; +import javax.persistence.metamodel.EmbeddableType; +import javax.persistence.metamodel.ManagedType; + +import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import com.sap.olingo.jpa.metadata.api.JPAEdmMetadataPostProcessor; +import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmProtectedBy; +import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmProtections; +import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; +import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediateEntityTypeAccess; +import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediateNavigationPropertyAccess; +import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediatePropertyAccess; +import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.IntermediateReferenceList; +import com.sap.olingo.jpa.metadata.core.edm.mapper.util.MemberDouble; +import com.sap.olingo.jpa.processor.core.errormodel.TeamWithTransientCalculatorConstructorError; +import com.sap.olingo.jpa.processor.core.errormodel.TeamWithTransientCalculatorError; +import com.sap.olingo.jpa.processor.core.errormodel.TeamWithTransientKey; +import com.sap.olingo.jpa.processor.core.testmodel.AdministrativeDivision; +import com.sap.olingo.jpa.processor.core.testmodel.BusinessPartner; +import com.sap.olingo.jpa.processor.core.testmodel.BusinessPartnerProtected; +import com.sap.olingo.jpa.processor.core.testmodel.Comment; +import com.sap.olingo.jpa.processor.core.testmodel.DummyToBeIgnored; +import com.sap.olingo.jpa.processor.core.testmodel.Organization; +import com.sap.olingo.jpa.processor.core.testmodel.Person; +import com.sap.olingo.jpa.processor.core.testmodel.PersonImage; + +public class TestIntermediateSimpleProperty extends TestMappingRoot { + private TestHelper helper; + private TestHelper errorHelper; + private JPAEdmMetadataPostProcessor processor; + + @BeforeEach + public void setup() throws ODataJPAModelException { + helper = new TestHelper(emf.getMetamodel(), PUNIT_NAME); + errorHelper = new TestHelper(errorEmf.getMetamodel(), ERROR_PUNIT); + processor = mock(JPAEdmMetadataPostProcessor.class); + } + + @Test + public void checkProptertyCanBeCreated() throws ODataJPAModelException { + EmbeddableType et = helper.getEmbeddedableType("CommunicationData"); + Attribute jpaAttribute = helper.getAttribute(et, "landlinePhoneNumber"); + assertNotNull(new IntermediateSimpleProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), jpaAttribute, + helper.schema)); + } + + @Test + public void checkGetProptertyName() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(BusinessPartner.class), "type"); + IntermediateSimpleProperty property = new IntermediateSimpleProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), + jpaAttribute, + helper.schema); + assertEquals("Type", property.getEdmItem().getName(), "Wrong name"); + } + + @Test + public void checkGetProptertyDBFieldName() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(BusinessPartner.class), "type"); + IntermediateSimpleProperty property = new IntermediateSimpleProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), + jpaAttribute, + helper.schema); + assertEquals("\"Type\"", property.getDBFieldName(), "Wrong name"); + } + + @Test + public void checkGetProptertySimpleType() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(BusinessPartner.class), "type"); + IntermediateSimpleProperty property = new IntermediateSimpleProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), + jpaAttribute, helper.schema); + assertEquals(EdmPrimitiveTypeKind.String.getFullQualifiedName().getFullQualifiedNameAsString(), + property.getEdmItem().getType(), "Wrong type"); + } + + @Test + public void checkGetProptertyComplexType() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(BusinessPartner.class), + "communicationData"); + IntermediateSimpleProperty property = new IntermediateSimpleProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), + jpaAttribute, + helper.schema); + assertEquals(PUNIT_NAME + ".CommunicationData", property.getEdmItem().getType(), "Wrong type"); + } + + @Test + public void checkGetProptertyEnumTypeWithoutConverter() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(Organization.class), "aBCClass"); + IntermediateSimpleProperty property = new IntermediateSimpleProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), + jpaAttribute, + helper.schema); + assertEquals("com.sap.olingo.jpa.ABCClassifiaction", property.getEdmItem().getType(), "Wrong type"); + } + + @Test + public void checkGetProptertyEnumTypeWithoutConverterMustNotHaveMapper() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(Organization.class), "aBCClass"); + IntermediateSimpleProperty property = new IntermediateSimpleProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), + jpaAttribute, + helper.schema); + assertNull(property.getEdmItem().getMapping()); + } + + @Test + public void checkGetProptertyEnumTypeWithConverter() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(Person.class), "accessRights"); + IntermediateSimpleProperty property = new IntermediateSimpleProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), + jpaAttribute, + helper.schema); + assertEquals("com.sap.olingo.jpa.AccessRights", property.getEdmItem().getType(), "Wrong type"); + } + + @Test + public void checkGetProptertyIgnoreFalse() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(BusinessPartner.class), "type"); + IntermediatePropertyAccess property = new IntermediateSimpleProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), + jpaAttribute, + helper.schema); + assertFalse(property.ignore()); + } + + @Test + public void checkGetProptertyIgnoreTrue() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(BusinessPartner.class), "customString1"); + IntermediatePropertyAccess property = new IntermediateSimpleProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), + jpaAttribute, + helper.schema); + assertTrue(property.ignore()); + } + + @Test + public void checkGetProptertyFacetsNullableTrue() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(BusinessPartner.class), "customString1"); + IntermediateSimpleProperty property = new IntermediateSimpleProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), + jpaAttribute, + helper.schema); + assertTrue(property.getEdmItem().isNullable()); + } + + @Test + public void checkGetProptertyFacetsNullableTrueComplex() throws ODataJPAModelException { + final Attribute jpaAttribute = helper.getAttribute(helper.getEmbeddedableType("PostalAddressData"), "pOBox"); + final IntermediateSimpleProperty property = new IntermediateSimpleProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), + jpaAttribute, helper.schema); + assertTrue(property.getEdmItem().isNullable()); + } + + @Test + public void checkGetProptertyFacetsNullableFalse() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(BusinessPartner.class), "eTag"); + IntermediateSimpleProperty property = new IntermediateSimpleProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), + jpaAttribute, helper.schema); + assertFalse(property.getEdmItem().isNullable()); + } + + @Test + public void checkGetProptertyIsETagTrue() throws ODataJPAModelException { + final Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(BusinessPartner.class), "eTag"); + final IntermediateSimpleProperty property = new IntermediateSimpleProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), + jpaAttribute, helper.schema); + assertTrue(property.isEtag()); + } + + @Test + public void checkGetProptertyIsETagFalse() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(BusinessPartner.class), "type"); + IntermediateSimpleProperty property = new IntermediateSimpleProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), + jpaAttribute, + helper.schema); + assertFalse(property.isEtag()); + } + + @Test + public void checkGetProptertyMaxLength() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(BusinessPartner.class), "type"); + IntermediateSimpleProperty property = new IntermediateSimpleProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), + jpaAttribute, + helper.schema); + assertEquals(new Integer(1), property.getEdmItem().getMaxLength()); + } + + @Test + public void checkGetProptertyMaxLengthNullForClob() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getAttribute(helper.getComplexType("DummyEmbeddedToIgnore"), "command"); + IntermediateSimpleProperty property = new IntermediateSimpleProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), + jpaAttribute, + helper.schema); + assertNull(property.getEdmItem().getMaxLength()); + } + + @Test + public void checkGetProptertyPrecisionDecimal() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(BusinessPartner.class), "customNum1"); + IntermediateSimpleProperty property = new IntermediateSimpleProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), + jpaAttribute, + helper.schema); + assertEquals(new Integer(16), property.getEdmItem().getPrecision()); + } + + @Test + public void checkGetProptertyScaleDecimal() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(BusinessPartner.class), "customNum1"); + IntermediateSimpleProperty property = new IntermediateSimpleProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), + jpaAttribute, + helper.schema); + assertEquals(new Integer(5), property.getEdmItem().getScale()); + } + + @Test + public void checkGetProptertyPrecisionTime() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(BusinessPartner.class), "creationDateTime"); + IntermediateSimpleProperty property = new IntermediateSimpleProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), + jpaAttribute, + helper.schema); + assertEquals(new Integer(3), property.getEdmItem().getPrecision()); + } + + @Test + public void checkGetProptertyMapper() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(BusinessPartner.class), "creationDateTime"); + IntermediateSimpleProperty property = new IntermediateSimpleProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), + jpaAttribute, + helper.schema); + assertNotNull(property.getEdmItem().getMapping()); + assertEquals(Timestamp.class, property.getEdmItem().getMapping().getMappedJavaClass()); + } + + @Test + public void checkGetProptertyMapperWithConverter() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(Person.class), "birthDay"); + IntermediateSimpleProperty property = new IntermediateSimpleProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), + jpaAttribute, + helper.schema); + assertNotNull(property.getEdmItem().getMapping()); + assertEquals(Date.class, property.getEdmItem().getMapping().getMappedJavaClass()); + } + + @Test + public void checkGetNoProptertyMapperForClob() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(Comment.class), "text"); + IntermediateSimpleProperty property = new IntermediateSimpleProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), + jpaAttribute, + helper.schema); + assertNull(property.getEdmItem().getMapping()); + } + + @Test + public void checkPostProcessorCalled() throws ODataJPAModelException { + IntermediateSimpleProperty.setPostProcessor(processor); + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(BusinessPartner.class), "creationDateTime"); + IntermediateSimpleProperty property = new IntermediateSimpleProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), + jpaAttribute, + helper.schema); + + property.getEdmItem(); + verify(processor, atLeastOnce()).processProperty(property, BUPA_CANONICAL_NAME); + } + + @Test + public void checkPostProcessorNameChanged() throws ODataJPAModelException { + PostProcessorSetName pPDouble = new PostProcessorSetName(); + IntermediateSimpleProperty.setPostProcessor(pPDouble); + + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(BusinessPartner.class), "customString1"); + IntermediateSimpleProperty property = new IntermediateSimpleProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), + jpaAttribute, + helper.schema); + + assertEquals("ContactPersonName", property.getEdmItem().getName(), "Wrong name"); + } + + @Test + public void checkPostProcessorExternalNameChanged() throws ODataJPAModelException { + PostProcessorSetName pPDouble = new PostProcessorSetName(); + IntermediateModelElement.setPostProcessor(pPDouble); + + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(BusinessPartner.class), "customString1"); + IntermediatePropertyAccess property = new IntermediateSimpleProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), + jpaAttribute, + helper.schema); + + assertEquals("ContactPersonName", property.getExternalName(), "Wrong name"); + } + + @Test + public void checkConverterGetConverterReturned() throws ODataJPAModelException { + PostProcessorSetName pPDouble = new PostProcessorSetName(); + IntermediateModelElement.setPostProcessor(pPDouble); + + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(BusinessPartner.class), "creationDateTime"); + IntermediateSimpleProperty property = new IntermediateSimpleProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), + jpaAttribute, helper.schema); + + assertNotNull(property.getConverter()); + } + + @Test + public void checkConverterGetConverterNotReturned() throws ODataJPAModelException { + PostProcessorSetName pPDouble = new PostProcessorSetName(); + IntermediateModelElement.setPostProcessor(pPDouble); + + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(Person.class), "customString1"); + IntermediateSimpleProperty property = new IntermediateSimpleProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), + jpaAttribute, helper.schema); + + assertNull(property.getConverter()); + } + + @Test + public void checkConverterGetConverterNotReturnedDiffernt() throws ODataJPAModelException { + PostProcessorSetName pPDouble = new PostProcessorSetName(); + IntermediateModelElement.setPostProcessor(pPDouble); + + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(DummyToBeIgnored.class), "uuid"); + IntermediateSimpleProperty property = new IntermediateSimpleProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), + jpaAttribute, + helper.schema); + + assertNull(property.getConverter()); + } + + @Test + public void checkGetProptertyDefaultValue() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getAttribute(helper.getEmbeddedableType("PostalAddressData"), + "regionCodePublisher"); + IntermediateSimpleProperty property = new IntermediateSimpleProperty(nameBuilder, + jpaAttribute, helper.schema); + assertEquals("ISO", property.getEdmItem().getDefaultValue()); + } + + @Test + public void checkGetPropertyIsStream() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(PersonImage.class), + "image"); + IntermediateSimpleProperty property = new IntermediateSimpleProperty(nameBuilder, + jpaAttribute, helper.schema); + assertTrue(property.isStream()); + } + + @Test + public void checkGetPropertyIsTransientTrue() throws ODataJPAModelException, NoSuchFieldException, SecurityException { + + final Attribute jpaAttribute = new IntermediateStructuredType.TransientSingularAttribute<>(helper.getEntityType( + Person.class), Person.class.getDeclaredField("fullName")); + IntermediateSimpleProperty property = new IntermediateSimpleProperty(nameBuilder, + jpaAttribute, helper.schema); + assertTrue(property.isTransient()); + } + + @Test + public void checkGetPropertyIsTransientFalse() throws ODataJPAModelException, NoSuchFieldException, + SecurityException { + + final Attribute jpaAttribute = new IntermediateStructuredType.TransientSingularAttribute<>(helper.getEntityType( + Person.class), Person.class.getDeclaredField("lastName")); + IntermediateSimpleProperty property = new IntermediateSimpleProperty(nameBuilder, + jpaAttribute, helper.schema); + assertFalse(property.isTransient()); + } + + @Test + public void checkGetPropertyIsTransientThrowExceptionOnBeingKey() throws ODataJPAModelException, + NoSuchFieldException, SecurityException { + + final Attribute jpaAttribute = new IntermediateStructuredType.TransientSingularAttribute<>(errorHelper.getEntityType( + TeamWithTransientKey.class), TeamWithTransientKey.class.getDeclaredField("name")); + assertException(ODataJPAModelException.class, + () -> new IntermediateSimpleProperty(errorNameBuilder, jpaAttribute, errorHelper.schema), + TRANSIENT_KEY_NOT_SUPPORTED.getKey()); + } + + @Test + public void checkGetPropertyGetCalculatorPersistantIsNull() throws ODataJPAModelException, NoSuchFieldException, + SecurityException { + + final Attribute jpaAttribute = new IntermediateStructuredType.TransientSingularAttribute<>(helper.getEntityType( + Person.class), Person.class.getDeclaredField("lastName")); + IntermediateSimpleProperty property = new IntermediateSimpleProperty(nameBuilder, + jpaAttribute, helper.schema); + assertNull(property.getCalculatorConstructor()); + } + + @Test + public void checkGetPropertyGetCalculatorTransientNotNull() throws ODataJPAModelException, NoSuchFieldException, + SecurityException { + + final Attribute jpaAttribute = new IntermediateStructuredType.TransientSingularAttribute<>(helper.getEntityType( + Person.class), Person.class.getDeclaredField("fullName")); + IntermediateSimpleProperty property = new IntermediateSimpleProperty(nameBuilder, + jpaAttribute, helper.schema); + assertNotNull(property.getCalculatorConstructor()); + } + + @Test + public void checkGetPropertyGetCalculatorThrowExceptionOnMultipleConstructors() throws ODataJPAModelException, + NoSuchFieldException, SecurityException { + + final Attribute jpaAttribute = new IntermediateStructuredType.TransientSingularAttribute<>(errorHelper.getEntityType( + TeamWithTransientCalculatorError.class), TeamWithTransientCalculatorError.class.getDeclaredField( + "completeName")); + assertException(ODataJPAModelException.class, + () -> new IntermediateSimpleProperty(errorNameBuilder, jpaAttribute, errorHelper.schema), + TRANSIENT_CALCULATOR_TOO_MANY_CONSTRUCTORS.getKey()); + } + + @Test + public void checkGetPropertyGetCalculatorThrowExceptionOnWrongConstructors() throws ODataJPAModelException, + NoSuchFieldException, SecurityException { + + final Attribute jpaAttribute = new IntermediateStructuredType.TransientSingularAttribute<>(errorHelper.getEntityType( + TeamWithTransientCalculatorConstructorError.class), TeamWithTransientCalculatorConstructorError.class + .getDeclaredField("completeName")); + assertException(ODataJPAModelException.class, + () -> new IntermediateSimpleProperty(errorNameBuilder, jpaAttribute, errorHelper.schema), + TRANSIENT_CALCULATOR_WRONG_PARAMETER.getKey()); + } + + @Test + public void checkGetPropertyGetCalculatorNullOnPersistantProperty() throws ODataJPAModelException, + NoSuchFieldException, + SecurityException { + + final Attribute jpaAttribute = new IntermediateStructuredType.TransientSingularAttribute<>(helper.getEntityType( + Person.class), Person.class.getDeclaredField("lastName")); + IntermediateSimpleProperty property = new IntermediateSimpleProperty(nameBuilder, jpaAttribute, helper.schema); + assertNull(property.getCalculatorConstructor()); + } + + @Test + public void checkGetTypeBoxedForPrimitive() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(AdministrativeDivision.class), + "population"); + IntermediateSimpleProperty property = new IntermediateSimpleProperty(nameBuilder, + jpaAttribute, + helper.schema); + assertEquals(Long.class, property.getType()); + } + + @Test + public void checkGetTypeBoxed() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(AdministrativeDivision.class), + "area"); + IntermediateSimpleProperty property = new IntermediateSimpleProperty(nameBuilder, + jpaAttribute, + helper.schema); + assertEquals(Integer.class, property.getType()); + } + + @Test + public void checkThrowsAnExceptionTimestampWithoutPrecision() throws ODataJPAModelException { + // If Precision missing EdmDateTimeOffset.internalValueToString throws an exception => pre-check + final Attribute jpaAttribute = mock(Attribute.class); + final ManagedType jpaManagedType = mock(ManagedType.class); + when(jpaAttribute.getName()).thenReturn("start"); + when(jpaAttribute.getPersistentAttributeType()).thenReturn(PersistentAttributeType.BASIC); + when(jpaAttribute.getDeclaringType()).thenAnswer(new Answer>() { + @Override + public ManagedType answer(InvocationOnMock invocation) throws Throwable { + return jpaManagedType; + } + }); + when(jpaAttribute.getJavaType()).thenAnswer(new Answer>() { + @Override + public Class answer(InvocationOnMock invocation) throws Throwable { + return Timestamp.class; + } + }); + when(jpaManagedType.getJavaType()).thenAnswer(new Answer>() { + @Override + public Class answer(InvocationOnMock invocation) throws Throwable { + return DummyToBeIgnored.class; + } + }); + + Column column = mock(Column.class); + AnnotatedElement annotations = mock(AnnotatedElement.class, withSettings().extraInterfaces(Member.class)); + when(annotations.getAnnotation(Column.class)).thenReturn(column); + when(jpaAttribute.getJavaMember()).thenReturn((Member) annotations); + when(column.name()).thenReturn("Test"); + + IntermediateSimpleProperty property = new IntermediateSimpleProperty(nameBuilder, + jpaAttribute, + helper.schema); + + assertThrows(ODataJPAModelException.class, () -> { + property.getEdmItem(); + }); + } + + @Test + public void checkGetProptertyHasProtectionFalse() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(BusinessPartnerProtected.class), "eTag"); + IntermediatePropertyAccess property = new IntermediateSimpleProperty(nameBuilder, + jpaAttribute, helper.schema); + assertFalse(property.hasProtection()); + } + + @Test + public void checkGetProptertyHasProtectionTrue() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(BusinessPartnerProtected.class), + "username"); + IntermediatePropertyAccess property = new IntermediateSimpleProperty(nameBuilder, + jpaAttribute, helper.schema); + assertTrue(property.hasProtection()); + } + + @Test + public void checkGetProptertyProtectionSupportsWildCardTrue() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(BusinessPartnerProtected.class), + "username"); + IntermediateProperty property = new IntermediateSimpleProperty(nameBuilder, + jpaAttribute, helper.schema); + assertTrue(property.protectionWithWildcard("UserId", String.class)); + } + + // + @Test + public void checkGetProptertyProtectionSupportsWildCardFalse() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getAttribute(helper.getComplexType("InhouseAddressWithThreeProtections"), + "building"); + IntermediateProperty property = new IntermediateSimpleProperty(nameBuilder, + jpaAttribute, helper.schema); + assertFalse(property.protectionWithWildcard("BuildingNumber", String.class)); + } + + @Test + public void checkGetProptertyProtectionSupportsWildCardFalseNonString() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getAttribute(helper.getComplexType("InhouseAddressWithThreeProtections"), + "roomNumber"); + IntermediateProperty property = new IntermediateSimpleProperty(nameBuilder, + jpaAttribute, helper.schema); + assertFalse(property.protectionWithWildcard("RoomNumber", Integer.class)); + } + + @Test + public void checkGetProptertyProtectedAttributeClaimName() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(BusinessPartnerProtected.class), + "username"); + IntermediateProperty property = new IntermediateSimpleProperty(nameBuilder, + jpaAttribute, helper.schema); + assertEquals("UserId", property.getProtectionClaimNames().toArray(new String[] {})[0]); + assertNotNull(property.getProtectionPath("UserId")); + List actPath = property.getProtectionPath("UserId"); + assertEquals(1, actPath.size()); + assertEquals("Username", actPath.get(0)); + } + + @Test + public void checkGetProptertyNotProtectedAttributeClaimName() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(BusinessPartnerProtected.class), "eTag"); + IntermediateProperty property = new IntermediateSimpleProperty(nameBuilder, + jpaAttribute, helper.schema); + assertTrue(property.getProtectionClaimNames().isEmpty()); + assertTrue(property.getProtectionPath("Username").isEmpty()); + } + + @Test + public void checkGetComplexProptertyProtectedAttributeClaimName() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(BusinessPartnerProtected.class), + "administrativeInformation"); + + EdmProtectedBy annotation = Mockito.mock(EdmProtectedBy.class); + when(annotation.name()).thenReturn("UserId"); + when(annotation.path()).thenReturn("created/by"); + + MemberDouble memberSpy = new MemberDouble(jpaAttribute.getJavaMember()); + memberSpy.addAnnotation(EdmProtectedBy.class, annotation); + Attribute attributeSpy = Mockito.spy(jpaAttribute); + when(attributeSpy.getJavaMember()).thenReturn(memberSpy); + + IntermediateProperty property = new IntermediateSimpleProperty(nameBuilder, + attributeSpy, helper.schema); + assertEquals("UserId", property.getProtectionClaimNames().toArray(new String[] {})[0]); + assertNotNull(property.getProtectionPath("UserId")); + List actPath = property.getProtectionPath("UserId"); + assertEquals(1, actPath.size()); + assertEquals("AdministrativeInformation/Created/By", actPath.get(0)); + } + + @Test + public void checkGetComplexProptertyTwoProtectedAttributeClaimName() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(BusinessPartnerProtected.class), + "administrativeInformation"); + + EdmProtections protections = Mockito.mock(EdmProtections.class); + EdmProtectedBy protectedBy1 = Mockito.mock(EdmProtectedBy.class); + when(protectedBy1.name()).thenReturn("UserId"); + when(protectedBy1.path()).thenReturn("created/by"); + + EdmProtectedBy protectedBy2 = Mockito.mock(EdmProtectedBy.class); + when(protectedBy2.name()).thenReturn("UserId"); + when(protectedBy2.path()).thenReturn("updated/by"); + + when(protections.value()).thenReturn(new EdmProtectedBy[] { protectedBy1, protectedBy2 }); + + MemberDouble memberSpy = new MemberDouble(jpaAttribute.getJavaMember()); + memberSpy.addAnnotation(EdmProtections.class, protections); + Attribute attributeSpy = Mockito.spy(jpaAttribute); + when(attributeSpy.getJavaMember()).thenReturn(memberSpy); + + IntermediateProperty property = new IntermediateSimpleProperty(nameBuilder, + attributeSpy, helper.schema); + assertEquals("UserId", property.getProtectionClaimNames().toArray(new String[] {})[0]); + assertNotNull(property.getProtectionPath("UserId")); + + List actPath = property.getProtectionPath("UserId"); + assertEquals(2, actPath.size()); + assertEquals("AdministrativeInformation/Created/By", actPath.get(0)); + assertEquals("AdministrativeInformation/Updated/By", actPath.get(1)); + } + + @Test + public void checkGetComplexProptertyTwoProtectedAttributeTwoClaimName() throws ODataJPAModelException { + Attribute jpaAttribute = helper.getAttribute(helper.getEntityType(BusinessPartnerProtected.class), + "administrativeInformation"); + + EdmProtections protections = Mockito.mock(EdmProtections.class); + EdmProtectedBy protectedBy1 = Mockito.mock(EdmProtectedBy.class); + when(protectedBy1.name()).thenReturn("UserId"); + when(protectedBy1.path()).thenReturn("created/by"); + + EdmProtectedBy protectedBy2 = Mockito.mock(EdmProtectedBy.class); + when(protectedBy2.name()).thenReturn("Date"); + when(protectedBy2.path()).thenReturn("created/at"); + + when(protections.value()).thenReturn(new EdmProtectedBy[] { protectedBy1, protectedBy2 }); + + MemberDouble memberSpy = new MemberDouble(jpaAttribute.getJavaMember()); + memberSpy.addAnnotation(EdmProtections.class, protections); + Attribute attributeSpy = Mockito.spy(jpaAttribute); + when(attributeSpy.getJavaMember()).thenReturn(memberSpy); + + IntermediateProperty property = new IntermediateSimpleProperty(nameBuilder, + attributeSpy, helper.schema); + + assertTrue(property.getProtectionClaimNames().contains("UserId")); + List actPath = property.getProtectionPath("UserId"); + assertEquals(1, actPath.size()); + assertEquals("AdministrativeInformation/Created/By", actPath.get(0)); + + assertTrue(property.getProtectionClaimNames().contains("Date")); + actPath = property.getProtectionPath("Date"); + assertEquals(1, actPath.size()); + assertEquals("AdministrativeInformation/Created/At", actPath.get(0)); + } + + @Disabled + @Test + public void checkGetSRID() { + // Test for spatial data missing + } + + private class PostProcessorSetName extends JPAEdmMetadataPostProcessor { + + @Override + public void processProperty(IntermediatePropertyAccess property, String jpaManagedTypeClassName) { + if (jpaManagedTypeClassName.equals( + "com.sap.olingo.jpa.processor.core.testmodel.BusinessPartner")) { + if (property.getInternalName().equals("customString1")) { + property.setExternalName("ContactPersonName"); + } + } + } + + @Override + public void processNavigationProperty(IntermediateNavigationPropertyAccess property, + String jpaManagedTypeClassName) {} + + @Override + public void provideReferences(IntermediateReferenceList references) throws ODataJPAModelException {} + + @Override + public void processEntityType(IntermediateEntityTypeAccess entity) {} + } +} diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateWrongAnnotation.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateWrongAnnotation.java new file mode 100644 index 000000000..5cb21cbb8 --- /dev/null +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestIntermediateWrongAnnotation.java @@ -0,0 +1,179 @@ +package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; + +import static com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException.MessageKeys.COMPLEX_PROPERTY_MISSING_PROTECTION_PATH; +import static com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException.MessageKeys.COMPLEX_PROPERTY_WRONG_PROTECTION_PATH; +import static com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException.MessageKeys.NOT_SUPPORTED_KEY_PART_OF_GROUP; +import static com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException.MessageKeys.NOT_SUPPORTED_MANDATORY_PART_OF_GROUP; +import static com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException.MessageKeys.NOT_SUPPORTED_NAVIGATION_PART_OF_GROUP; +import static com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException.MessageKeys.NOT_SUPPORTED_PROTECTED_COLLECTION; +import static com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException.MessageKeys.NOT_SUPPORTED_PROTECTED_NAVIGATION; +import static com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException.MessageKeys.PROPERTY_REQUIRED_UNKNOWN; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import javax.persistence.EntityManagerFactory; +import javax.persistence.metamodel.Attribute; +import javax.persistence.metamodel.EntityType; +import javax.persistence.metamodel.PluralAttribute; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import com.sap.olingo.jpa.metadata.api.JPAEntityManagerFactory; +import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; +import com.sap.olingo.jpa.processor.core.errormodel.CollectionAttributeProtected; +import com.sap.olingo.jpa.processor.core.errormodel.ComplextProtectedNoPath; +import com.sap.olingo.jpa.processor.core.errormodel.ComplextProtectedWrongPath; +import com.sap.olingo.jpa.processor.core.errormodel.EmbeddedKeyPartOfGroup; +import com.sap.olingo.jpa.processor.core.errormodel.KeyPartOfGroup; +import com.sap.olingo.jpa.processor.core.errormodel.MandatoryPartOfGroup; +import com.sap.olingo.jpa.processor.core.errormodel.NavigationAttributeProtected; +import com.sap.olingo.jpa.processor.core.errormodel.NavigationPropertyPartOfGroup; +import com.sap.olingo.jpa.processor.core.errormodel.PersonDeepCollectionProtected; +import com.sap.olingo.jpa.processor.core.errormodel.TeamWithTransientError; +import com.sap.olingo.jpa.processor.core.testmodel.DataSourceHelper; + +public class TestIntermediateWrongAnnotation { + private TestHelper helper; + protected static final String PUNIT_NAME = "error"; + protected static EntityManagerFactory emf; + + @BeforeEach + public void setup() throws ODataJPAModelException { + emf = JPAEntityManagerFactory.getEntityManagerFactory(PUNIT_NAME, DataSourceHelper.createDataSource( + DataSourceHelper.DB_HSQLDB)); + helper = new TestHelper(emf.getMetamodel(), PUNIT_NAME); + } + + @Test + public void checkErrorOnProtectedCollectionAttribute() { + final PluralAttribute jpaAttribute = helper.getCollectionAttribute(helper.getEntityType( + CollectionAttributeProtected.class), "inhouseAddress"); + final IntermediateStructuredType entityType = helper.schema.getEntityType(CollectionAttributeProtected.class); + + final ODataJPAModelException act = assertThrows(ODataJPAModelException.class, + () -> new IntermediateCollectionProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), + jpaAttribute, helper.schema, entityType)); + + assertEquals(NOT_SUPPORTED_PROTECTED_COLLECTION.name(), act.getId()); + assertFalse(act.getMessage().isEmpty()); + + } + + @Test + public void checkErrorOnProtectedCollectionAttributeDeep() { + final PluralAttribute jpaAttribute = helper.getCollectionAttribute(helper.getEntityType( + PersonDeepCollectionProtected.class), "inhouseAddress"); + final IntermediateStructuredType entityType = helper.schema.getEntityType(PersonDeepCollectionProtected.class); + + final ODataJPAModelException act = assertThrows(ODataJPAModelException.class, + () -> new IntermediateCollectionProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), + jpaAttribute, helper.schema, entityType)); + + assertEquals(NOT_SUPPORTED_PROTECTED_COLLECTION.name(), act.getId()); + assertFalse(act.getMessage().isEmpty()); + } + + @Test + public void checkErrorOnProtectedNavigationAttribute() { + final Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType( + NavigationAttributeProtected.class), "teams"); + + final ODataJPAModelException act = assertThrows(ODataJPAModelException.class, + () -> new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), + helper.schema.getEntityType(NavigationAttributeProtected.class), jpaAttribute, helper.schema)); + + assertEquals(NOT_SUPPORTED_PROTECTED_NAVIGATION.name(), act.getId()); + assertFalse(act.getMessage().isEmpty()); + } + + @Test + public void checkErrorOnProtectedComplexAttributeMissingPath() { + final Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType( + ComplextProtectedNoPath.class), + "administrativeInformation"); + + final ODataJPAModelException act = assertThrows(ODataJPAModelException.class, + () -> new IntermediateSimpleProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), jpaAttribute, helper.schema)); + + assertEquals(COMPLEX_PROPERTY_MISSING_PROTECTION_PATH.name(), act.getId()); + assertFalse(act.getMessage().isEmpty()); + } + + @Test + public void checkErrorOnProtectedComplexAttributeWrongPath() throws ODataJPAModelException { + // ComplextProtectedWrongPath + final EntityType jpaEt = helper.getEntityType(ComplextProtectedWrongPath.class); + final IntermediateEntityType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), jpaEt, + helper.schema); + et.getEdmItem(); + + final ODataJPAModelException act = assertThrows(ODataJPAModelException.class, + () -> et.getProtections()); + + assertEquals(COMPLEX_PROPERTY_WRONG_PROTECTION_PATH.name(), act.getId()); + assertFalse(act.getMessage().isEmpty()); + + } + + @Test + public void checkErrorOnNavigationPropertyPartOfGroup() throws ODataJPAModelException { + final Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType( + NavigationPropertyPartOfGroup.class), "teams"); + final IntermediateStructuredType entityType = helper.schema.getEntityType(NavigationPropertyPartOfGroup.class); + + final ODataJPAModelException act = assertThrows(ODataJPAModelException.class, + () -> new IntermediateNavigationProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), entityType, jpaAttribute, + helper.schema)); + + assertEquals(NOT_SUPPORTED_NAVIGATION_PART_OF_GROUP.name(), act.getId()); + assertFalse(act.getMessage().isEmpty()); + } + + @Test + public void checkErrorOnMandatoryPropertyPartOfGroup() throws ODataJPAModelException { + final Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType( + MandatoryPartOfGroup.class), "eTag"); + + final ODataJPAModelException act = assertThrows(ODataJPAModelException.class, + () -> new IntermediateSimpleProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), jpaAttribute, helper.schema)); + + assertEquals(NOT_SUPPORTED_MANDATORY_PART_OF_GROUP.name(), act.getId()); + assertFalse(act.getMessage().isEmpty()); + } + + @Test + public void checkErrorOnKeyPropertyPartOfGroup() throws ODataJPAModelException { + final Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType( + KeyPartOfGroup.class), "iD"); + + final ODataJPAModelException act = assertThrows(ODataJPAModelException.class, + () -> new IntermediateSimpleProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), jpaAttribute, helper.schema)); + + assertEquals(NOT_SUPPORTED_KEY_PART_OF_GROUP.name(), act.getId()); + assertFalse(act.getMessage().isEmpty()); + } + + @Test + public void checkErrorOnEmbeddedKeyPropertyPartOfGroup() throws ODataJPAModelException { + final Attribute jpaAttribute = helper.getDeclaredAttribute(helper.getEntityType( + EmbeddedKeyPartOfGroup.class), "key"); + + final ODataJPAModelException act = assertThrows(ODataJPAModelException.class, + () -> new IntermediateSimpleProperty(new JPADefaultEdmNameBuilder(PUNIT_NAME), jpaAttribute, helper.schema)); + + assertEquals(NOT_SUPPORTED_KEY_PART_OF_GROUP.name(), act.getId()); + assertFalse(act.getMessage().isEmpty()); + } + + @Test + public void checkErrorOnTransientFieldWithUnknownRequired() { + final EntityType jpaEt = helper.getEntityType(TeamWithTransientError.class); + final IntermediateEntityType et = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), jpaEt, + helper.schema); + final ODataJPAModelException act = assertThrows(ODataJPAModelException.class, + () -> et.getEdmItem()); + assertEquals(PROPERTY_REQUIRED_UNKNOWN.name(), act.getId()); + } +} diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestJPAEdmNameBuilder.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestJPAEdmNameBuilder.java index 6b217067e..1dece615a 100644 --- a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestJPAEdmNameBuilder.java +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestJPAEdmNameBuilder.java @@ -1,30 +1,29 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; -import com.sap.olingo.jpa.metadata.core.edm.mapper.impl.JPAEdmNameBuilder; public class TestJPAEdmNameBuilder { - private JPAEdmNameBuilder cut; + private JPADefaultEdmNameBuilder cut; - @Before + @BeforeEach public void setup() throws ODataJPAModelException { } @Test public void CheckBuildContainerNameSimple() { - cut = new JPAEdmNameBuilder("cdw"); + cut = new JPADefaultEdmNameBuilder("cdw"); assertEquals("CdwContainer", cut.buildContainerName()); } @Test public void CheckBuildContainerNameComplex() { - cut = new JPAEdmNameBuilder("org.apache.olingo.jpa"); + cut = new JPADefaultEdmNameBuilder("org.apache.olingo.jpa"); assertEquals("OrgApacheOlingoJpaContainer", cut.buildContainerName()); } } diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestJPAOnConditionItemImpl.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestJPAOnConditionItemImpl.java new file mode 100644 index 000000000..3fefd4c2f --- /dev/null +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestJPAOnConditionItemImpl.java @@ -0,0 +1,42 @@ +package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.mock; + +import org.junit.jupiter.api.Test; + +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAPath; +import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; +import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException.MessageKeys; + +public class TestJPAOnConditionItemImpl { + private JPAOnConditionItemImpl cut; + + @Test + public void checkThowsExceptionOnMissingLeft() { + final JPAPath rightAttribute = mock(JPAPath.class); + + final ODataJPAModelException act = assertThrows(ODataJPAModelException.class, + () -> new JPAOnConditionItemImpl(null, rightAttribute)); + assertEquals(MessageKeys.ON_LEFT_ATTRIBUTE_NULL.getKey(), act.getId()); + } + + @Test + public void checkThowsExceptionOnMissingRight() { + final JPAPath leftAttribute = mock(JPAPath.class); + + final ODataJPAModelException act = assertThrows(ODataJPAModelException.class, + () -> new JPAOnConditionItemImpl(leftAttribute, null)); + assertEquals(MessageKeys.ON_RIGHT_ATTRIBUTE_NULL.getKey(), act.getId()); + } + + @Test + public void checkReturnProvidedValuse() throws ODataJPAModelException { + final JPAPath leftAttribute = mock(JPAPath.class); + final JPAPath rightAttribute = mock(JPAPath.class); + cut = new JPAOnConditionItemImpl(leftAttribute, rightAttribute); + assertEquals(leftAttribute, cut.getLeftPath()); + assertEquals(rightAttribute, cut.getRightPath()); + } +} diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestJPAPath.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestJPAPath.java index 01537bce1..c636ab6f8 100644 --- a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestJPAPath.java +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestJPAPath.java @@ -1,27 +1,41 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; -import static org.junit.Assert.assertEquals; +import static com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException.MessageKeys.NOT_SUPPORTED_MIXED_PART_OF_GROUP; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import org.apache.olingo.server.api.ODataApplicationException; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAElement; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEntityType; import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAPath; import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; -import com.sap.olingo.jpa.metadata.core.edm.mapper.impl.IntermediateEntityType; -import com.sap.olingo.jpa.metadata.core.edm.mapper.impl.JPAEdmNameBuilder; +import com.sap.olingo.jpa.processor.core.testmodel.BusinessPartnerWithGroups; +import com.sap.olingo.jpa.processor.core.testmodel.Organization; public class TestJPAPath extends TestMappingRoot { private JPAEntityType organization; - // private JPAStructuredType postalAddress; + private JPAEntityType bupaWithGroup; private TestHelper helper; - @Before + @BeforeEach public void setup() throws ODataJPAModelException { helper = new TestHelper(emf.getMetamodel(), PUNIT_NAME); - organization = new IntermediateEntityType(new JPAEdmNameBuilder(PUNIT_NAME), helper.getEntityType( - "Organization"), helper.schema); + organization = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), helper.getEntityType( + Organization.class), helper.schema); + bupaWithGroup = new IntermediateEntityType(new JPADefaultEdmNameBuilder(PUNIT_NAME), helper.getEntityType( + BusinessPartnerWithGroups.class), helper.schema); } @Test @@ -87,4 +101,132 @@ public void checkThreePathElementPathElements() throws ODataApplicationException assertEquals("by", cut.getPath().get(2).getInternalName()); } + @Test + public void checkIsPartOfGroupReturnsTrueOnNotAnnotated() throws ODataJPAModelException { + + final JPAPath act = bupaWithGroup.getPath("Type"); + assertTrue(act.isPartOfGroups(Arrays.asList("Test"))); + } + + @Test + public void checkIsPartOfGroupReturnsTrueOnAnnotatedBelogsToIt() throws ODataJPAModelException { + + final JPAPath act = bupaWithGroup.getPath("Country"); + assertTrue(act.isPartOfGroups(Arrays.asList("Person"))); + } + + @Test + public void checkIsPartOfGroupCheckTwice() throws ODataJPAModelException { + + final JPAPath act = bupaWithGroup.getPath("Country"); + assertTrue(act.isPartOfGroups(Arrays.asList("Person"))); + assertTrue(act.isPartOfGroups(Arrays.asList("Person"))); + } + + @Test + public void checkIsPartOfGroupReturnsFalseOnAnnotatedDoesNotBelogsToIt() throws ODataJPAModelException { + + final JPAPath act = bupaWithGroup.getPath("Country"); + assertFalse(act.isPartOfGroups(Arrays.asList("Test"))); + } + + @Test + public void checkIsPartOfGroupReturnsFalseOnAnnotatedComplex() throws ODataJPAModelException { + + final JPAPath act = bupaWithGroup.getPath("CommunicationData/Email"); + assertFalse(act.isPartOfGroups(Arrays.asList("Test"))); + + } + + @Test + public void checkIsPartOfGroupReturnsTrueOnNotAnnotatedComplex() throws ODataJPAModelException { + + final JPAPath act = organization.getPath("CommunicationData/Email"); + assertTrue(act.isPartOfGroups(Arrays.asList("Test"))); + } + + @Test + public void checkThrowsExceptionOnInconsistentGroups1() { + final List attributes = new ArrayList<>(2); + + final IntermediateProperty complex = mock(IntermediateProperty.class); + when(complex.isPartOfGroup()).thenReturn(true); + when(complex.getGroups()).thenReturn(Arrays.asList("Test", "Dummy")); + attributes.add(complex); + + final IntermediateProperty primitive = mock(IntermediateProperty.class); + when(primitive.isPartOfGroup()).thenReturn(true); + when(primitive.getGroups()).thenReturn(Arrays.asList("Dummy")); + attributes.add(primitive); + + final ODataJPAModelException act = assertThrows(ODataJPAModelException.class, + () -> new JPAPathImpl("Communication/Email", "Telecom.Email", attributes)); + + assertEquals(NOT_SUPPORTED_MIXED_PART_OF_GROUP.getKey(), act.getId()); + assertFalse(act.getMessage().isEmpty()); + } + + @Test + public void checkThrowsExceptionOnInconsistentGroups2() { + final List attributes = new ArrayList<>(2); + + final IntermediateProperty complex = mock(IntermediateProperty.class); + when(complex.isPartOfGroup()).thenReturn(true); + when(complex.getGroups()).thenReturn(Arrays.asList("Test", "Dummy")); + attributes.add(complex); + + final IntermediateProperty primitive = mock(IntermediateProperty.class); + when(primitive.isPartOfGroup()).thenReturn(true); + when(primitive.getGroups()).thenReturn(Arrays.asList("Dummy", "Willi")); + attributes.add(primitive); + + final ODataJPAModelException act = assertThrows(ODataJPAModelException.class, + () -> new JPAPathImpl("Communication/Email", "Telecom.Email", attributes)); + + assertEquals(NOT_SUPPORTED_MIXED_PART_OF_GROUP.getKey(), act.getId()); + assertFalse(act.getMessage().isEmpty()); + } + + @Test + public void checkThrowsExceptionOnInconsistentGroups3() { + final List attributes = new ArrayList<>(2); + + final IntermediateProperty complex = mock(IntermediateProperty.class); + when(complex.isPartOfGroup()).thenReturn(true); + when(complex.getGroups()).thenReturn(Arrays.asList("Test", "Dummy")); + attributes.add(complex); + + final IntermediateProperty primitive = mock(IntermediateProperty.class); + when(primitive.isPartOfGroup()).thenReturn(true); + when(primitive.getGroups()).thenReturn(Arrays.asList("Dummy", "Test", "Willi")); + attributes.add(primitive); + + final ODataJPAModelException act = assertThrows(ODataJPAModelException.class, + () -> new JPAPathImpl("Communication/Email", "Telecom.Email", attributes)); + + assertEquals(NOT_SUPPORTED_MIXED_PART_OF_GROUP.getKey(), act.getId()); + assertFalse(act.getMessage().isEmpty()); + } + + @Test + public void checkTwoNotEqualIfAliasNotEqual() throws ODataApplicationException, ODataJPAModelException { + final JPAPath cut = organization.getPath("Address/Country"); + final JPAPath act = new JPAPathImpl("Address", cut.getDBFieldName(), cut.getPath()); + assertNotEquals(act, cut); + } + + @Test + public void checkTwoNotEqualIfElementListNotEqual() throws ODataApplicationException, ODataJPAModelException { + final JPAPath cut = organization.getPath("Address/Country"); + final List pathList = new ArrayList<>(cut.getPath()); + pathList.remove(0); + final JPAPath act = new JPAPathImpl("Address/Country", cut.getDBFieldName(), pathList); + assertNotEquals(act, cut); + } + + @Test + public void checkTwoEqualIfSame() throws ODataApplicationException, ODataJPAModelException { + final JPAPath cut = organization.getPath("Address/Country"); + assertEquals(cut, cut); + } } diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestJPAProtectionInfo.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestJPAProtectionInfo.java new file mode 100644 index 000000000..87e1a5e0b --- /dev/null +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestJPAProtectionInfo.java @@ -0,0 +1,64 @@ +/** + * + */ +package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.time.LocalDate; +import java.util.Arrays; +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * @author Oliver Grande + * Created: 14.02.2020 + * + */ +public class TestJPAProtectionInfo { + private JPAProtectionInfo cut; + + @BeforeEach + public void setup() { + cut = new JPAProtectionInfo(Arrays.asList("AdministrativeInformation/Created/By"), true); + } + + @Test + public void checkToStringContainsPath() { + assertNotNull(cut.toString()); + assertTrue(cut.toString().contains("AdministrativeInformation/Created/By")); + } + + @Test + public void checkWildcardsTrue() { + assertTrue(cut.supportsWildcards()); + } + + @Test + public void checkPathGetsReturned() { + final List act = cut.getPath(); + assertNotNull(act); + assertEquals(1, act.size()); + assertEquals("AdministrativeInformation/Created/By", act.get(0)); + } + + @Test + public void checkWildcardsReturnsFalseForInteger() { + assertFalse(cut.supportsWildcards(Integer.class)); + } + + @Test + public void checkWildcardsReturnsFalseForDate() { + assertFalse(cut.supportsWildcards(LocalDate.class)); + } + + @Test + public void checkWildcardsReturnsTrueForString() { + assertTrue(cut.supportsWildcards(String.class)); + } +} diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestJPATypeConvertor.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestJPATypeConvertor.java new file mode 100644 index 000000000..d97ca7c44 --- /dev/null +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestJPATypeConvertor.java @@ -0,0 +1,339 @@ +package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.params.provider.Arguments.arguments; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Member; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.sql.Blob; +import java.sql.Clob; +import java.sql.Timestamp; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZonedDateTime; +import java.util.Calendar; +import java.util.UUID; +import java.util.stream.Stream; + +import javax.persistence.Lob; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import javax.persistence.metamodel.Attribute; + +import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind; +import org.apache.olingo.commons.api.edm.geo.Geospatial.Dimension; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.Mockito; + +import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmGeospatial; +import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; + +public class TestJPATypeConvertor { + + static Stream mappingJavaLobToOData() { + + return Stream.of( + arguments(Blob.class, buildLobAttribute(), EdmPrimitiveTypeKind.Binary), + arguments(Clob.class, buildLobAttribute(), EdmPrimitiveTypeKind.String)); + } + + static Stream mappingJavaTimeToOData() { + return Stream.of( + arguments(java.time.LocalTime.class, null, EdmPrimitiveTypeKind.TimeOfDay), + arguments(java.sql.Time.class, null, EdmPrimitiveTypeKind.TimeOfDay), + arguments(java.time.Duration.class, null, EdmPrimitiveTypeKind.Duration), + arguments(java.time.LocalDate.class, null, EdmPrimitiveTypeKind.Date), + arguments(java.sql.Date.class, null, EdmPrimitiveTypeKind.Date), + arguments(Calendar.class, null, EdmPrimitiveTypeKind.DateTimeOffset), + arguments(Calendar.class, buildTimeAttribute(TemporalType.TIME), EdmPrimitiveTypeKind.TimeOfDay), + arguments(Calendar.class, buildTimeAttribute(TemporalType.DATE), EdmPrimitiveTypeKind.Date), + arguments(Calendar.class, buildTimeAttribute(TemporalType.TIMESTAMP), EdmPrimitiveTypeKind.DateTimeOffset), + arguments(Calendar.class, buildTimeAttribute(null), EdmPrimitiveTypeKind.DateTimeOffset), + arguments(Timestamp.class, null, EdmPrimitiveTypeKind.DateTimeOffset), + arguments(Timestamp.class, buildTimeAttribute(TemporalType.TIME), EdmPrimitiveTypeKind.TimeOfDay), + arguments(Timestamp.class, buildTimeAttribute(TemporalType.DATE), EdmPrimitiveTypeKind.Date), + arguments(Timestamp.class, buildTimeAttribute(TemporalType.TIMESTAMP), EdmPrimitiveTypeKind.DateTimeOffset), + arguments(Timestamp.class, buildTimeAttribute(null), EdmPrimitiveTypeKind.DateTimeOffset), + arguments(java.util.Date.class, null, EdmPrimitiveTypeKind.DateTimeOffset), + arguments(java.util.Date.class, buildTimeAttribute(TemporalType.TIME), EdmPrimitiveTypeKind.TimeOfDay), + arguments(java.util.Date.class, buildTimeAttribute(TemporalType.DATE), EdmPrimitiveTypeKind.Date), + arguments(java.util.Date.class, buildTimeAttribute(TemporalType.TIMESTAMP), + EdmPrimitiveTypeKind.DateTimeOffset), + arguments(java.time.OffsetDateTime.class, buildTimeAttribute(null), EdmPrimitiveTypeKind.DateTimeOffset), + arguments(java.time.LocalDateTime.class, buildTimeAttribute(null), EdmPrimitiveTypeKind.DateTimeOffset), + arguments(java.time.ZonedDateTime.class, buildTimeAttribute(null), EdmPrimitiveTypeKind.DateTimeOffset)); + } + + static Stream mappingSimpleJavaToOData() { + return Stream.of( + arguments(Long.class, EdmPrimitiveTypeKind.Int64), + arguments(long.class, EdmPrimitiveTypeKind.Int64), + arguments(Integer.class, EdmPrimitiveTypeKind.Int32), + arguments(int.class, EdmPrimitiveTypeKind.Int32), + arguments(Short.class, EdmPrimitiveTypeKind.Int16), + arguments(short.class, EdmPrimitiveTypeKind.Int16), + arguments(String.class, EdmPrimitiveTypeKind.String), + arguments(Character.class, EdmPrimitiveTypeKind.String), + arguments(char.class, EdmPrimitiveTypeKind.String), + arguments(char[].class, EdmPrimitiveTypeKind.String), + arguments(Character[].class, EdmPrimitiveTypeKind.String), + arguments(Double.class, EdmPrimitiveTypeKind.Double), + arguments(double.class, EdmPrimitiveTypeKind.Double), + arguments(Float.class, EdmPrimitiveTypeKind.Single), + arguments(float.class, EdmPrimitiveTypeKind.Single), + arguments(BigDecimal.class, EdmPrimitiveTypeKind.Decimal), + arguments(Byte.class, EdmPrimitiveTypeKind.SByte), + arguments(byte.class, EdmPrimitiveTypeKind.SByte), + arguments(byte[].class, EdmPrimitiveTypeKind.Binary), + arguments(Boolean.class, EdmPrimitiveTypeKind.Boolean), + arguments(boolean.class, EdmPrimitiveTypeKind.Boolean), + arguments(UUID.class, EdmPrimitiveTypeKind.Guid)); + } + + static Stream mappingJavaGeographyToOData() { + return Stream.of( + arguments(org.apache.olingo.commons.api.edm.geo.Point.class, buildDimensionAttribute(Dimension.GEOGRAPHY), + EdmPrimitiveTypeKind.GeographyPoint), + arguments(org.apache.olingo.commons.api.edm.geo.MultiPoint.class, buildDimensionAttribute(Dimension.GEOGRAPHY), + EdmPrimitiveTypeKind.GeographyMultiPoint), + arguments(org.apache.olingo.commons.api.edm.geo.LineString.class, buildDimensionAttribute(Dimension.GEOGRAPHY), + EdmPrimitiveTypeKind.GeographyLineString), + arguments(org.apache.olingo.commons.api.edm.geo.MultiLineString.class, buildDimensionAttribute( + Dimension.GEOGRAPHY), + EdmPrimitiveTypeKind.GeographyMultiLineString), + arguments(org.apache.olingo.commons.api.edm.geo.Polygon.class, buildDimensionAttribute(Dimension.GEOGRAPHY), + EdmPrimitiveTypeKind.GeographyPolygon), + arguments(org.apache.olingo.commons.api.edm.geo.MultiPolygon.class, buildDimensionAttribute( + Dimension.GEOGRAPHY), + EdmPrimitiveTypeKind.GeographyMultiPolygon), + arguments(org.apache.olingo.commons.api.edm.geo.GeospatialCollection.class, buildDimensionAttribute( + Dimension.GEOGRAPHY), + EdmPrimitiveTypeKind.GeographyCollection) + + ); + } + + static Stream mappingJavaGeometryToOData() { + return Stream.of( + arguments(org.apache.olingo.commons.api.edm.geo.Point.class, buildDimensionAttribute(Dimension.GEOMETRY), + EdmPrimitiveTypeKind.GeometryPoint), + arguments(org.apache.olingo.commons.api.edm.geo.MultiPoint.class, buildDimensionAttribute(Dimension.GEOMETRY), + EdmPrimitiveTypeKind.GeometryMultiPoint), + arguments(org.apache.olingo.commons.api.edm.geo.LineString.class, buildDimensionAttribute(Dimension.GEOMETRY), + EdmPrimitiveTypeKind.GeometryLineString), + arguments(org.apache.olingo.commons.api.edm.geo.MultiLineString.class, buildDimensionAttribute( + Dimension.GEOMETRY), + EdmPrimitiveTypeKind.GeometryMultiLineString), + arguments(org.apache.olingo.commons.api.edm.geo.Polygon.class, buildDimensionAttribute(Dimension.GEOMETRY), + EdmPrimitiveTypeKind.GeometryPolygon), + arguments(org.apache.olingo.commons.api.edm.geo.MultiPolygon.class, buildDimensionAttribute( + Dimension.GEOMETRY), + EdmPrimitiveTypeKind.GeometryMultiPolygon), + arguments(org.apache.olingo.commons.api.edm.geo.GeospatialCollection.class, buildDimensionAttribute( + Dimension.GEOMETRY), + EdmPrimitiveTypeKind.GeometryCollection) + + ); + } + + static Stream scalarJavaTypes() { + return Stream.of( + arguments(Integer.class, null, true), + arguments(String.class, null, true), + arguments(Character.class, null, true), + arguments(Long.class, null, true), + arguments(Short.class, null, true), + arguments(Integer.class, null, true), + arguments(Double.class, null, true), + arguments(Float.class, null, true), + arguments(BigDecimal.class, null, true), + arguments(Byte.class, null, true), + arguments(Boolean.class, null, true), + arguments(java.time.LocalTime.class, null, true), + arguments(java.sql.Time.class, null, true), + arguments(java.time.Duration.class, null, true), + arguments(java.time.LocalDate.class, null, true), + arguments(java.sql.Date.class, null, true), + arguments(Calendar.class, null, true), + arguments(Timestamp.class, null, true), + arguments(java.util.Date.class, null, true), + arguments(UUID.class, null, true), + arguments(Attribute.class, null, false)); + } + + static Stream supportedByOlingo() { + + return Stream.of( + arguments(Boolean.class, true), + arguments(Byte.class, true), + arguments(Byte[].class, true), + arguments(byte[].class, true), + arguments(Double.class, true), + arguments(Float.class, true), + arguments(Integer.class, true), + arguments(java.math.BigDecimal.class, true), + arguments(java.math.BigInteger.class, true), + arguments(java.sql.Time.class, true), + arguments(java.sql.Timestamp.class, true), + arguments(java.util.Calendar.class, true), + arguments(java.util.Date.class, true), + arguments(java.util.UUID.class, true), + arguments(Long.class, true), + arguments(Short.class, true), + arguments(String.class, true), + arguments(LocalDate.class, true), + arguments(LocalTime.class, true), + arguments(ZonedDateTime.class, true), + arguments(LocalDateTime.class, false)); + } + + static Stream simpleJavaTypes() { + return Stream.concat(scalarJavaTypes(), Stream.of( + arguments(Integer.class, null, true))); + } + + private static Attribute buildLobAttribute() { + final Attribute a = mock(Attribute.class); + final AnnotatedElement e = mock(AnnotatedElement.class, Mockito.withSettings().extraInterfaces(Member.class)); + final Lob l = mock(Lob.class); + + when(a.getJavaMember()).thenReturn((Member) e); + when(e.getAnnotation(Lob.class)).thenReturn(l); + when(a.getName()).thenReturn("Lob"); + return a; + } + + private static Attribute buildTimeAttribute(final TemporalType time) { + final Attribute a = mock(Attribute.class); + final AnnotatedElement e = mock(AnnotatedElement.class, Mockito.withSettings().extraInterfaces(Member.class)); + final Temporal t = mock(Temporal.class); + + when(a.getJavaMember()).thenReturn((Member) e); + when(e.getAnnotation(Temporal.class)).thenReturn(t); + when(t.value()).thenReturn(time); + + return a; + } + + private static Attribute buildDimensionAttribute(final Dimension dimension) { + final Attribute a = mock(Attribute.class); + final AnnotatedElement e = mock(AnnotatedElement.class, Mockito.withSettings().extraInterfaces(Member.class)); + final EdmGeospatial g = mock(EdmGeospatial.class); + + when(a.getJavaMember()).thenReturn((Member) e); + when(e.getAnnotation(EdmGeospatial.class)).thenReturn(g); + when(g.dimension()).thenReturn(dimension); + + return a; + } + + @ParameterizedTest + @MethodSource("mappingJavaGeographyToOData") + public void checkConvertJavaGeographyToOData(final Class javaType, final Attribute jpaAttribute, + final EdmPrimitiveTypeKind ODataType) throws ODataJPAModelException { + + assertEquals(ODataType, JPATypeConvertor.convertToEdmSimpleType(javaType, jpaAttribute)); + final ODataJPAModelException act = assertThrows(ODataJPAModelException.class, + () -> JPATypeConvertor.convertToEdmSimpleType(javaType, buildTimeAttribute(TemporalType.TIME))); + assertEquals(ODataJPAModelException.MessageKeys.TYPE_NOT_SUPPORTED.getKey(), act.getId()); + } + + @ParameterizedTest + @MethodSource("mappingJavaGeometryToOData") + public void checkConvertJavaGemetryToOData(final Class javaType, final Attribute jpaAttribute, + final EdmPrimitiveTypeKind ODataType) throws ODataJPAModelException { + + assertEquals(ODataType, JPATypeConvertor.convertToEdmSimpleType(javaType, jpaAttribute)); + final ODataJPAModelException act = assertThrows(ODataJPAModelException.class, + () -> JPATypeConvertor.convertToEdmSimpleType(javaType, buildTimeAttribute(TemporalType.TIME))); + assertEquals(ODataJPAModelException.MessageKeys.TYPE_NOT_SUPPORTED.getKey(), act.getId()); + } + + @ParameterizedTest + @MethodSource("mappingJavaTimeToOData") + public void checkConvertJavaDateTimeToOData(final Class javaType, final Attribute jpaAttribute, + final EdmPrimitiveTypeKind ODataType) throws ODataJPAModelException { + + assertEquals(ODataType, JPATypeConvertor.convertToEdmSimpleType(javaType, jpaAttribute)); + } + + @ParameterizedTest + @MethodSource("mappingJavaLobToOData") + public void checkConvertJavaLobToOData(final Class javaType, final Attribute jpaAttribute, + final EdmPrimitiveTypeKind ODataType) throws ODataJPAModelException { + + assertEquals(ODataType, JPATypeConvertor.convertToEdmSimpleType(javaType, jpaAttribute)); + + final ODataJPAModelException act = assertThrows(ODataJPAModelException.class, + () -> JPATypeConvertor.convertToEdmSimpleType(javaType, buildTimeAttribute(TemporalType.TIME))); + assertEquals(ODataJPAModelException.MessageKeys.TYPE_NOT_SUPPORTED.getKey(), act.getId()); + } + + @ParameterizedTest + @MethodSource("mappingSimpleJavaToOData") + public void checkConvertSimpleJavaToOData(final Class javaType, final EdmPrimitiveTypeKind ODataType) + throws ODataJPAModelException { + + assertEquals(ODataType, JPATypeConvertor.convertToEdmSimpleType(javaType)); + } + + @ParameterizedTest + @MethodSource("scalarJavaTypes") + public void checkIsScalarJavaType(final Class javaType, final Attribute jpaAttribute, + final boolean isSalar) { + + assertEquals(isSalar, JPATypeConvertor.isScalarType(javaType)); + } + + @ParameterizedTest + @MethodSource("simpleJavaTypes") + public void checkIsSimpleJavaType(final Class javaType, final Attribute jpaAttribute, + final boolean isSimple) { + + assertEquals(isSimple, JPATypeConvertor.isSimpleType(javaType, jpaAttribute)); + } + + @ParameterizedTest + @MethodSource("supportedByOlingo") + public void checkIsSupportedByOling(final Class javaType, final boolean isSupported) { + + assertEquals(isSupported, JPATypeConvertor.isSupportedByOlingo(javaType)); + } + + @Test + public void checkReturnsNullOnUnknownTypeWithoutAnnotation() throws ODataJPAModelException { + + assertNull(JPATypeConvertor.convertToEdmSimpleType(BigInteger.class)); + } + + @Test + public void checkThrowsExceptionOnUnknownTypeWithAnnotation() throws ODataJPAModelException { + + assertThrows(ODataJPAModelException.class, + () -> JPATypeConvertor.convertToEdmSimpleType(BigInteger.class, buildTimeAttribute(TemporalType.TIME))); + } + + @Test + public void checkThrowsExceptionOnUnknownGeographyType() throws ODataJPAModelException { + + assertThrows(ODataJPAModelException.class, + () -> JPATypeConvertor.convertToEdmSimpleType(BigInteger.class, buildDimensionAttribute(Dimension.GEOGRAPHY))); + } + + @Test + public void checkThrowsExceptionOnUnknownGeometryType() throws ODataJPAModelException { + + assertThrows(ODataJPAModelException.class, + () -> JPATypeConvertor.convertToEdmSimpleType(BigInteger.class, buildDimensionAttribute(Dimension.GEOMETRY))); + } +} diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestMappingRoot.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestMappingRoot.java index 36c5702b3..64f9428cc 100644 --- a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestMappingRoot.java +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestMappingRoot.java @@ -2,23 +2,32 @@ import javax.persistence.EntityManagerFactory; -import org.junit.BeforeClass; +import org.junit.jupiter.api.BeforeAll; import com.sap.olingo.jpa.metadata.api.JPAEntityManagerFactory; import com.sap.olingo.jpa.processor.core.testmodel.DataSourceHelper; public class TestMappingRoot { protected static final String PUNIT_NAME = "com.sap.olingo.jpa"; + protected static final String ERROR_PUNIT = "error"; protected static EntityManagerFactory emf; + protected static EntityManagerFactory errorEmf; + protected static JPADefaultEdmNameBuilder nameBuilder; + protected static JPADefaultEdmNameBuilder errorNameBuilder; public static final String BUPA_CANONICAL_NAME = "com.sap.olingo.jpa.processor.core.testmodel.BusinessPartner"; + public static final String ORG_CANONICAL_NAME = "com.sap.olingo.jpa.processor.core.testmodel.Organization"; public static final String ADDR_CANONICAL_NAME = "com.sap.olingo.jpa.processor.core.testmodel.PostalAddressData"; public static final String COMM_CANONICAL_NAME = "com.sap.olingo.jpa.processor.core.testmodel.CommunicationData"; public static final String ADMIN_CANONICAL_NAME = "com.sap.olingo.jpa.processor.core.testmodel.AdministrativeDivision"; - @BeforeClass + @BeforeAll public static void setupClass() { emf = JPAEntityManagerFactory.getEntityManagerFactory(PUNIT_NAME, DataSourceHelper.createDataSource( DataSourceHelper.DB_HSQLDB)); + errorEmf = JPAEntityManagerFactory.getEntityManagerFactory(ERROR_PUNIT, DataSourceHelper.createDataSource( + DataSourceHelper.DB_HSQLDB)); + nameBuilder = new JPADefaultEdmNameBuilder(PUNIT_NAME); + errorNameBuilder = new JPADefaultEdmNameBuilder(ERROR_PUNIT); } } \ No newline at end of file diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestOffsetDateTimeConverter.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestOffsetDateTimeConverter.java new file mode 100644 index 000000000..58c064dac --- /dev/null +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/impl/TestOffsetDateTimeConverter.java @@ -0,0 +1,56 @@ +/** + * + */ +package com.sap.olingo.jpa.metadata.core.edm.mapper.impl; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * @author Oliver Grande + * Created: 09.03.2020 + * + */ +public class TestOffsetDateTimeConverter { + private OffsetDateTimeConverter cut; + + @BeforeEach + public void setup() { + cut = new OffsetDateTimeConverter(); + } + + @Test + public void checkConvertToDatabaseColumnReturnNullOnNull() { + assertNull(cut.convertToDatabaseColumn(null)); + } + + @Test + public void checkConvertToEntityAttributeReturnNullOnNull() { + assertNull(cut.convertToEntityAttribute(null)); + } + + @Test + public void checkConvertToDatabaseColumnReturnConvertedOnNonNull() { + final ZonedDateTime time = ZonedDateTime + .of(LocalDateTime.of(2020, 10, 20, 6, 23, 10), ZoneId.of(ZoneId.SHORT_IDS.get("ECT"))); + final OffsetDateTime act = cut.convertToDatabaseColumn(time); + assertEquals("2020-10-20T06:23:10+02:00", act.toString()); + } + + @Test + public void checkConvertToEntityAttributeReturnConvertedOnNonNull() { + final OffsetDateTime time = OffsetDateTime.of( + LocalDateTime.of(2020, 10, 20, 6, 23), ZoneOffset.ofHours(3)); + final ZonedDateTime act = cut.convertToEntityAttribute(time); + assertEquals(time, act.toOffsetDateTime()); + } +} diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testaction/Actions.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testaction/Actions.java new file mode 100644 index 000000000..7e293a526 --- /dev/null +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testaction/Actions.java @@ -0,0 +1,30 @@ +package com.sap.olingo.jpa.metadata.core.edm.mapper.testaction; + +import java.math.BigDecimal; + +import javax.persistence.EntityManager; + +import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmAction; +import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmParameter; +import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.ODataAction; +import com.sap.olingo.jpa.processor.core.testmodel.Person; + +public class Actions implements ODataAction { + public Actions(final EntityManager em) { + super(); + } + + @EdmAction(name = "BoundNoImport", isBound = true) + public void boundNoImport( + @EdmParameter(name = "Person") Person person, + @EdmParameter(name = "A", precision = 34, scale = 10) BigDecimal a) { + // Do nothing + } + + @EdmAction(name = "WithImport", isBound = false) + public void withImport( + @EdmParameter(name = "Person") Person person, + @EdmParameter(name = "A", precision = 34, scale = 10) BigDecimal a) { + // Do nothing + } +} diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testaction/function/Function.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testaction/function/Function.java new file mode 100644 index 000000000..190ea33ba --- /dev/null +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testaction/function/Function.java @@ -0,0 +1,14 @@ +package com.sap.olingo.jpa.metadata.core.edm.mapper.testaction.function; + +import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmFunction; +import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmFunction.ReturnType; +import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmParameter; +import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.ODataFunction; + +public class Function implements ODataFunction { + @EdmFunction(name = "", returnType = @ReturnType) + public Integer sum( + @EdmParameter(name = "A") short a, @EdmParameter(name = "B") int b) { + return a + b; + } +} diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/DayOfWeek.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/DayOfWeek.java index 661b5efd6..8705d65d0 100644 --- a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/DayOfWeek.java +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/DayOfWeek.java @@ -1,19 +1,8 @@ package com.sap.olingo.jpa.metadata.core.edm.mapper.testobjects; -import com.sap.olingo.jpa.metadata.core.edm.mapper.impl.ODataEnum; +import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmEnumeration; -public enum DayOfWeek implements ODataEnum { - MONDAY(1), TUESDAY(2), WEDNESDAY(3), - THURSDAY(4), FRIDAY(5), SATURDAY(6), SUNDAY(7); - - private final int value; - - DayOfWeek(int ordinal) { - value = ordinal; - } - - @Override - public Integer getValue() { - return value; - } +@EdmEnumeration +public enum DayOfWeek { + MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY; } diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/ExampleJavaActions.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/ExampleJavaActions.java index d258687f1..a2f19425c 100644 --- a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/ExampleJavaActions.java +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/ExampleJavaActions.java @@ -12,6 +12,8 @@ import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmGeospatial; import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmParameter; import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.ODataAction; +import com.sap.olingo.jpa.processor.core.testmodel.ABCClassifiaction; +import com.sap.olingo.jpa.processor.core.testmodel.AccessRights; import com.sap.olingo.jpa.processor.core.testmodel.BusinessPartnerRole; import com.sap.olingo.jpa.processor.core.testmodel.ChangeInformation; import com.sap.olingo.jpa.processor.core.testmodel.Person; @@ -54,9 +56,14 @@ public Person returnEntity() { return new Person(); } + @EdmAction + public ABCClassifiaction returnEnumeration(@EdmParameter(name = "Rights") AccessRights rights) { + return ABCClassifiaction.B; + } + @EdmAction(name = "", returnType = @ReturnType(type = String.class)) public List returnCollection() { - return new ArrayList(); + return new ArrayList<>(); } @EdmAction(name = "", returnType = @ReturnType(type = ChangeInformation.class)) @@ -66,7 +73,7 @@ public List returnEmbeddableCollection() { @EdmAction(name = "") public List returnCollectionWithoutReturnType() { - return new ArrayList(); + return new ArrayList<>(); } @EdmAction(name = "", diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/ExampleJavaFunctions.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/ExampleJavaFunctions.java index 3ecdf6e8d..f12e70192 100644 --- a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/ExampleJavaFunctions.java +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/ExampleJavaFunctions.java @@ -11,9 +11,11 @@ import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmFunction; import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmFunction.ReturnType; -import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmParameter; import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmGeospatial; +import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmParameter; import com.sap.olingo.jpa.metadata.core.edm.mapper.extention.ODataFunction; +import com.sap.olingo.jpa.processor.core.testmodel.ABCClassifiaction; +import com.sap.olingo.jpa.processor.core.testmodel.AccessRights; import com.sap.olingo.jpa.processor.core.testmodel.ChangeInformation; import com.sap.olingo.jpa.processor.core.testmodel.Person; import com.sap.olingo.jpa.processor.core.testmodel.PostalAddressData; @@ -54,12 +56,12 @@ public String determineLocation() { @EdmFunction(name = "", returnType = @ReturnType(type = String.class)) public List returnCollection() { - return new ArrayList(); + return new ArrayList<>(); } @EdmFunction(name = "", returnType = @ReturnType()) public List returnCollectionWithoutReturnType() { - return new ArrayList(); + return new ArrayList<>(); } @EdmFunction(name = "", returnType = @ReturnType()) @@ -87,4 +89,14 @@ public Integer errorNonPrimitiveParameter( @EdmParameter(name = "A") PostalAddressData a) { return 1; } + + @EdmFunction(name = "", returnType = @ReturnType()) + public ABCClassifiaction returnEnumerationType(@EdmParameter(name = "Rights") AccessRights rights) { + return ABCClassifiaction.A; + } + + @EdmFunction(name = "", returnType = @ReturnType(type = ABCClassifiaction.class)) + public List returnEnumerationCollection() { + return new ArrayList<>(); + } } diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/ExampleJavaOneFunction.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/ExampleJavaOneFunction.java index f0d1e1fea..3bd50f419 100644 --- a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/ExampleJavaOneFunction.java +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/ExampleJavaOneFunction.java @@ -11,7 +11,7 @@ public ExampleJavaOneFunction() { super(); } - @EdmFunction(name = "", returnType = @ReturnType) + @EdmFunction(returnType = @ReturnType) public Integer sum( @EdmParameter(name = "A") short a, @EdmParameter(name = "B") int b) { return a + b; diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/FileAccess.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/FileAccess.java new file mode 100644 index 000000000..e62fa1617 --- /dev/null +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/FileAccess.java @@ -0,0 +1,22 @@ +package com.sap.olingo.jpa.metadata.core.edm.mapper.testobjects; + +import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmEnumeration; + +@EdmEnumeration(isFlags = true, converter = FileAccessConverter.class) +public enum FileAccess { + Read((short) 1), Write((short) 2), Create((short) 4), Delete((short) 8); + + private short value; + + private FileAccess(short value) { + this.setValue(value); + } + + public short getValue() { + return value; + } + + private void setValue(short value) { + this.value = value; + } +} diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/FileAccessConverter.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/FileAccessConverter.java new file mode 100644 index 000000000..b1a59fc65 --- /dev/null +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/FileAccessConverter.java @@ -0,0 +1,28 @@ +package com.sap.olingo.jpa.metadata.core.edm.mapper.testobjects; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.persistence.AttributeConverter; + +public class FileAccessConverter implements AttributeConverter { + + @Override + public Short convertToDatabaseColumn(FileAccess[] attributes) { + return attributes[0].getValue(); + } + + @Override + public FileAccess[] convertToEntityAttribute(Short dbData) { + if (dbData == null) + return null; + final List accesses = new ArrayList<>(); + for (FileAccess e : Arrays.asList(FileAccess.values())) { + if (e.getValue() == dbData) + accesses.add(e); + } + return accesses.toArray(new FileAccess[] {}); + } + +} diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/WrongMember.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/WrongMember.java new file mode 100644 index 000000000..dfac2ed4f --- /dev/null +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/WrongMember.java @@ -0,0 +1,18 @@ +package com.sap.olingo.jpa.metadata.core.edm.mapper.testobjects; + +import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmEnumeration; + +@EdmEnumeration(isFlags = true, converter = WrongMemberConverter.class) +public enum WrongMember { + Right(1), Wrong(-2); + private final int value; + + private WrongMember(final int value) { + this.value = value; + } + + public int getValue() { + return value; + } + +} diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/WrongMemberConverter.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/WrongMemberConverter.java new file mode 100644 index 000000000..7d2d23189 --- /dev/null +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/WrongMemberConverter.java @@ -0,0 +1,28 @@ +package com.sap.olingo.jpa.metadata.core.edm.mapper.testobjects; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.persistence.AttributeConverter; + +public class WrongMemberConverter implements AttributeConverter { + + @Override + public Integer convertToDatabaseColumn(WrongMember[] attributes) { + return attributes[0].getValue(); + } + + @Override + public WrongMember[] convertToEntityAttribute(Integer dbData) { + if (dbData == null) + return null; + final List accesses = new ArrayList<>(); + for (WrongMember e : Arrays.asList(WrongMember.values())) { + if (e.getValue() == dbData) + accesses.add(e); + } + return accesses.toArray(new WrongMember[] {}); + } + +} diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/WrongType.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/WrongType.java new file mode 100644 index 000000000..9e2e2cb6b --- /dev/null +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/WrongType.java @@ -0,0 +1,20 @@ +package com.sap.olingo.jpa.metadata.core.edm.mapper.testobjects; + +import java.math.BigDecimal; + +import com.sap.olingo.jpa.metadata.core.edm.annotation.EdmEnumeration; + +@EdmEnumeration(converter = WrongTypeConverter.class) +public enum WrongType { + TEST(BigDecimal.valueOf(2L)); + + private BigDecimal value; + + private WrongType(BigDecimal value) { + this.value = value; + } + + public BigDecimal getValue() { + return value; + } +} diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/WrongTypeConverter.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/WrongTypeConverter.java new file mode 100644 index 000000000..5cc1af983 --- /dev/null +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/testobjects/WrongTypeConverter.java @@ -0,0 +1,19 @@ +package com.sap.olingo.jpa.metadata.core.edm.mapper.testobjects; + +import java.math.BigDecimal; + +import javax.persistence.AttributeConverter; + +public class WrongTypeConverter implements AttributeConverter { + + @Override + public BigDecimal convertToDatabaseColumn(WrongType[] attribute) { + return WrongType.TEST.getValue(); + } + + @Override + public WrongType[] convertToEntityAttribute(BigDecimal dbData) { + return new WrongType[] { WrongType.TEST }; + } + +} diff --git a/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/util/MemberDouble.java b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/util/MemberDouble.java new file mode 100644 index 000000000..174c3870a --- /dev/null +++ b/jpa/odata-jpa-metadata/src/test/java/com/sap/olingo/jpa/metadata/core/edm/mapper/util/MemberDouble.java @@ -0,0 +1,63 @@ +package com.sap.olingo.jpa.metadata.core.edm.mapper.util; + +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Member; +import java.util.HashMap; +import java.util.Map; + +public class MemberDouble implements Member, AnnotatedElement { + private final Member member; + private final AnnotatedElement annotatedElement; + + private final Map, Annotation> annotations; + + public MemberDouble(Member member) { + super(); + this.member = member; + this.annotatedElement = (AnnotatedElement) member; + this.annotations = new HashMap<>(); + } + + @SuppressWarnings("unchecked") + @Override + public T getAnnotation(Class annotationClass) { + if (annotations.containsKey(annotationClass)) + return (T) annotations.get(annotationClass); + return annotatedElement.getAnnotation(annotationClass); + } + + @Override + public Annotation[] getAnnotations() { + return annotatedElement.getAnnotations(); + } + + @Override + public Annotation[] getDeclaredAnnotations() { + return annotatedElement.getDeclaredAnnotations(); + } + + @Override + public Class getDeclaringClass() { + return member.getDeclaringClass(); + } + + @Override + public String getName() { + return member.getName(); + } + + @Override + public int getModifiers() { + return member.getModifiers(); + } + + @Override + public boolean isSynthetic() { + return member.isSynthetic(); + } + + public void addAnnotation(Class clazz, T annotation) { + annotations.put(clazz, annotation); + } +} diff --git a/jpa/odata-jpa-metadata/src/test/resources/annotations/Org.OData.Aggregation.V1.xml b/jpa/odata-jpa-metadata/src/test/resources/annotations/Org.OData.Aggregation.V1.xml new file mode 100644 index 000000000..e9c5151a9 --- /dev/null +++ b/jpa/odata-jpa-metadata/src/test/resources/annotations/Org.OData.Aggregation.V1.xml @@ -0,0 +1,202 @@ + + + + + + + + + + Terms to describe which data in a given entity model can be aggregated, and how. + + + + + + + + + + + + + + + + + + + + + This structured type or entity container supports the $apply system query option + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The context-defining properties need either be part of the result entities, or be restricted to a single value by a pre-filter operation. Examples are postal codes within a country, or monetary amounts whose context is the unit of currency. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/jpa/odata-jpa-metadata/src/test/resources/annotations/Org.OData.Capabilities.V1.xml b/jpa/odata-jpa-metadata/src/test/resources/annotations/Org.OData.Capabilities.V1.xml index fd771cacf..2d01e1432 100644 --- a/jpa/odata-jpa-metadata/src/test/resources/annotations/Org.OData.Capabilities.V1.xml +++ b/jpa/odata-jpa-metadata/src/test/resources/annotations/Org.OData.Capabilities.V1.xml @@ -1,368 +1,408 @@ - - - - - - - - - - - - The Capabilities vocabulary aims to provide a way for service authors to describe - certain capabilities of an OData Service. - - - - - There are some capabilities which are strongly recommended for services to support even - though they are optional. Support for $top and $skip is a good example as - supporting these query options helps with performance of a service and are essential. Such - capabilities are assumed to be default capabilities of an OData service even in - the case that a capabilities annotation doesn’t exist. Capabilities annotations are - mainly expected to be used to explicitly specify that a service doesn’t support such - capabilities. Capabilities annotations can as well be used to declaratively - specify the support of such capabilities. - - On the other hand, there are some capabilities that a service may choose to support or - not support and in varying degrees. $filter and $orderby are such good examples. - This vocabulary aims to define terms to specify support or no support for such - capabilities. - - A service is assumed to support by default the following capabilities even though an - annotation doesn’t exist: - - Countability ($count) - - Client pageability ($top, $skip) - - Expandability ($expand) - - Indexability by key - - Batch support ($batch) - - Navigability of navigation properties - - A service is expected to support the following capabilities. If not supported, the - service is expected to call out the restrictions using annotations: - - Filterability ($filter) - - Sortability ($orderby) - - Queryability of top level entity sets - - Query functions - - A client cannot assume that a service supports certain capabilities. A client can try, but - it needs to be prepared to handle an error in case the following capabilities are not - supported: - - Insertability - - Updatability - - Deletability - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + Terms describing capabilities of a service + + + + There are some capabilities which are strongly recommended for services to support even + though they are optional. Support for $top and $skip is a good example as + supporting these query options helps with performance of a service and are essential. Such + capabilities are assumed to be default capabilities of an OData service even in + the case that a capabilities annotation doesn’t exist. Capabilities annotations are + mainly expected to be used to explicitly specify that a service doesn’t support such + capabilities. Capabilities annotations can as well be used to declaratively + specify the support of such capabilities. + + On the other hand, there are some capabilities that a service may choose to support or + not support and in varying degrees. $filter and $orderby are such good examples. + This vocabulary aims to define terms to specify support or no support for such + capabilities. + + A service is assumed to support by default the following capabilities even though an + annotation doesn’t exist: + - Countability ($count) + - Client pageability ($top, $skip) + - Expandability ($expand) + - Indexability by key + - Batch support ($batch) + - Navigability of navigation properties + + A service is expected to support the following capabilities. If not supported, the + service is expected to call out the restrictions using annotations: + - Filterability ($filter) + - Sortability ($orderby) + - Queryability of top level entity sets + - Query functions + + A client cannot assume that a service supports certain capabilities. A client can try, but + it needs to be prepared to handle an error in case the following capabilities are not + supported: + - Insertability + - Updatability + - Deletability + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/jpa/odata-jpa-metadata/src/test/resources/annotations/Org.OData.Core.V1.xml b/jpa/odata-jpa-metadata/src/test/resources/annotations/Org.OData.Core.V1.xml index 7586a6973..d47df5004 100644 --- a/jpa/odata-jpa-metadata/src/test/resources/annotations/Org.OData.Core.V1.xml +++ b/jpa/odata-jpa-metadata/src/test/resources/annotations/Org.OData.Core.V1.xml @@ -1,76 +1,63 @@ - + + + Core terms needed to write vocabularies - - - + + + + + + + + + + @@ -83,6 +70,66 @@ Overview: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -90,6 +137,10 @@ Overview: + + + + @@ -100,9 +151,8 @@ Overview: - - + + @@ -115,21 +165,36 @@ Overview: - - + + - + + + + + + + + - + + String="Functions, actions and types in this namespace can be referenced in URLs with or without namespace- or alias- qualification." /> + + + + + @@ -141,13 +206,14 @@ Overview: - + + @@ -157,10 +223,63 @@ Overview: - + + String="Data modification requires the use of ETags. A non-empty collection contains the set of properties that are used to compute the ETag." /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jpa/odata-jpa-metadata/src/test/resources/annotations/Org.OData.Repeatability.V1.xml b/jpa/odata-jpa-metadata/src/test/resources/annotations/Org.OData.Repeatability.V1.xml new file mode 100644 index 000000000..ff1ed5dc7 --- /dev/null +++ b/jpa/odata-jpa-metadata/src/test/resources/annotations/Org.OData.Repeatability.V1.xml @@ -0,0 +1,85 @@ + + + + + + + + + + Terms describing repeatable requests + + + + + + + + + + + + + + + + + + + + + + + + + Clients that specify a `RepeatabilityClientID` header can delete all remembered requests for that client ID by sending a `DELETE $RepeatableRequests/{ClientID}` request to the service root. + + + + + + Clients can delete a single remembered request by sending a `DELETE $RepeatableRequest/{RequestID}` request to the service root. + + + + + + \ No newline at end of file diff --git a/jpa/odata-jpa-metadata/src/test/resources/annotations/Org.Olingo.Test.V1.xml b/jpa/odata-jpa-metadata/src/test/resources/annotations/Org.Olingo.Test.V1.xml index 341d14ac4..08be8d638 100644 --- a/jpa/odata-jpa-metadata/src/test/resources/annotations/Org.Olingo.Test.V1.xml +++ b/jpa/odata-jpa-metadata/src/test/resources/annotations/Org.Olingo.Test.V1.xml @@ -1,4 +1,7 @@ - + + @@ -53,6 +56,51 @@
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/jpa/odata-jpa-metadata/src/test/resources/annotations/empty.xml b/jpa/odata-jpa-metadata/src/test/resources/annotations/empty.xml new file mode 100644 index 000000000..e69de29bb diff --git a/jpa/odata-jpa-metadata/src/test/resources/metadata/TripPin.xml b/jpa/odata-jpa-metadata/src/test/resources/metadata/TripPin.xml index f51884c22..e0b932f65 100644 --- a/jpa/odata-jpa-metadata/src/test/resources/metadata/TripPin.xml +++ b/jpa/odata-jpa-metadata/src/test/resources/metadata/TripPin.xml @@ -130,7 +130,7 @@ - + diff --git a/jpa/odata-jpa-processor-cb/.gitignore b/jpa/odata-jpa-processor-cb/.gitignore new file mode 100644 index 000000000..bc3d61598 --- /dev/null +++ b/jpa/odata-jpa-processor-cb/.gitignore @@ -0,0 +1,14 @@ +/.sts4-cache/ + +target/ +**/target/ +/target/ +/.pmd +/derby.log +/test/ +/.settings/ +/*.log + +# JDT-specific (Eclipse Java Development Tools) +.classpath +/model/ \ No newline at end of file diff --git a/jpa/odata-jpa-processor-cb/pom.xml b/jpa/odata-jpa-processor-cb/pom.xml new file mode 100644 index 000000000..c5fbede88 --- /dev/null +++ b/jpa/odata-jpa-processor-cb/pom.xml @@ -0,0 +1,36 @@ + + 4.0.0 + + com.sap.olingo + odata-jpa + 0.3.8-SNAPSHOT + + + odata-jpa-processor-cb + + + + com.sap.olingo + odata-jpa-test + test + ${project.version} + + + com.sap.olingo + odata-jpa-annotation + ${project.version} + + + com.sap.olingo + odata-jpa-metadata + ${project.version} + + + org.eclipse.persistence + javax.persistence + ${jpa.version} + + + diff --git a/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/EntityManagerFactoryWrapper.java b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/EntityManagerFactoryWrapper.java new file mode 100644 index 000000000..f0f402f2e --- /dev/null +++ b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/EntityManagerFactoryWrapper.java @@ -0,0 +1,99 @@ +package com.sap.olingo.jpa.processor.cb.api; + +import java.util.Map; + +import javax.persistence.Cache; +import javax.persistence.EntityGraph; +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.PersistenceUnitUtil; +import javax.persistence.Query; +import javax.persistence.SynchronizationType; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.metamodel.Metamodel; + +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAServiceDocument; +import com.sap.olingo.jpa.processor.cb.impl.EntityManagerWrapper; + +public final class EntityManagerFactoryWrapper implements EntityManagerFactory { + private final EntityManagerFactory emf; + private final JPAServiceDocument sd; + + public EntityManagerFactoryWrapper(final EntityManagerFactory emf, final JPAServiceDocument sd) { + super(); + this.emf = emf; + this.sd = sd; + } + + @Override + public EntityManager createEntityManager() { + return new EntityManagerWrapper(emf.createEntityManager(), sd); + } + + @Override + public EntityManager createEntityManager(@SuppressWarnings("rawtypes") final Map map) { + return new EntityManagerWrapper(emf.createEntityManager(map), sd); + } + + @Override + public EntityManager createEntityManager(final SynchronizationType synchronizationType) { + return new EntityManagerWrapper(emf.createEntityManager(synchronizationType), sd); + } + + @Override + public EntityManager createEntityManager(final SynchronizationType synchronizationType, + @SuppressWarnings("rawtypes") final Map map) { + return new EntityManagerWrapper(emf.createEntityManager(synchronizationType, map), sd); + } + + @Override + public CriteriaBuilder getCriteriaBuilder() { + return new EntityManagerWrapper(emf.createEntityManager(), sd).getCriteriaBuilder(); + } + + @Override + public Metamodel getMetamodel() { + return emf.getMetamodel(); + } + + @Override + public boolean isOpen() { + return emf.isOpen(); + } + + @Override + public void close() { + emf.close(); + } + + @Override + public Map getProperties() { + return emf.getProperties(); + } + + @Override + public Cache getCache() { + return emf.getCache(); + } + + @Override + public PersistenceUnitUtil getPersistenceUnitUtil() { + return emf.getPersistenceUnitUtil(); + } + + @Override + public void addNamedQuery(final String name, final Query query) { + emf.addNamedQuery(name, query); + } + + @Override + public T unwrap(final Class cls) { + return emf.unwrap(cls); + } + + @Override + public void addNamedEntityGraph(final String graphName, final EntityGraph entityGraph) { + emf.addNamedEntityGraph(graphName, entityGraph); + } + +} diff --git a/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/ProcessorSelection.java b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/ProcessorSelection.java new file mode 100644 index 000000000..5c860866e --- /dev/null +++ b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/ProcessorSelection.java @@ -0,0 +1,77 @@ +package com.sap.olingo.jpa.processor.cb.api; + +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import javax.persistence.criteria.Selection; + +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAAttribute; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAPath; + +public interface ProcessorSelection extends Selection, SqlConvertable { + /** + * + * @return a list of pairs of alias and path + */ + List> getResolvedSelection(); + + /** + * Immutable pair + * @author D023143 + * + */ + public static class SelectionItem implements Map.Entry { + + private final String key; + private JPAPath value; + + public SelectionItem(final String key, final JPAPath value) { + super(); + this.key = key; + this.value = value; + } + + @Override + public String getKey() { + return key; + } + + @Override + public JPAPath getValue() { + return value; + } + + @Override + public JPAPath setValue(JPAPath value) { + throw new IllegalAccessError(); + } + } + + public static class SelectionAttribute implements Map.Entry { + + private final String key; + private JPAAttribute value; + + public SelectionAttribute(final String key, final JPAAttribute value) { + super(); + this.key = key; + this.value = value; + } + + @Override + public String getKey() { + return key; + } + + @Override + public JPAAttribute getValue() { + return value; + } + + @Override + public JPAAttribute setValue(JPAAttribute value) { + throw new IllegalAccessError(); + } + } +} diff --git a/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/ProcessorSubquery.java b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/ProcessorSubquery.java new file mode 100644 index 000000000..db39dff9e --- /dev/null +++ b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/ProcessorSubquery.java @@ -0,0 +1,20 @@ +package com.sap.olingo.jpa.processor.cb.api; + +public interface ProcessorSubquery extends javax.persistence.criteria.Subquery { + /** + * Set the maximum number of results to retrieve. + * @param maxResult maximum number of results to retrieve + * @return the same query instance + * @throws IllegalArgumentException if the argument is negative + */ + ProcessorSubquery setMaxResults(int maxResult); + + /** + * Set the position of the first result to retrieve. + * @param startPosition position of the first result, + * numbered from 0 + * @return the same query instance + * @throws IllegalArgumentException if the argument is negative + */ + ProcessorSubquery setFirstResult(int startPosition); +} diff --git a/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlAggregation.java b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlAggregation.java new file mode 100644 index 000000000..4f5561c2f --- /dev/null +++ b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlAggregation.java @@ -0,0 +1,19 @@ +package com.sap.olingo.jpa.processor.cb.api; + +public enum SqlAggregation { + + AVG("AVG"), + COUNT("COUNT"), + SUM("SUM"); + + private String keyWord; + + private SqlAggregation(final String keyWord) { + this.keyWord = keyWord; + } + + @Override + public String toString() { + return keyWord; + } +} diff --git a/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlArithmetic.java b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlArithmetic.java new file mode 100644 index 000000000..4ab683504 --- /dev/null +++ b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlArithmetic.java @@ -0,0 +1,21 @@ +package com.sap.olingo.jpa.processor.cb.api; + +public enum SqlArithmetic { + + SUM("+"), + PROD("*"), + DIFF("-"), + MOD("%"), + QUOT("/"); + + private String keyWord; + + private SqlArithmetic(final String keyWord) { + this.keyWord = keyWord; + } + + @Override + public String toString() { + return keyWord; + } +} diff --git a/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlConvertable.java b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlConvertable.java new file mode 100644 index 000000000..35838490f --- /dev/null +++ b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlConvertable.java @@ -0,0 +1,8 @@ +package com.sap.olingo.jpa.processor.cb.api; + +import javax.annotation.Nonnull; + +public interface SqlConvertable { + + public StringBuilder asSQL(@Nonnull final StringBuilder statment); +} diff --git a/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlJoinType.java b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlJoinType.java new file mode 100644 index 000000000..60481a556 --- /dev/null +++ b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlJoinType.java @@ -0,0 +1,44 @@ +package com.sap.olingo.jpa.processor.cb.api; + +import java.util.EnumMap; + +import javax.persistence.criteria.JoinType; + +public enum SqlJoinType { + + INNER("INNER JOIN", JoinType.INNER), + LEFT("LEFT OUTER JOIN", JoinType.LEFT), + RIGHT("RIGHT OUTER JOIN", JoinType.RIGHT); + + private static final EnumMap REL = new EnumMap<>(JoinType.class); + + public static SqlJoinType byJoinType(final JoinType jt) { + SqlJoinType s = REL.get(jt); + if (s != null) + return s; + for (final SqlJoinType sql : SqlJoinType.values()) { + if (sql.getJoinType() == jt) { + REL.put(jt, sql); + return sql; + } + } + return null; + } + + private final String keyWord; + private final JoinType jt; + + private SqlJoinType(final String keyWord, final JoinType jt) { + this.keyWord = keyWord; + this.jt = jt; + } + + JoinType getJoinType() { + return jt; + } + + @Override + public String toString() { + return keyWord; + } +} diff --git a/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlKeyWords.java b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlKeyWords.java new file mode 100644 index 000000000..990c8cc7e --- /dev/null +++ b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlKeyWords.java @@ -0,0 +1,39 @@ +package com.sap.olingo.jpa.processor.cb.api; + +public enum SqlKeyWords { + ADD("ADD"), + ALL("ALL"), + AND("AND"), + ANY("ANY"), + ASC("ASC"), + BETWEEN("BETWEEN"), + COALESCE("COALESCE"), + CONTAINS("CONTAINS"), + DESC("DESC"), + DISTINCT("DISTINCT"), + ESCAPE("ESCAPE"), + EXISTS("EXISTS"), + FROM("FROM"), + GROUPBY("GROUP BY"), + HAVING("HAVING"), + IN("IN"), + LIKE("LIKE"), + MOD("MOD"), + NOT("NOT"), + ORDERBY("ORDER BY"), + SELECT("SELECT"), + SOME("SOME"), + UNION("UNION"), + WHERE("WHERE"); + + private String keyWord; + + private SqlKeyWords(final String keyWord) { + this.keyWord = keyWord; + } + + @Override + public String toString() { + return keyWord; + } +} diff --git a/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlNullCheck.java b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlNullCheck.java new file mode 100644 index 000000000..879b7ee6b --- /dev/null +++ b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlNullCheck.java @@ -0,0 +1,18 @@ +package com.sap.olingo.jpa.processor.cb.api; + +public enum SqlNullCheck { + + NULL("IS NULL"), + NOT_NULL("IS NOT NULL"); + + private String keyWord; + + private SqlNullCheck(final String keyWord) { + this.keyWord = keyWord; + } + + @Override + public String toString() { + return keyWord; + } +} diff --git a/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlStringFunctions.java b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlStringFunctions.java new file mode 100644 index 000000000..1f15938df --- /dev/null +++ b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlStringFunctions.java @@ -0,0 +1,23 @@ +package com.sap.olingo.jpa.processor.cb.api; + +public enum SqlStringFunctions { + + LOWER("LOWER"), + UPPER("UPPER"), + LENGTH("LENGTH"), + TRIM("TRIM"), + SUBSTRING("SUBSTRING"), + CONCAT("CONCAT"), + LOCATE("LOCATE"); + + private String keyWord; + + private SqlStringFunctions(final String keyWord) { + this.keyWord = keyWord; + } + + @Override + public String toString() { + return keyWord; + } +} diff --git a/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlSubQuery.java b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlSubQuery.java new file mode 100644 index 000000000..4c5143f63 --- /dev/null +++ b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlSubQuery.java @@ -0,0 +1,20 @@ +package com.sap.olingo.jpa.processor.cb.api; + +public enum SqlSubQuery { + + EXISTS("EXISTS"), + SOME("SOME"), + ALL("ALL"), + ANY("ANY"); + + private String keyWord; + + private SqlSubQuery(final String keyWord) { + this.keyWord = keyWord; + } + + @Override + public String toString() { + return keyWord; + } +} diff --git a/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlTimeFunctions.java b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlTimeFunctions.java new file mode 100644 index 000000000..f338fb24e --- /dev/null +++ b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/api/SqlTimeFunctions.java @@ -0,0 +1,19 @@ +package com.sap.olingo.jpa.processor.cb.api; + +public enum SqlTimeFunctions { + + TIMESTAMP("CURRENT_TIMESTAMP"), + DATE("CURRENT_DATE"), + TIME("CURRENT_TIME"); + + private String keyWord; + + private SqlTimeFunctions(final String keyWord) { + this.keyWord = keyWord; + } + + @Override + public String toString() { + return keyWord; + } +} diff --git a/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/exeptions/InternalServerError.java b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/exeptions/InternalServerError.java new file mode 100644 index 000000000..6a9dc5351 --- /dev/null +++ b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/exeptions/InternalServerError.java @@ -0,0 +1,12 @@ +package com.sap.olingo.jpa.processor.cb.exeptions; + +import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; + +public class InternalServerError extends RuntimeException { + + private static final long serialVersionUID = -2239224331308130011L; + + public InternalServerError(ODataJPAModelException e) { + super(e); + } +} diff --git a/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/exeptions/NotImplementedException.java b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/exeptions/NotImplementedException.java new file mode 100644 index 000000000..e405654ab --- /dev/null +++ b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/exeptions/NotImplementedException.java @@ -0,0 +1,10 @@ +package com.sap.olingo.jpa.processor.cb.exeptions; + +public class NotImplementedException extends RuntimeException { + + /** + * + */ + private static final long serialVersionUID = -5704193843480029363L; + +} diff --git a/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/impl/AbstractJoinImp.java b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/impl/AbstractJoinImp.java new file mode 100644 index 000000000..e78d69b17 --- /dev/null +++ b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/impl/AbstractJoinImp.java @@ -0,0 +1,206 @@ +package com.sap.olingo.jpa.processor.cb.impl; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import javax.annotation.Nonnull; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.Expression; +import javax.persistence.criteria.From; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.Path; +import javax.persistence.criteria.Predicate; +import javax.persistence.metamodel.Bindable; +import javax.persistence.metamodel.MapAttribute; +import javax.persistence.metamodel.PluralAttribute; +import javax.persistence.metamodel.SingularAttribute; + +import com.sap.olingo.jpa.metadata.api.JPAJoinColumn; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEntityType; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAOnConditionItem; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAPath; +import com.sap.olingo.jpa.processor.cb.api.SqlConvertable; +import com.sap.olingo.jpa.processor.cb.api.SqlJoinType; +import com.sap.olingo.jpa.processor.cb.exeptions.NotImplementedException; +import com.sap.olingo.jpa.processor.cb.impl.PredicateImpl.BinaryExpressionPredicate; +import com.sap.olingo.jpa.processor.cb.joiner.StringBuilderCollector; + +abstract class AbstractJoinImp extends FromImpl implements Join { + + protected Predicate on; + protected final From related; + + AbstractJoinImp(@Nonnull final JPAEntityType type, @Nonnull final From parent, + @Nonnull final AliasBuilder ab, @Nonnull CriteriaBuilder cb) { + super(type, ab, cb); + this.related = parent; + } + + AbstractJoinImp(@Nonnull final JPAEntityType type, @Nonnull final From parent, final JPAPath path, + @Nonnull final AliasBuilder ab, @Nonnull CriteriaBuilder cb) { + super(type, path, ab, cb); + this.related = parent; + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public StringBuilder asSQL(final StringBuilder statment) { + + statment.append(" ") + .append(SqlJoinType.byJoinType(getJoinType())) + .append(" "); + if (!getJoins().isEmpty()) + statment.append(OPENING_BRACKET); + statment.append(st.getTableName()); + tableAlias.ifPresent(p -> statment.append(" ").append(p)); + getJoins().stream().collect(new StringBuilderCollector.ExpressionCollector(statment, " ")); + if (!getJoins().isEmpty()) + statment.append(CLOSING_BRACKET); + statment.append(" ON "); + ((SqlConvertable) on).asSQL(statment); + return statment; + } + + /** + * Return the predicate that corresponds to the ON + * restriction(s) on the join, or null if no ON condition + * has been specified. + * @return the ON restriction predicate + * @since Java Persistence 2.1 + */ + @Override + public Predicate getOn() { + return on; + } + + /** + * Return the parent of the join. + * @return join parent + */ + @Override + public From getParent() { + return related; + } + + /** + * Modify the join to restrict the result according to the + * specified ON condition and return the join object. + * Replaces the previous ON condition, if any. + * @param restriction a simple or compound boolean expression + * @return the modified join object + * @since Java Persistence 2.1 + */ + @Override + public Join on(@Nonnull final Expression restriction) { + on = (Predicate) restriction; + return this; + } + + /** + * Modify the join to restrict the result according to the + * specified ON condition and return the join object. + * Replaces the previous ON condition, if any. + * @param restrictions zero or more restriction predicates + * @return the modified join object + * @since Java Persistence 2.1 + */ + @Override + public Join on(@Nonnull final Predicate... restrictions) { + on = PredicateImpl.and(restrictions); + return this; + } + + protected void createOn(final List items, final JPAEntityType targetType) { + for (final JPAOnConditionItem item : items) { + final Predicate eq = createOnElement(item, targetType); + if (on == null) + on = eq; + else + on = new PredicateImpl.AndPredicate(on, eq); + } + } + + private Predicate createOnElement(final JPAOnConditionItem item, final JPAEntityType target) { + final Expression left = new PathImpl<>(item.getLeftPath(), Optional.of((PathImpl) related), + ((PathImpl) related).st, ((FromImpl) related).tableAlias); + final Expression right = new PathImpl<>(item.getRightPath(), Optional.of(this), + target, tableAlias); + return new PredicateImpl.BinaryExpressionPredicate(PredicateImpl.BinaryExpressionPredicate.Operation.EQ, left, + right); + } + + protected void createOn(final List joinInformation) { + for (final JPAJoinColumn column : joinInformation) { + final Predicate eq = createOnElement(column); + if (on == null) + on = eq; + else + on = new PredicateImpl.AndPredicate(on, eq); + } + } + + @SuppressWarnings("unchecked") + private BinaryExpressionPredicate createOnElement(final JPAJoinColumn column) { + return new PredicateImpl.BinaryExpressionPredicate(PredicateImpl.BinaryExpressionPredicate.Operation.EQ, + new RawPath<>(column.getName(), ((FromImpl) related).tableAlias), + new RawPath<>(column.getReferencedColumnName(), tableAlias)); + } + + class RawPath extends ExpressionImpl implements Path { + + private final String dbFieldName; + private final Optional table; + + public RawPath(final String dbFieldName, final Optional table) { + this.dbFieldName = dbFieldName; + this.table = table; + } + + @Override + public StringBuilder asSQL(StringBuilder statment) { + table.ifPresent(p -> { + statment.append(p); + statment.append(DOT); + }); + statment.append(dbFieldName); + return statment; + } + + @Override + public Bindable getModel() { + throw new NotImplementedException(); + } + + @Override + public Path getParentPath() { + throw new NotImplementedException(); + } + + @Override + public Path get(SingularAttribute attribute) { + throw new NotImplementedException(); + } + + @Override + public > Expression get(PluralAttribute collection) { + throw new NotImplementedException(); + } + + @Override + public > Expression get(MapAttribute map) { + throw new NotImplementedException(); + } + + @Override + public Expression> type() { + throw new NotImplementedException(); + } + + @Override + public Path get(String attributeName) { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/impl/AliasBuilder.java b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/impl/AliasBuilder.java new file mode 100644 index 000000000..a2fcabc7b --- /dev/null +++ b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/impl/AliasBuilder.java @@ -0,0 +1,19 @@ +package com.sap.olingo.jpa.processor.cb.impl; + +class AliasBuilder { + private static final String ALIAS_PREFIX = "E"; + private int aliasCount = 0; + private final String prefix; + + AliasBuilder() { + this(ALIAS_PREFIX); + } + + AliasBuilder(final String prefix) { + this.prefix = prefix; + } + + String getNext() { + return prefix + aliasCount++; + } +} diff --git a/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/impl/CollectionJoinImpl.java b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/impl/CollectionJoinImpl.java new file mode 100644 index 000000000..b5a1f3b88 --- /dev/null +++ b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/impl/CollectionJoinImpl.java @@ -0,0 +1,119 @@ +package com.sap.olingo.jpa.processor.cb.impl; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import javax.annotation.Nonnull; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.JoinType; +import javax.persistence.criteria.Path; +import javax.persistence.metamodel.Attribute; + +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPACollectionAttribute; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAEntityType; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAPath; +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAStructuredType; +import com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException; +import com.sap.olingo.jpa.processor.cb.api.SqlConvertable; +import com.sap.olingo.jpa.processor.cb.api.SqlJoinType; +import com.sap.olingo.jpa.processor.cb.exeptions.NotImplementedException; + +class CollectionJoinImpl extends AbstractJoinImp { + + private final JPACollectionAttribute attribute; + + CollectionJoinImpl(@Nonnull final JPAPath path, @Nonnull final FromImpl parent, + @Nonnull final AliasBuilder aliasBuilder, @Nonnull CriteriaBuilder cb) throws ODataJPAModelException { + + super(determineEt(path, parent), parent, determinePath(path), aliasBuilder, cb); + this.attribute = (JPACollectionAttribute) path.getLeaf(); + + createOn(attribute.asAssociation().getJoinTable().getRawJoinInformation()); + } + + private static JPAPath determinePath(final JPAPath path) throws ODataJPAModelException { + return ((JPACollectionAttribute) path.getLeaf()).asAssociation().getJoinTable().getEntityType() == null + ? path : null; + } + + private static JPAEntityType determineEt(final JPAPath path, final FromImpl parent) + throws ODataJPAModelException { + return Optional.ofNullable(((JPACollectionAttribute) path.getLeaf()).asAssociation().getJoinTable().getEntityType()) + .orElse(parent.st); + } + + @Override + public StringBuilder asSQL(final StringBuilder statment) { + + try { + statment.append(" ") + .append(SqlJoinType.byJoinType(getJoinType())) + .append(" ") + .append(attribute.asAssociation() + .getJoinTable() + .getTableName()); + + tableAlias.ifPresent(p -> statment.append(" ").append(p)); + statment.append(" ON "); + return ((SqlConvertable) on).asSQL(statment); + } catch (ODataJPAModelException e) { + throw new IllegalStateException("Target DB table of collection attribute &1 of &2" + .replace("&1", attribute.getInternalName()) + .replace("&2", st.getInternalName())); + } + } + + @Override + List> resolvePathElements() { + final List> pathList = new ArrayList<>(); + try { + if (!attribute.isComplex()) { + final JPAStructuredType source = attribute.asAssociation().getSourceType(); + pathList.add(new PathImpl<>(source.getPath(attribute.asAssociation().getAlias()), + parent, st, tableAlias)); + } else { + final JPAStructuredType source = attribute.getStructuredType(); + for (final JPAPath p : source.getPathList()) { + pathList.add(new PathImpl<>(p, parent, st, tableAlias)); + } + } + } catch (ODataJPAModelException e) { + throw new IllegalStateException(); + } + return pathList; + } + + @Override + List getPathList() { + final List pathList = new ArrayList<>(); + try { + if (!attribute.isComplex()) { + final JPAStructuredType source = attribute.asAssociation().getSourceType(); + final JPAPath path = source.getPath(this.alias.orElse(attribute.getExternalName())); + pathList.add(path); + } else { + pathList.addAll(attribute.getStructuredType().getPathList().stream().filter(p -> !p.ignore()).collect(Collectors + .toList())); + } + } catch (ODataJPAModelException e) { + throw new IllegalStateException(); + } + return pathList; + } + + /** + * Return the metamodel attribute corresponding to the join. + * @return metamodel attribute corresponding to the join + */ + @Override + public Attribute getAttribute() { + throw new NotImplementedException(); + } + + @Override + public JoinType getJoinType() { + return JoinType.INNER; + } +} diff --git a/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/impl/CriteriaBuilderImpl.java b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/impl/CriteriaBuilderImpl.java new file mode 100644 index 000000000..e1f5f3570 --- /dev/null +++ b/jpa/odata-jpa-processor-cb/src/main/java/com/sap/olingo/jpa/processor/cb/impl/CriteriaBuilderImpl.java @@ -0,0 +1,1691 @@ +package com.sap.olingo.jpa.processor.cb.impl; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.sql.Date; +import java.sql.Time; +import java.sql.Timestamp; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import javax.annotation.Nonnull; +import javax.persistence.Tuple; +import javax.persistence.criteria.CollectionJoin; +import javax.persistence.criteria.CompoundSelection; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaDelete; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.CriteriaUpdate; +import javax.persistence.criteria.Expression; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.ListJoin; +import javax.persistence.criteria.MapJoin; +import javax.persistence.criteria.Order; +import javax.persistence.criteria.Path; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; +import javax.persistence.criteria.Selection; +import javax.persistence.criteria.SetJoin; +import javax.persistence.criteria.Subquery; + +import com.sap.olingo.jpa.metadata.core.edm.mapper.api.JPAServiceDocument; +import com.sap.olingo.jpa.processor.cb.api.SqlAggregation; +import com.sap.olingo.jpa.processor.cb.api.SqlArithmetic; +import com.sap.olingo.jpa.processor.cb.api.SqlConvertable; +import com.sap.olingo.jpa.processor.cb.api.SqlNullCheck; +import com.sap.olingo.jpa.processor.cb.api.SqlStringFunctions; +import com.sap.olingo.jpa.processor.cb.api.SqlSubQuery; +import com.sap.olingo.jpa.processor.cb.api.SqlTimeFunctions; +import com.sap.olingo.jpa.processor.cb.exeptions.NotImplementedException; +import com.sap.olingo.jpa.processor.cb.impl.ExpressionImpl.ParameterExpression; +import com.sap.olingo.jpa.processor.cb.impl.PredicateImpl.BinaryExpressionPredicate.Operation; + +class CriteriaBuilderImpl implements CriteriaBuilder { + + private final JPAServiceDocument sd; + private final ParameterBuffer parameter; + + CriteriaBuilderImpl(final JPAServiceDocument sd, final ParameterBuffer parameterBuffer) { + this.sd = sd; + this.parameter = parameterBuffer; + } + + /** + * Create an expression that returns the absolute value + * of its argument. + * @param x expression + * @return absolute value + */ + @Override + public Expression abs(@Nonnull final Expression x) { + throw new NotImplementedException(); + } + + /** + * Create an all expression over the subquery results. + * @param subquery subquery + * @return all expression + */ + @Override + public Expression all(@Nonnull final Subquery subquery) { + return new ExpressionImpl.SubQuery<>(subquery, SqlSubQuery.ALL); + } + + @Override + public Predicate and(final Expression x, final Expression y) { + return new PredicateImpl.AndPredicate(x, y); + } + + @Override + public Predicate and(final Predicate... restrictions) { + return PredicateImpl.and(restrictions); + } + + /** + * Create an any expression over the subquery results. + * This expression is equivalent to a some expression. + * @param subquery subquery + * @return any expression + */ + @Override + public Expression any(@Nonnull final Subquery subquery) { + return new ExpressionImpl.SubQuery<>(subquery, SqlSubQuery.ANY); + } + + /** + * Create an array-valued selection item. + * @param selections selection items + * @return array-valued compound selection + * @throws IllegalArgumentException if an argument is a + * tuple- or array-valued selection item + */ + @Override + public CompoundSelection array(@Nonnull final Selection... selections) { + throw new NotImplementedException(); + } + + /** + * Create an ordering by the ascending value of the expression. + * @param x expression used to define the ordering + * @return ascending ordering corresponding to the expression + */ + @Override + public Order asc(@Nonnull final Expression x) { + return new OrderImpl(true, Objects.requireNonNull((SqlConvertable) x)); + } + + /** + * Create an aggregate expression applying the avg operation. + * @param x expression representing input value to avg operation + * @return avg expression + */ + @Override + public Expression avg(@Nonnull final Expression x) { + throw new NotImplementedException(); + } + + /** + * Create a predicate for testing whether the first argument is + * between the second and third arguments in value. + * @param v expression + * @param x expression + * @param y expression + * @return between predicate + */ + @Override + public > Predicate between(@Nonnull final Expression v, + @Nonnull final Expression x, @Nonnull final Expression y) { + return new PredicateImpl.BetweenExpressionPredicate((ExpressionImpl) v, x, y); + } + + /** + * Create a predicate for testing whether the first argument is + * between the second and third arguments in value. + * @param v expression + * @param x value + * @param y value + * @return between predicate + */ + @Override + public > Predicate between(@Nonnull final Expression v, + @Nonnull final Y x, @Nonnull final Y y) { + return between(v, literal(x, v), literal(y, v)); + } + + /** + * Create a coalesce expression. + * @return coalesce expression + */ + @Override + public Coalesce coalesce() { + return new ExpressionImpl.CoalesceExpression<>(); + } + + /** + * Create an expression that returns null if all its arguments + * evaluate to null, and the value of the first non-null argument + * otherwise. + * @param x expression + * @param y expression + * @return coalesce expression + */ + @Override + public Expression coalesce(@Nonnull final Expression x, + @Nonnull final Expression y) { + return new ExpressionImpl.CoalesceExpression().value(x).value(y); + } + + /** + * Create an expression that returns null if all its arguments + * evaluate to null, and the value of the first non-null argument + * otherwise. + * @param x expression + * @param y value + * @return coalesce expression + */ + @Override + public Expression coalesce(@Nonnull final Expression x, @Nonnull final Y y) { + return new ExpressionImpl.CoalesceExpression().value(x).value(literal(y)); + } + + /** + * Create an expression for string concatenation. + * @param x string expression + * @param y string expression + * @return expression corresponding to concatenation + */ + @Override + public Expression concat(@Nonnull final Expression x, @Nonnull final Expression y) { + return new ExpressionImpl.ConcatExpression(x, y); + } + + /** + * Create an expression for string concatenation. + * @param x string expression + * @param y string + * @return expression corresponding to concatenation + */ + @Override + public Expression concat(@Nonnull final Expression x, @Nonnull final String y) { + return new ExpressionImpl.ConcatExpression(x, literal(y)); + } + + /** + * Create an expression for string concatenation. + * @param x string + * @param y string expression + * @return expression corresponding to concatenation + */ + @Override + public Expression concat(@Nonnull final String x, @Nonnull final Expression y) { + return new ExpressionImpl.ConcatExpression(literal(x), y); + } + + /** + * Create a conjunction (with zero conjuncts). + * A conjunction with zero conjuncts is true. + * @return and predicate + */ + @Override + public Predicate conjunction() { + throw new NotImplementedException(); + } + + /** + * Create a selection item corresponding to a constructor. + * This method is used to specify a constructor that will be + * applied to the results of the query execution. If the + * constructor is for an entity class, the resulting entities + * will be in the new state after the query is executed. + * @param resultClass class whose instance is to be constructed + * @param selections arguments to the constructor + * @return compound selection item + * @throws IllegalArgumentException if an argument is a + * tuple- or array-valued selection item + */ + @Override + public CompoundSelection construct(@Nonnull final Class resultClass, + @Nonnull final Selection... selections) { + throw new NotImplementedException(); + } + + /** + * Create an aggregate expression applying the count operation. + * @param x expression representing input value to count + * operation + * @return count expression + */ + @Override + public Expression count(@Nonnull final Expression x) { + return new ExpressionImpl.AggregationExpression<>(SqlAggregation.COUNT, x); + } + + /** + * Create an aggregate expression applying the count distinct + * operation. + * @param x expression representing input value to count distinct operation + * @return count distinct expression + */ + @Override + public Expression countDistinct(@Nonnull final Expression x) { + return count(new ExpressionImpl.DistinctExpression<>(x)); + } + + @Override + public CriteriaDelete createCriteriaDelete(final Class targetEntity) { + throw new NotImplementedException(); + } + + @Override + public CriteriaUpdate createCriteriaUpdate(final Class targetEntity) { + throw new NotImplementedException(); + } + + @Override + public CriteriaQuery createQuery() { + return new CriteriaQueryImpl<>(Object.class, sd, this); + } + + @Override + public CriteriaQuery createQuery(final Class resultClass) { + return new CriteriaQueryImpl<>(resultClass, sd, this); + } + + @Override + public CriteriaQuery createTupleQuery() { + return new CriteriaQueryImpl<>(Tuple.class, sd, this); + } + + @Override + public Expression currentDate() { + throw new NotImplementedException(); + } + + @Override + public Expression