PageRenderTime 33ms CodeModel.GetById 8ms RepoModel.GetById 0ms app.codeStats 0ms

/addon-jpa/addon/src/main/java/org/springframework/roo/addon/jpa/addon/entity/JpaFieldCreatorProvider.java

http://github.com/SpringSource/spring-roo
Java | 2376 lines | 1650 code | 362 blank | 364 comment | 430 complexity | 5ee7772f7ae4137df42e694359e103ef MD5 | raw file
  1. package org.springframework.roo.addon.jpa.addon.entity;
  2. import static org.springframework.roo.model.JdkJavaType.LIST;
  3. import static org.springframework.roo.model.JdkJavaType.SET;
  4. import static org.springframework.roo.model.JpaJavaType.ENTITY;
  5. import static org.springframework.roo.model.SpringJavaType.PERSISTENT;
  6. import static org.springframework.roo.shell.OptionContexts.PROJECT;
  7. import org.apache.commons.lang3.StringEscapeUtils;
  8. import org.apache.commons.lang3.StringUtils;
  9. import org.apache.commons.lang3.Validate;
  10. import org.apache.felix.scr.annotations.Component;
  11. import org.apache.felix.scr.annotations.Reference;
  12. import org.apache.felix.scr.annotations.Service;
  13. import org.osgi.framework.BundleContext;
  14. import org.osgi.framework.InvalidSyntaxException;
  15. import org.osgi.framework.ServiceReference;
  16. import org.osgi.service.component.ComponentContext;
  17. import org.springframework.roo.addon.field.addon.FieldCommands;
  18. import org.springframework.roo.addon.field.addon.FieldCreatorProvider;
  19. import org.springframework.roo.addon.jpa.addon.entity.factories.JpaEntityFactoryLocator;
  20. import org.springframework.roo.addon.plural.addon.PluralService;
  21. import org.springframework.roo.addon.test.providers.DataOnDemandCreatorProvider;
  22. import org.springframework.roo.classpath.PhysicalTypeCategory;
  23. import org.springframework.roo.classpath.PhysicalTypeDetails;
  24. import org.springframework.roo.classpath.PhysicalTypeMetadata;
  25. import org.springframework.roo.classpath.TypeLocationService;
  26. import org.springframework.roo.classpath.TypeManagementService;
  27. import org.springframework.roo.classpath.details.ClassOrInterfaceTypeDetails;
  28. import org.springframework.roo.classpath.details.FieldDetails;
  29. import org.springframework.roo.classpath.details.FieldMetadata;
  30. import org.springframework.roo.classpath.details.FieldMetadataBuilder;
  31. import org.springframework.roo.classpath.details.MemberHoldingTypeDetails;
  32. import org.springframework.roo.classpath.details.annotations.AnnotationAttributeValue;
  33. import org.springframework.roo.classpath.details.annotations.AnnotationMetadata;
  34. import org.springframework.roo.classpath.details.annotations.AnnotationMetadataBuilder;
  35. import org.springframework.roo.classpath.details.comments.CommentFormatter;
  36. import org.springframework.roo.classpath.operations.Cardinality;
  37. import org.springframework.roo.classpath.operations.Cascade;
  38. import org.springframework.roo.classpath.operations.DateTime;
  39. import org.springframework.roo.classpath.operations.EnumType;
  40. import org.springframework.roo.classpath.operations.Fetch;
  41. import org.springframework.roo.classpath.operations.jsr303.BooleanField;
  42. import org.springframework.roo.classpath.operations.jsr303.CollectionField;
  43. import org.springframework.roo.classpath.operations.jsr303.DateField;
  44. import org.springframework.roo.classpath.operations.jsr303.DateFieldPersistenceType;
  45. import org.springframework.roo.classpath.operations.jsr303.EmbeddedField;
  46. import org.springframework.roo.classpath.operations.jsr303.EnumField;
  47. import org.springframework.roo.classpath.operations.jsr303.ListField;
  48. import org.springframework.roo.classpath.operations.jsr303.NumericField;
  49. import org.springframework.roo.classpath.operations.jsr303.ReferenceField;
  50. import org.springframework.roo.classpath.operations.jsr303.SetField;
  51. import org.springframework.roo.classpath.operations.jsr303.StringField;
  52. import org.springframework.roo.classpath.operations.jsr303.UploadedFileContentType;
  53. import org.springframework.roo.classpath.operations.jsr303.UploadedFileField;
  54. import org.springframework.roo.classpath.scanner.MemberDetails;
  55. import org.springframework.roo.classpath.scanner.MemberDetailsScanner;
  56. import org.springframework.roo.metadata.MetadataService;
  57. import org.springframework.roo.model.DataType;
  58. import org.springframework.roo.model.EnumDetails;
  59. import org.springframework.roo.model.JavaSymbolName;
  60. import org.springframework.roo.model.JavaType;
  61. import org.springframework.roo.model.JdkJavaType;
  62. import org.springframework.roo.model.JpaJavaType;
  63. import org.springframework.roo.model.ReservedWords;
  64. import org.springframework.roo.model.RooEnumDetails;
  65. import org.springframework.roo.model.RooJavaType;
  66. import org.springframework.roo.model.SpringletsJavaType;
  67. import org.springframework.roo.project.LogicalPath;
  68. import org.springframework.roo.project.ProjectOperations;
  69. import org.springframework.roo.settings.project.ProjectSettingsService;
  70. import org.springframework.roo.shell.Converter;
  71. import org.springframework.roo.shell.ShellContext;
  72. import org.springframework.roo.support.logging.HandlerUtils;
  73. import java.lang.reflect.Modifier;
  74. import java.util.ArrayList;
  75. import java.util.Arrays;
  76. import java.util.List;
  77. import java.util.Set;
  78. import java.util.logging.Logger;
  79. /**
  80. * Provides field creation operations support for JPA entities by implementing
  81. * FieldCreatorProvider.
  82. *
  83. * @author Sergio Clares
  84. * @author Jose Manuel Vivó
  85. * @author Juan Carlos García
  86. * @author Fran Cardoso
  87. * @since 2.0
  88. */
  89. @Component
  90. @Service
  91. public class JpaFieldCreatorProvider implements FieldCreatorProvider {
  92. protected final static Logger LOGGER = HandlerUtils.getLogger(FieldCommands.class);
  93. //------------ OSGi component attributes ----------------//
  94. private BundleContext context;
  95. @Reference
  96. private TypeLocationService typeLocationService;
  97. @Reference
  98. private ProjectOperations projectOperations;
  99. @Reference
  100. private ProjectSettingsService projectSettings;
  101. @Reference
  102. private MetadataService metadataService;
  103. @Reference
  104. private TypeManagementService typeManagementService;
  105. @Reference
  106. private MemberDetailsScanner memberDetailsScanner;
  107. @Reference
  108. private PluralService pluralService;
  109. @Reference
  110. private DataOnDemandCreatorProvider dataOnDemandCreatorProvider;
  111. @Reference
  112. private JpaEntityFactoryLocator jpaEntityFactoryLocator;
  113. private Converter<JavaType> javaTypeConverter;
  114. private static final String SPRING_ROO_JPA_REQUIRE_SCHEMA_OBJECT_NAME =
  115. "spring.roo.jpa.require.schema-object-name";
  116. private static final String CARDINALITY = "cardinality";
  117. private static final String JOIN_TABLE = "joinTable";
  118. private static final String JOIN_COLUMN_NAME = "joinColumnName";
  119. private static final String ONE_TO_MANY = "ONE_TO_MANY";
  120. private static final String MANY_TO_MANY = "MANY_TO_MANY";
  121. private static final String TRUE = "true";
  122. protected void activate(final ComponentContext context) {
  123. this.context = context.getBundleContext();
  124. }
  125. protected void deactivate(final ComponentContext context) {
  126. this.context = null;
  127. }
  128. @Override
  129. public boolean isValid(JavaType javaType) {
  130. ClassOrInterfaceTypeDetails cid = typeLocationService.getTypeDetails(javaType);
  131. if (cid.getAnnotation(RooJavaType.ROO_JPA_ENTITY) != null
  132. || cid.getAnnotation(JpaJavaType.ENTITY) != null) {
  133. return true;
  134. }
  135. return false;
  136. }
  137. @Override
  138. public boolean isFieldManagementAvailable() {
  139. Set<ClassOrInterfaceTypeDetails> entities =
  140. typeLocationService.findClassesOrInterfaceDetailsWithAnnotation(JpaJavaType.ENTITY,
  141. RooJavaType.ROO_JPA_ENTITY);
  142. if (!entities.isEmpty()) {
  143. return true;
  144. }
  145. return false;
  146. }
  147. @Override
  148. public boolean isFieldEmbeddedAvailable() {
  149. return true;
  150. }
  151. @Override
  152. public boolean isFieldReferenceAvailable() {
  153. return true;
  154. }
  155. @Override
  156. public boolean isFieldCollectionAvailable() {
  157. return true;
  158. }
  159. /**
  160. * ROO-3710: Indicator that checks if exists some project setting that makes
  161. * table column parameter mandatory.
  162. *
  163. * @param shellContext
  164. * @return true if exists property
  165. * {@link #SPRING_ROO_JPA_REQUIRE_SCHEMA_OBJECT_NAME} on project
  166. * settings and its value is "true". If not, return false.
  167. */
  168. @Override
  169. public boolean isColumnMandatoryForFieldBoolean(ShellContext shellContext) {
  170. // Check if property 'spring.roo.jpa.require.schema-object-name' is defined
  171. // on
  172. // project settings
  173. String requiredSchemaObjectName =
  174. projectSettings.getProperty(SPRING_ROO_JPA_REQUIRE_SCHEMA_OBJECT_NAME);
  175. if (requiredSchemaObjectName != null && requiredSchemaObjectName.equals(TRUE)) {
  176. return true;
  177. }
  178. return false;
  179. }
  180. @Override
  181. public boolean isColumnVisibleForFieldBoolean(ShellContext shellContext) {
  182. return true;
  183. }
  184. @Override
  185. public boolean isTransientVisibleForFieldBoolean(ShellContext shellContext) {
  186. return true;
  187. }
  188. @Override
  189. public boolean isAssertFalseVisibleForFieldBoolean(ShellContext shellContext) {
  190. String param = shellContext.getParameters().get("assertTrue");
  191. if (param != null) {
  192. return false;
  193. }
  194. return true;
  195. }
  196. @Override
  197. public boolean isAssertTrueVisibleForFieldBoolean(ShellContext shellContext) {
  198. String param = shellContext.getParameters().get("assertFalse");
  199. if (param != null) {
  200. return false;
  201. }
  202. return true;
  203. }
  204. /**
  205. * ROO-3710: Indicator that checks if exists some project setting that makes
  206. * table column parameter mandatory.
  207. *
  208. * @param shellContext
  209. * @return true if exists property
  210. * {@link #SPRING_ROO_JPA_REQUIRE_SCHEMA_OBJECT_NAME} on project
  211. * settings and its value is "true". If not, return false.
  212. */
  213. @Override
  214. public boolean isColumnMandatoryForFieldDate(ShellContext shellContext) {
  215. // Check if property 'spring.roo.jpa.require.schema-object-name' is defined
  216. // on
  217. // project settings
  218. String requiredSchemaObjectName =
  219. projectSettings.getProperty(SPRING_ROO_JPA_REQUIRE_SCHEMA_OBJECT_NAME);
  220. if (requiredSchemaObjectName != null && requiredSchemaObjectName.equals(TRUE)) {
  221. return true;
  222. }
  223. return false;
  224. }
  225. @Override
  226. public boolean isColumnVisibleForFieldDate(ShellContext shellContext) {
  227. return true;
  228. }
  229. @Override
  230. public boolean isPersistenceTypeVisibleForFieldDate(ShellContext shellContext) {
  231. return true;
  232. }
  233. @Override
  234. public boolean isTransientVisibleForFieldDate(ShellContext shellContext) {
  235. return true;
  236. }
  237. @Override
  238. public boolean isFutureVisibleForFieldDate(ShellContext shellContext) {
  239. String past = shellContext.getParameters().get("past");
  240. if (past != null) {
  241. return false;
  242. }
  243. return true;
  244. }
  245. @Override
  246. public boolean isPastVisibleForFieldDate(ShellContext shellContext) {
  247. String past = shellContext.getParameters().get("future");
  248. if (past != null) {
  249. return false;
  250. }
  251. return true;
  252. }
  253. @Override
  254. public boolean areDateAndTimeFormatVisibleForFieldDate(ShellContext shellContext) {
  255. String dateTimeFormatPattern = shellContext.getParameters().get("dateTimeFormatPattern");
  256. if (dateTimeFormatPattern != null) {
  257. return false;
  258. }
  259. return true;
  260. }
  261. @Override
  262. public boolean isDateTimeFormatPatternVisibleForFieldDate(ShellContext shellContext) {
  263. String dateFormat = shellContext.getParameters().get("dateFormat");
  264. String timeFormat = shellContext.getParameters().get("timeFormat");
  265. if (dateFormat == null && timeFormat == null) {
  266. return true;
  267. }
  268. return false;
  269. }
  270. @Override
  271. public boolean isNotNullVisibleForFieldDate(ShellContext shellContext) {
  272. String antagonistParam = shellContext.getParameters().get("nullRequired");
  273. if (antagonistParam != null) {
  274. return false;
  275. }
  276. return true;
  277. }
  278. @Override
  279. public boolean isNullRequiredVisibleForFieldDate(ShellContext shellContext) {
  280. String antagonistParam = shellContext.getParameters().get("notNull");
  281. if (antagonistParam != null) {
  282. return false;
  283. }
  284. return true;
  285. }
  286. /**
  287. * ROO-3710: Indicator that checks if exists some project setting that makes
  288. * table column parameter mandatory.
  289. *
  290. * @param shellContext
  291. * @return true if exists property
  292. * {@link #SPRING_ROO_JPA_REQUIRE_SCHEMA_OBJECT_NAME} on project
  293. * settings and its value is "true". If not, return false.
  294. */
  295. @Override
  296. public boolean isColumnMandatoryForFieldEnum(ShellContext shellContext) {
  297. // Check if property 'spring.roo.jpa.require.schema-object-name' is defined
  298. // on
  299. // project settings
  300. String requiredSchemaObjectName =
  301. projectSettings.getProperty(SPRING_ROO_JPA_REQUIRE_SCHEMA_OBJECT_NAME);
  302. if (requiredSchemaObjectName != null && requiredSchemaObjectName.equals(TRUE)) {
  303. return true;
  304. }
  305. return false;
  306. }
  307. @Override
  308. public boolean isColumnVisibleForFieldEnum(ShellContext shellContext) {
  309. return true;
  310. }
  311. @Override
  312. public boolean isEnumTypeVisibleForFieldEnum(ShellContext shellContext) {
  313. return true;
  314. }
  315. @Override
  316. public boolean isTransientVisibleForFieldEnum(ShellContext shellContext) {
  317. return true;
  318. }
  319. @Override
  320. public boolean isNotNullVisibleForFieldEnum(ShellContext shellContext) {
  321. String antagonistParam = shellContext.getParameters().get("nullRequired");
  322. if (antagonistParam != null) {
  323. return false;
  324. }
  325. return true;
  326. }
  327. @Override
  328. public boolean isNullRequiredVisibleForFieldEnum(ShellContext shellContext) {
  329. String antagonistParam = shellContext.getParameters().get("notNull");
  330. if (antagonistParam != null) {
  331. return false;
  332. }
  333. return true;
  334. }
  335. /**
  336. * ROO-3710: Indicator that checks if exists some project setting that makes
  337. * table column parameter mandatory.
  338. *
  339. * @param shellContext
  340. * @return true if exists property
  341. * {@link #SPRING_ROO_JPA_REQUIRE_SCHEMA_OBJECT_NAME} on project
  342. * settings and its value is "true". If not, return false.
  343. */
  344. @Override
  345. public boolean isColumnMandatoryForFieldNumber(ShellContext shellContext) {
  346. // Check if property 'spring.roo.jpa.require.schema-object-name' is defined
  347. // on
  348. // project settings
  349. String requiredSchemaObjectName =
  350. projectSettings.getProperty(SPRING_ROO_JPA_REQUIRE_SCHEMA_OBJECT_NAME);
  351. if (requiredSchemaObjectName != null && requiredSchemaObjectName.equals(TRUE)) {
  352. return true;
  353. }
  354. return false;
  355. }
  356. @Override
  357. public boolean isColumnVisibleForFieldNumber(ShellContext shellContext) {
  358. return true;
  359. }
  360. @Override
  361. public boolean isUniqueVisibleForFieldNumber(ShellContext shellContext) {
  362. return true;
  363. }
  364. @Override
  365. public boolean isTransientVisibleForFieldNumber(ShellContext shellContext) {
  366. return true;
  367. }
  368. @Override
  369. public boolean isNullRequiredVisibleForFieldNumber(ShellContext shellContext) {
  370. // Check if `notNull`is specified
  371. String notNullParam = shellContext.getParameters().get("notNull");
  372. if (notNullParam != null) {
  373. return false;
  374. }
  375. // Check if type is primitive
  376. String typeValue = shellContext.getParameters().get("type");
  377. if (StringUtils.isNotBlank(typeValue)) {
  378. JavaType numberType =
  379. getJavaTypeConverter().convertFromText(typeValue, JavaType.class, "java-number");
  380. if (numberType.isPrimitive()) {
  381. return false;
  382. }
  383. }
  384. return true;
  385. }
  386. @Override
  387. public boolean isNotNullVisibleForFieldNumber(ShellContext shellContext) {
  388. String antagonistParam = shellContext.getParameters().get("nullRequired");
  389. if (antagonistParam != null) {
  390. return false;
  391. }
  392. return true;
  393. }
  394. /**
  395. * ROO-3710: Indicator that checks if exists some project setting that makes
  396. * table column parameter mandatory.
  397. *
  398. * @param shellContext
  399. * @return true if exists property
  400. * {@link #SPRING_ROO_JPA_REQUIRE_SCHEMA_OBJECT_NAME} on project
  401. * settings and its value is "true". If not, return false.
  402. */
  403. @Override
  404. public boolean isColumnMandatoryForFieldReference(ShellContext shellContext) {
  405. // Check if property 'spring.roo.jpa.require.schema-object-name' is defined
  406. // on
  407. // project settings
  408. String requiredSchemaObjectName =
  409. projectSettings.getProperty(SPRING_ROO_JPA_REQUIRE_SCHEMA_OBJECT_NAME);
  410. if (requiredSchemaObjectName != null && requiredSchemaObjectName.equals(TRUE)) {
  411. return true;
  412. }
  413. return false;
  414. }
  415. @Override
  416. public boolean isJoinColumnNameVisibleForFieldReference(ShellContext shellContext) {
  417. return true;
  418. }
  419. @Override
  420. public boolean isReferencedColumnNameVisibleForFieldReference(ShellContext shellContext) {
  421. return true;
  422. }
  423. @Override
  424. public boolean isFetchVisibleForFieldReference(ShellContext shellContext) {
  425. return true;
  426. }
  427. @Override
  428. public boolean isCascadeTypeVisibleForFieldReference(ShellContext shellContext) {
  429. return true;
  430. }
  431. @Override
  432. public boolean isNotNullVisibleForFieldReference(ShellContext shellContext) {
  433. String antagonistParam = shellContext.getParameters().get("nullRequired");
  434. if (antagonistParam != null) {
  435. return false;
  436. }
  437. return true;
  438. }
  439. @Override
  440. public boolean isNullRequiredVisibleForFieldReference(ShellContext shellContext) {
  441. String antagonistParam = shellContext.getParameters().get("notNull");
  442. if (antagonistParam != null) {
  443. return false;
  444. }
  445. return true;
  446. }
  447. @Override
  448. public boolean areOptionalParametersVisibleForFieldSet(ShellContext shellContext) {
  449. String cardinality = shellContext.getParameters().get(CARDINALITY);
  450. String joinColumnNameParam = shellContext.getParameters().get(JOIN_COLUMN_NAME);
  451. String joinTableParam = shellContext.getParameters().get(JOIN_TABLE);
  452. // Check if property 'spring.roo.jpa.require.schema-object-name' is defined
  453. // on project settings
  454. boolean requiredSchemaObjectName =
  455. TRUE.equals(projectSettings.getProperty(SPRING_ROO_JPA_REQUIRE_SCHEMA_OBJECT_NAME));
  456. if (!requiredSchemaObjectName) {
  457. return true;
  458. }
  459. if (MANY_TO_MANY.equals(cardinality)) {
  460. return true;
  461. }
  462. if (joinColumnNameParam == null && joinTableParam == null) {
  463. return false;
  464. }
  465. return true;
  466. }
  467. @Override
  468. public boolean isJoinColumnNameMandatoryForFieldSet(ShellContext shellContext) {
  469. String cardinality = shellContext.getParameters().get(CARDINALITY);
  470. if (MANY_TO_MANY.equals(cardinality)) {
  471. // Never available for MANY-TO-MANY relationships
  472. return false;
  473. }
  474. // Check if param 'joinTable' is already defined
  475. String joinColumnNameParam = shellContext.getParameters().get(JOIN_COLUMN_NAME);
  476. // Check if property 'spring.roo.jpa.require.schema-object-name' is defined
  477. // on project settings
  478. boolean requiredSchemaObjectName =
  479. (TRUE).equals(projectSettings.getProperty(SPRING_ROO_JPA_REQUIRE_SCHEMA_OBJECT_NAME));
  480. if (requiredSchemaObjectName && joinColumnNameParam != null) {
  481. return true;
  482. }
  483. return false;
  484. }
  485. /**
  486. * ROO-3710: Indicator that checks if exists some project setting that makes
  487. * table column parameter mandatory.
  488. *
  489. * @param shellContext
  490. * @return true if exists property
  491. * {@link #SPRING_ROO_JPA_REQUIRE_SCHEMA_OBJECT_NAME} on project
  492. * settings and its value is "true". If not, return false.
  493. */
  494. @Override
  495. public boolean areJoinTableParamsMandatoryForFieldSet(ShellContext shellContext) {
  496. // Check if property 'spring.roo.jpa.require.schema-object-name' is defined
  497. // on project settings
  498. String requiredSchemaObjectName =
  499. projectSettings.getProperty(SPRING_ROO_JPA_REQUIRE_SCHEMA_OBJECT_NAME);
  500. // See if joinTable param has been specified
  501. String joinTableParam = shellContext.getParameters().get(JOIN_TABLE);
  502. if (joinTableParam != null && requiredSchemaObjectName != null
  503. && requiredSchemaObjectName.equals(TRUE)) {
  504. return true;
  505. }
  506. return false;
  507. }
  508. /**
  509. * ROO-3710: Indicator that checks if exists some project setting that makes
  510. * table column parameter mandatory.
  511. *
  512. * @param shellContext
  513. * @return true if exists property
  514. * {@link #SPRING_ROO_JPA_REQUIRE_SCHEMA_OBJECT_NAME} on project
  515. * settings and its value is "true". If not, return false.
  516. */
  517. @Override
  518. public boolean isJoinTableMandatoryForFieldSet(ShellContext shellContext) {
  519. String cardinality = shellContext.getParameters().get(CARDINALITY);
  520. String joinTableParam = shellContext.getParameters().get(JOIN_TABLE);
  521. // Check if property 'spring.roo.jpa.require.schema-object-name' is defined
  522. // on project settings
  523. String requiredSchemaObjectName =
  524. projectSettings.getProperty(SPRING_ROO_JPA_REQUIRE_SCHEMA_OBJECT_NAME);
  525. if (requiredSchemaObjectName != null && requiredSchemaObjectName.equals(TRUE)) {
  526. // property 'spring.roo.jpa.require.schema-object-name' is defined 'true'
  527. if (cardinality != null && cardinality.equals(MANY_TO_MANY)) {
  528. // mandatory if cardinality is MANY_TO_MANY
  529. return true;
  530. } else if ((cardinality == null || cardinality.equals(ONE_TO_MANY)) && joinTableParam != null) {
  531. // mandatory if cardinality is ONE_TO_MANY and '--joinTable' is already specified
  532. return true;
  533. }
  534. }
  535. return false;
  536. }
  537. @Override
  538. public boolean areJoinTableParamsVisibleForFieldSet(ShellContext shellContext) {
  539. String joinTableParam = shellContext.getParameters().get(JOIN_TABLE);
  540. if (joinTableParam != null) {
  541. return true;
  542. }
  543. return false;
  544. }
  545. @Override
  546. public boolean isMappedByVisibleForFieldSet(ShellContext shellContext) {
  547. return true;
  548. }
  549. @Override
  550. public boolean isCardinalityVisibleForFieldSet(ShellContext shellContext) {
  551. if (!areOptionalParametersVisibleForFieldList(shellContext)) {
  552. return false;
  553. }
  554. // Only can be ONE-TO-MANY if '--joinColumnName' has been specified
  555. return !StringUtils.isNotBlank(shellContext.getParameters().get(JOIN_COLUMN_NAME));
  556. }
  557. @Override
  558. public boolean isFetchVisibleForFieldSet(ShellContext shellContext) {
  559. return true;
  560. }
  561. @Override
  562. public boolean isJoinTableVisibleForFieldSet(ShellContext shellContext) {
  563. String joinColumnNameParam = shellContext.getParameters().get(JOIN_COLUMN_NAME);
  564. if (joinColumnNameParam == null) {
  565. // Visible if '--joinColumnName' is not specified
  566. return true;
  567. }
  568. return false;
  569. }
  570. @Override
  571. public boolean isJoinColumnNameVisibleForFieldSet(ShellContext shellContext) {
  572. String joinTableParam = shellContext.getParameters().get(JOIN_TABLE);
  573. String cardinality = shellContext.getParameters().get(CARDINALITY);
  574. if (MANY_TO_MANY.equals(cardinality)) {
  575. // Never available for MANY-TO-MANY relationships
  576. return false;
  577. }
  578. if (joinTableParam == null) {
  579. // Visible if '--joinTable' is not specified
  580. return true;
  581. }
  582. return false;
  583. }
  584. @Override
  585. public boolean isReferencedColumnNameVisibleForFieldSet(ShellContext shellContext) {
  586. String joinColumnNameParam = shellContext.getParameters().get(JOIN_COLUMN_NAME);
  587. if (joinColumnNameParam == null) {
  588. return false;
  589. }
  590. return true;
  591. }
  592. @Override
  593. public boolean isNotNullVisibleForFieldSet(ShellContext shellContext) {
  594. String antagonistParam = shellContext.getParameters().get("nullRequired");
  595. if (antagonistParam != null) {
  596. return false;
  597. }
  598. return true;
  599. }
  600. @Override
  601. public boolean isNullRequiredVisibleForFieldSet(ShellContext shellContext) {
  602. String antagonistParam = shellContext.getParameters().get("notNull");
  603. if (antagonistParam != null) {
  604. return false;
  605. }
  606. return true;
  607. }
  608. @Override
  609. public boolean areOptionalParametersVisibleForFieldList(ShellContext shellContext) {
  610. String cardinality = shellContext.getParameters().get(CARDINALITY);
  611. String joinColumnNameParam = shellContext.getParameters().get(JOIN_COLUMN_NAME);
  612. String joinTableParam = shellContext.getParameters().get(JOIN_TABLE);
  613. // Check if property 'spring.roo.jpa.require.schema-object-name' is defined
  614. // on project settings
  615. boolean requiredSchemaObjectName =
  616. TRUE.equals(projectSettings.getProperty(SPRING_ROO_JPA_REQUIRE_SCHEMA_OBJECT_NAME));
  617. if (!requiredSchemaObjectName) {
  618. return true;
  619. }
  620. if (MANY_TO_MANY.equals(cardinality)) {
  621. return true;
  622. }
  623. if (joinColumnNameParam == null && joinTableParam == null) {
  624. return false;
  625. }
  626. return true;
  627. }
  628. @Override
  629. public boolean areJoinTableParamsVisibleForFieldList(ShellContext shellContext) {
  630. String joinTableParam = shellContext.getParameters().get(JOIN_TABLE);
  631. if (joinTableParam != null) {
  632. return true;
  633. }
  634. return false;
  635. }
  636. @Override
  637. public boolean isJoinTableMandatoryForFieldList(ShellContext shellContext) {
  638. String cardinality = shellContext.getParameters().get(CARDINALITY);
  639. String joinTableParam = shellContext.getParameters().get(JOIN_TABLE);
  640. // Check if property 'spring.roo.jpa.require.schema-object-name' is defined
  641. // on project settings
  642. String requiredSchemaObjectName =
  643. projectSettings.getProperty(SPRING_ROO_JPA_REQUIRE_SCHEMA_OBJECT_NAME);
  644. if (requiredSchemaObjectName != null && requiredSchemaObjectName.equals(TRUE)) {
  645. // property 'spring.roo.jpa.require.schema-object-name' is defined 'true'
  646. if (cardinality != null && cardinality.equals(MANY_TO_MANY)) {
  647. // mandatory if cardinality is MANY_TO_MANY
  648. return true;
  649. } else if ((cardinality == null || cardinality.equals(ONE_TO_MANY)) && joinTableParam != null) {
  650. // mandatory if cardinality is ONE_TO_MANY and '--joinTable' is already specified
  651. return true;
  652. }
  653. }
  654. return false;
  655. }
  656. @Override
  657. public boolean isJoinTableVisibleForFieldList(ShellContext shellContext) {
  658. String joinColumnNameParam = shellContext.getParameters().get(JOIN_COLUMN_NAME);
  659. if (joinColumnNameParam == null) {
  660. // Visible if '--joinColumnName' is not specified
  661. return true;
  662. }
  663. return false;
  664. }
  665. @Override
  666. public boolean isJoinColumnNameVisibleForFieldList(ShellContext shellContext) {
  667. String joinTableParam = shellContext.getParameters().get(JOIN_TABLE);
  668. String cardinality = shellContext.getParameters().get(CARDINALITY);
  669. if ("MANY_TO_MANY".equals(cardinality)) {
  670. // Never available for MANY-TO-MANY relationships
  671. return false;
  672. }
  673. if (joinTableParam == null) {
  674. // Visible if '--joinTable' is not specified
  675. return true;
  676. }
  677. return false;
  678. }
  679. @Override
  680. public boolean isReferencedColumnNameVisibleForFieldList(ShellContext shellContext) {
  681. String joinColumnNameParam = shellContext.getParameters().get(JOIN_COLUMN_NAME);
  682. if (joinColumnNameParam == null) {
  683. return false;
  684. }
  685. return true;
  686. }
  687. /**
  688. * ROO-3710: Indicator that checks if exists some project setting that makes
  689. * table column parameter mandatory.
  690. *
  691. * @param shellContext
  692. * @return true if exists property
  693. * {@link #SPRING_ROO_JPA_REQUIRE_SCHEMA_OBJECT_NAME} on project
  694. * settings and its value is "true". If not, return false.
  695. */
  696. @Override
  697. public boolean areJoinTableParamsMandatoryForFieldList(ShellContext shellContext) {
  698. // Check if property 'spring.roo.jpa.require.schema-object-name' is defined
  699. // on project settings
  700. String requiredSchemaObjectName =
  701. projectSettings.getProperty(SPRING_ROO_JPA_REQUIRE_SCHEMA_OBJECT_NAME);
  702. // See if joinTable param has been specified
  703. String joinTableParam = shellContext.getParameters().get(JOIN_TABLE);
  704. if (joinTableParam != null && requiredSchemaObjectName != null
  705. && requiredSchemaObjectName.equals(TRUE)) {
  706. return true;
  707. }
  708. return false;
  709. }
  710. @Override
  711. public boolean isMappedByVisibleForFieldList(ShellContext shellContext) {
  712. return true;
  713. }
  714. @Override
  715. public boolean isCardinalityVisibleForFieldList(ShellContext shellContext) {
  716. if (!areOptionalParametersVisibleForFieldList(shellContext)) {
  717. return false;
  718. }
  719. // Only can be ONE-TO-MANY if '--joinColumnName' has been specified
  720. return !StringUtils.isNotBlank(shellContext.getParameters().get(JOIN_COLUMN_NAME));
  721. }
  722. @Override
  723. public boolean isFetchVisibleForFieldList(ShellContext shellContext) {
  724. return true;
  725. }
  726. @Override
  727. public boolean isJoinColumnNameMandatoryForFieldList(ShellContext shellContext) {
  728. String cardinality = shellContext.getParameters().get(CARDINALITY);
  729. if (MANY_TO_MANY.equals(cardinality)) {
  730. // Never available for MANY-TO-MANY relationships
  731. return false;
  732. }
  733. // Check if param 'joinTable' is already defined
  734. String joinColumnNameParam = shellContext.getParameters().get(JOIN_COLUMN_NAME);
  735. // Check if property 'spring.roo.jpa.require.schema-object-name' is defined
  736. // on project settings
  737. boolean requiredSchemaObjectName =
  738. (TRUE).equals(projectSettings.getProperty(SPRING_ROO_JPA_REQUIRE_SCHEMA_OBJECT_NAME));
  739. if (requiredSchemaObjectName && joinColumnNameParam != null) {
  740. return true;
  741. }
  742. return false;
  743. }
  744. @Override
  745. public boolean isNotNullVisibleForFieldList(ShellContext shellContext) {
  746. String antagonistParam = shellContext.getParameters().get("nullRequired");
  747. if (antagonistParam != null) {
  748. return false;
  749. }
  750. return true;
  751. }
  752. @Override
  753. public boolean isNullRequiredVisibleForFieldList(ShellContext shellContext) {
  754. String antagonistParam = shellContext.getParameters().get("notNull");
  755. if (antagonistParam != null) {
  756. return false;
  757. }
  758. return true;
  759. }
  760. /**
  761. * ROO-3710: Indicator that checks if exists some project setting that makes
  762. * table column parameter mandatory.
  763. *
  764. * @param shellContext
  765. * @return true if exists property
  766. * {@link #SPRING_ROO_JPA_REQUIRE_SCHEMA_OBJECT_NAME} on project
  767. * settings and its value is "true". If not, return false.
  768. */
  769. @Override
  770. public boolean isColumnMandatoryForFieldString(ShellContext shellContext) {
  771. // Check if property 'spring.roo.jpa.require.schema-object-name' is defined
  772. // on
  773. // project settings
  774. String requiredSchemaObjectName =
  775. projectSettings.getProperty(SPRING_ROO_JPA_REQUIRE_SCHEMA_OBJECT_NAME);
  776. if (requiredSchemaObjectName != null && requiredSchemaObjectName.equals(TRUE)) {
  777. return true;
  778. }
  779. return false;
  780. }
  781. @Override
  782. public boolean isColumnVisibleForFieldString(ShellContext shellContext) {
  783. return true;
  784. }
  785. @Override
  786. public boolean isUniqueVisibleForFieldString(ShellContext shellContext) {
  787. return true;
  788. }
  789. @Override
  790. public boolean isTransientVisibleForFieldString(ShellContext shellContext) {
  791. return true;
  792. }
  793. @Override
  794. public boolean isLobVisibleForFieldString(ShellContext shellContext) {
  795. return true;
  796. }
  797. @Override
  798. public boolean isNotNullVisibleForFieldString(ShellContext shellContext) {
  799. String antagonistParam = shellContext.getParameters().get("nullRequired");
  800. if (antagonistParam != null) {
  801. return false;
  802. }
  803. return true;
  804. }
  805. @Override
  806. public boolean isNullRequiredVisibleForFieldString(ShellContext shellContext) {
  807. String antagonistParam = shellContext.getParameters().get("notNull");
  808. if (antagonistParam != null) {
  809. return false;
  810. }
  811. return true;
  812. }
  813. /**
  814. * ROO-3710: Indicator that checks if exists some project setting that makes
  815. * table column parameter mandatory.
  816. *
  817. * @param shellContext
  818. * @return true if exists property
  819. * {@link #SPRING_ROO_JPA_REQUIRE_SCHEMA_OBJECT_NAME} on project
  820. * settings and its value is "true". If not, return false.
  821. */
  822. @Override
  823. public boolean isColumnMandatoryForFieldFile(ShellContext shellContext) {
  824. // Check if property 'spring.roo.jpa.require.schema-object-name' is defined
  825. // on
  826. // project settings
  827. String requiredSchemaObjectName =
  828. projectSettings.getProperty(SPRING_ROO_JPA_REQUIRE_SCHEMA_OBJECT_NAME);
  829. if (requiredSchemaObjectName != null && requiredSchemaObjectName.equals(TRUE)) {
  830. return true;
  831. }
  832. return false;
  833. }
  834. @Override
  835. public boolean isColumnVisibleForFieldFile(ShellContext shellContext) {
  836. return true;
  837. }
  838. /**
  839. * ROO-3710: Indicator that checks if exists some project setting that makes
  840. * table column parameter mandatory.
  841. *
  842. * @param shellContext
  843. * @return true if exists property
  844. * {@link #SPRING_ROO_JPA_REQUIRE_SCHEMA_OBJECT_NAME} on project
  845. * settings and its value is "true". If not, return false.
  846. */
  847. public boolean isColumnMandatoryForFieldOther(ShellContext shellContext) {
  848. // Check if property 'spring.roo.jpa.require.schema-object-name' is defined
  849. // on
  850. // project settings
  851. String requiredSchemaObjectName =
  852. projectSettings.getProperty(SPRING_ROO_JPA_REQUIRE_SCHEMA_OBJECT_NAME);
  853. if (requiredSchemaObjectName != null && requiredSchemaObjectName.equals(TRUE)) {
  854. return true;
  855. }
  856. return false;
  857. }
  858. public boolean isColumnVisibleForFieldOther(ShellContext shellContext) {
  859. return true;
  860. }
  861. public boolean isTransientVisibleForFieldOther(ShellContext shellContext) {
  862. return true;
  863. }
  864. @Override
  865. public boolean isNotNullVisibleForFieldOther(ShellContext shellContext) {
  866. String antagonistParam = shellContext.getParameters().get("nullRequired");
  867. if (antagonistParam != null) {
  868. return false;
  869. }
  870. return true;
  871. }
  872. @Override
  873. public boolean isNullRequiredVisibleForFieldOther(ShellContext shellContext) {
  874. String antagonistParam = shellContext.getParameters().get("notNull");
  875. if (antagonistParam != null) {
  876. return false;
  877. }
  878. return true;
  879. }
  880. @Override
  881. public void createBooleanField(ClassOrInterfaceTypeDetails javaTypeDetails, boolean primitive,
  882. JavaSymbolName fieldName, boolean notNull, boolean assertFalse, boolean assertTrue,
  883. String column, String comment, String value, boolean permitReservedWords,
  884. boolean transientModifier) {
  885. createBooleanField(javaTypeDetails, primitive, fieldName, notNull, assertFalse, assertTrue,
  886. column, comment, value, permitReservedWords, transientModifier, null);
  887. }
  888. @Override
  889. public void createBooleanField(ClassOrInterfaceTypeDetails javaTypeDetails, boolean primitive,
  890. JavaSymbolName fieldName, boolean notNull, boolean assertFalse, boolean assertTrue,
  891. String column, String comment, String value, boolean permitReservedWords,
  892. boolean transientModifier, List<AnnotationMetadataBuilder> extraAnnotations) {
  893. final String physicalTypeIdentifier = javaTypeDetails.getDeclaredByMetadataId();
  894. final BooleanField fieldDetails =
  895. new BooleanField(physicalTypeIdentifier, primitive ? JavaType.BOOLEAN_PRIMITIVE
  896. : JavaType.BOOLEAN_OBJECT, fieldName);
  897. fieldDetails.setNotNull(notNull);
  898. fieldDetails.setAssertFalse(assertFalse);
  899. fieldDetails.setAssertTrue(assertTrue);
  900. if (column != null) {
  901. fieldDetails.setColumn(column);
  902. }
  903. if (comment != null) {
  904. fieldDetails.setComment(comment);
  905. }
  906. if (value != null) {
  907. fieldDetails.setValue(value);
  908. }
  909. if (extraAnnotations != null && !extraAnnotations.isEmpty()) {
  910. fieldDetails.addAnnotations(extraAnnotations);
  911. }
  912. insertField(fieldDetails, permitReservedWords, transientModifier);
  913. }
  914. @Override
  915. public void createDateField(ClassOrInterfaceTypeDetails javaTypeDetails, JavaType fieldType,
  916. JavaSymbolName fieldName, boolean notNull, boolean nullRequired, boolean future,
  917. boolean past, DateFieldPersistenceType persistenceType, String column, String comment,
  918. DateTime dateFormat, DateTime timeFormat, String pattern, String value,
  919. boolean permitReservedWords, boolean transientModifier) {
  920. createDateField(javaTypeDetails, fieldType, fieldName, notNull, nullRequired, future, past,
  921. persistenceType, column, comment, dateFormat, timeFormat, pattern, value,
  922. permitReservedWords, transientModifier, null);
  923. }
  924. @Override
  925. public void createDateField(ClassOrInterfaceTypeDetails javaTypeDetails, JavaType fieldType,
  926. JavaSymbolName fieldName, boolean notNull, boolean nullRequired, boolean future,
  927. boolean past, DateFieldPersistenceType persistenceType, String column, String comment,
  928. DateTime dateFormat, DateTime timeFormat, String pattern, String value,
  929. boolean permitReservedWords, boolean transientModifier,
  930. List<AnnotationMetadataBuilder> extraAnnotations) {
  931. final String physicalTypeIdentifier = javaTypeDetails.getDeclaredByMetadataId();
  932. final DateField fieldDetails = new DateField(physicalTypeIdentifier, fieldType, fieldName);
  933. fieldDetails.setNotNull(notNull);
  934. fieldDetails.setNullRequired(nullRequired);
  935. fieldDetails.setFuture(future);
  936. fieldDetails.setPast(past);
  937. if (JdkJavaType.isDateField(fieldType)) {
  938. fieldDetails.setPersistenceType(persistenceType != null ? persistenceType
  939. : DateFieldPersistenceType.JPA_TIMESTAMP);
  940. }
  941. if (column != null) {
  942. fieldDetails.setColumn(column);
  943. }
  944. if (comment != null) {
  945. fieldDetails.setComment(comment);
  946. }
  947. if (dateFormat != null) {
  948. fieldDetails.setDateFormat(dateFormat);
  949. }
  950. if (timeFormat != null) {
  951. fieldDetails.setTimeFormat(timeFormat);
  952. }
  953. if (pattern != null) {
  954. fieldDetails.setPattern(pattern);
  955. }
  956. if (value != null) {
  957. fieldDetails.setValue(value);
  958. }
  959. if (extraAnnotations != null && !extraAnnotations.isEmpty()) {
  960. fieldDetails.addAnnotations(extraAnnotations);
  961. }
  962. insertField(fieldDetails, permitReservedWords, transientModifier);
  963. }
  964. @Override
  965. public void createEnumField(ClassOrInterfaceTypeDetails cid, JavaType fieldType,
  966. JavaSymbolName fieldName, String column, boolean notNull, boolean nullRequired,
  967. EnumType enumType, String comment, boolean permitReservedWords, boolean transientModifier) {
  968. createEnumField(cid, fieldType, fieldName, column, notNull, nullRequired, enumType, comment,
  969. permitReservedWords, transientModifier, null);
  970. }
  971. @Override
  972. public void createEnumField(ClassOrInterfaceTypeDetails cid, JavaType fieldType,
  973. JavaSymbolName fieldName, String column, boolean notNull, boolean nullRequired,
  974. EnumType enumType, String comment, boolean permitReservedWords, boolean transientModifier,
  975. List<AnnotationMetadataBuilder> extraAnnotations) {
  976. ClassOrInterfaceTypeDetails typeDetails = typeLocationService.getTypeDetails(fieldType);
  977. Validate.isTrue(typeDetails.getPhysicalTypeCategory() == PhysicalTypeCategory.ENUMERATION,
  978. "The field type is not an enum class.");
  979. final String physicalTypeIdentifier = cid.getDeclaredByMetadataId();
  980. final EnumField fieldDetails = new EnumField(physicalTypeIdentifier, fieldType, fieldName);
  981. if (column != null) {
  982. fieldDetails.setColumn(column);
  983. }
  984. fieldDetails.setNotNull(notNull);
  985. fieldDetails.setNullRequired(nullRequired);
  986. if (enumType != null) {
  987. fieldDetails.setEnumType(enumType);
  988. }
  989. if (comment != null) {
  990. fieldDetails.setComment(comment);
  991. }
  992. if (extraAnnotations != null && !extraAnnotations.isEmpty()) {
  993. fieldDetails.addAnnotations(extraAnnotations);
  994. }
  995. insertField(fieldDetails, permitReservedWords, transientModifier);
  996. }
  997. @Override
  998. public void createEmbeddedField(JavaType typeName, JavaType fieldType, JavaSymbolName fieldName,
  999. boolean permitReservedWords) {
  1000. createEmbeddedField(typeName, fieldType, fieldName, permitReservedWords, null);
  1001. }
  1002. @Override
  1003. public void createEmbeddedField(JavaType typeName, JavaType fieldType, JavaSymbolName fieldName,
  1004. boolean permitReservedWords, List<AnnotationMetadataBuilder> extraAnnotations) {
  1005. // Check if the requested entity is a JPA @Entity
  1006. final ClassOrInterfaceTypeDetails javaTypeDetails =
  1007. typeLocationService.getTypeDetails(typeName);
  1008. Validate.notNull(javaTypeDetails, "The type specified, '%s', doesn't exist", typeName);
  1009. final String physicalTypeIdentifier = javaTypeDetails.getDeclaredByMetadataId();
  1010. final PhysicalTypeMetadata targetTypeMetadata =
  1011. (PhysicalTypeMetadata) metadataService.get(physicalTypeIdentifier);
  1012. Validate
  1013. .notNull(targetTypeMetadata,
  1014. "The specified target '--class' does not exist or can not be found. Please create this type first.");
  1015. final PhysicalTypeDetails targetPtd = targetTypeMetadata.getMemberHoldingTypeDetails();
  1016. Validate.isInstanceOf(MemberHoldingTypeDetails.class, targetPtd);
  1017. final ClassOrInterfaceTypeDetails targetTypeCid = (ClassOrInterfaceTypeDetails) targetPtd;
  1018. final MemberDetails memberDetails =
  1019. memberDetailsScanner.getMemberDetails(this.getClass().getName(), targetTypeCid);
  1020. Validate
  1021. .isTrue(
  1022. memberDetails.getAnnotation(ENTITY) != null
  1023. || memberDetails.getAnnotation(PERSISTENT) != null,
  1024. "The field embedded command is only applicable to JPA @Entity or Spring Data @Persistent target types.");
  1025. final EmbeddedField fieldDetails =
  1026. new EmbeddedField(physicalTypeIdentifier, fieldType, fieldName);
  1027. if (extraAnnotations != null && !extraAnnotations.isEmpty()) {
  1028. fieldDetails.addAnnotations(extraAnnotations);
  1029. }
  1030. insertField(fieldDetails, permitReservedWords, false);
  1031. }
  1032. @Override
  1033. public void createNumericField(ClassOrInterfaceTypeDetails javaTypeDetails, JavaType fieldType,
  1034. boolean primitive, Set<String> legalNumericPrimitives, JavaSymbolName fieldName,
  1035. boolean notNull, boolean nullRequired, String decimalMin, String decimalMax,
  1036. Integer digitsInteger, Integer digitsFraction, Long min, Long max, String column,
  1037. String comment, boolean unique, String value, boolean permitReservedWords,
  1038. boolean transientModifier) {
  1039. createNumericField(javaTypeDetails, fieldType, primitive, legalNumericPrimitives, fieldName,
  1040. notNull, nullRequired, decimalMin, decimalMax, digitsInteger, digitsFraction, min, max,
  1041. column, comment, unique, value, permitReservedWords, transientModifier, null);
  1042. }
  1043. @Override
  1044. public void createNumericField(ClassOrInterfaceTypeDetails javaTypeDetails, JavaType fieldType,
  1045. boolean primitive, Set<String> legalNumericPrimitives, JavaSymbolName fieldName,
  1046. boolean notNull, boolean nullRequired, String decimalMin, String decimalMax,
  1047. Integer digitsInteger, Integer digitsFraction, Long min, Long max, String column,
  1048. String comment, boolean unique, String value, boolean permitReservedWords,
  1049. boolean transientModifier, List<AnnotationMetadataBuilder> extraAnnotations) {
  1050. final String physicalTypeIdentifier = javaTypeDetails.getDeclaredByMetadataId();
  1051. if (primitive && legalNumericPrimitives.contains(fieldType.getFullyQualifiedTypeName())) {
  1052. fieldType =
  1053. new JavaType(fieldType.getFullyQualifiedTypeName(), 0, DataType.PRIMITIVE, null, null);
  1054. }
  1055. final NumericField fieldDetails =
  1056. new NumericField(physicalTypeIdentifier, fieldType, fieldName);
  1057. fieldDetails.setNotNull(notNull);
  1058. fieldDetails.setNullRequired(nullRequired);
  1059. if (decimalMin != null) {
  1060. fieldDetails.setDecimalMin(decimalMin);
  1061. }
  1062. if (decimalMax != null) {
  1063. fieldDetails.setDecimalMax(decimalMax);
  1064. }
  1065. if (digitsInteger != null) {
  1066. fieldDetails.setDigitsInteger(digitsInteger);
  1067. }
  1068. if (digitsFraction != null) {
  1069. fieldDetails.setDigitsFraction(digitsFraction);
  1070. }
  1071. if (min != null) {
  1072. fieldDetails.setMin(min);
  1073. }
  1074. if (max != null) {
  1075. fieldDetails.setMax(max);
  1076. }
  1077. if (column != null) {
  1078. fieldDetails.setColumn(column);
  1079. }
  1080. if (comment != null) {
  1081. fieldDetails.setComment(comment);
  1082. }
  1083. if (unique) {
  1084. fieldDetails.setUnique(true);
  1085. }
  1086. if (value != null) {
  1087. fieldDetails.setValue(value);
  1088. }
  1089. if (extraAnnotations != null && !extraAnnotations.isEmpty()) {
  1090. fieldDetails.addAnnotations(extraAnnotations);
  1091. }
  1092. Validate.isTrue(fieldDetails.isDigitsSetCorrectly(),
  1093. "Must specify both --digitsInteger and --digitsFraction for @Digits to be added");
  1094. insertField(fieldDetails, permitReservedWords, transientModifier);
  1095. }
  1096. @Override
  1097. public void createReferenceField(JavaType typeName, JavaType fieldType, JavaSymbolName fieldName,
  1098. boolean aggregation, JavaSymbolName mappedBy, Cascade[] cascadeType, boolean notNull,
  1099. String joinColumnName, String referencedColumnName, Fetch fetch, String comment,
  1100. boolean permitReservedWords, Boolean orphanRemoval, boolean isForce, String formatExpression,
  1101. String formatMessage) {
  1102. final ClassOrInterfaceTypeDetails childCid = typeLocationService.getTypeDetails(fieldType);
  1103. final ClassOrInterfaceTypeDetails parentCid = typeLocationService.getTypeDetails(typeName);
  1104. Validate.notNull(parentCid, "The type specified, '%s', doesn't exist", typeName);
  1105. Validate
  1106. .notNull(
  1107. childCid,
  1108. "The specified target '--type' does not exist or can not be found. Please create this type first.",
  1109. fieldType);
  1110. // Check if parent field exist
  1111. checkFieldExists(fieldName, isForce, parentCid, "fieldName");
  1112. if (mappedBy == null) {
  1113. // generate mappedBy name from uncapitalized parentClass name
  1114. mappedBy = new JavaSymbolName(StringUtils.uncapitalize(typeName.getSimpleTypeName()));
  1115. }
  1116. // Check that child 'mappedBy' field isn't equal to child type name uncapitalized
  1117. Validate.isTrue(
  1118. !StringUtils.uncapitalize(fieldType.getSimpleTypeName()).equals(mappedBy.getSymbolName()),
  1119. "Child entity field can not have the same name as the referenced entity ('%s') name in "
  1120. + "lower camel case ('%s'). Please assign it other value using '--mappedBy' option.",
  1121. fieldType.getSimpleTypeName(), mappedBy.getSymbolName());
  1122. // Check if child field exist
  1123. checkFieldExists(mappedBy, false, childCid, "mappedBy");
  1124. // Check if the requested entity is a JPA @Entity
  1125. final MemberDetails childMemberDetails =
  1126. memberDetailsScanner.getMemberDetails(this.getClass().getName(), childCid);
  1127. final AnnotationMetadata entityAnnotation = childMemberDetails.getAnnotation(ENTITY);
  1128. final AnnotationMetadata persistentAnnotation = childMemberDetails.getAnnotation(PERSISTENT);
  1129. Validate
  1130. .isTrue(
  1131. entityAnnotation != null || persistentAnnotation != null,
  1132. "The field reference command is only applicable to JPA @Entity or Spring Data @Persistent target types.");
  1133. // Prepare parent field
  1134. if (cascadeType == null) {
  1135. // prepare cascadType
  1136. if (aggregation) {
  1137. cascadeType = Cascade.MERGE_PERSIST;
  1138. } else {
  1139. // Compsition
  1140. cascadeType = Cascade.ALL_ARRAY;
  1141. }
  1142. }
  1143. if (fetch == null) {
  1144. fetch = Fetch.LAZY;
  1145. }
  1146. final ReferenceField parentFieldDetails =
  1147. new ReferenceField(parentCid.getDeclaredByMetadataId(), fieldType, fieldName,
  1148. Cardinality.ONE_TO_ONE, cascadeType);
  1149. parentFieldDetails.setFetch(fetch);
  1150. AnnotationMetadataBuilder rooJpaRelationAnnotation =
  1151. new AnnotationMetadataBuilder(RooJavaType.ROO_JPA_RELATION);
  1152. if (aggregation) {
  1153. rooJpaRelationAnnotation.addEnumAttribute("type", RooEnumDetails.RELATION_TYPE_AGGREGATION);
  1154. } else {
  1155. rooJpaRelationAnnotation.addEnumAttribute("type", RooEnumDetails.RELATION_TYPE_COMPOSITION);
  1156. }
  1157. parentFieldDetails.addAdditionaAnnotation(rooJpaRelationAnnotation);
  1158. if (comment != null) {
  1159. parentFieldDetails.setComment(comment);
  1160. }
  1161. if (orphanRemoval == null && !aggregation) {
  1162. // composition
  1163. orphanRemoval = true;
  1164. }
  1165. parentFieldDetails.setOrphanRemoval(orphanRemoval);
  1166. parentFieldDetails.setMappedBy(mappedBy);
  1167. // ROO-3868: New entity visualization support using a new format annotation
  1168. parentFieldDetails.addAdditionaAnnotation(buildEntityFormatAnnotation(formatExpression,
  1169. formatMessage, fieldName.getSymbolName()));
  1170. // Prepare child files
  1171. final ReferenceField childFieldDetails =
  1172. new ReferenceField(childCid.getDeclaredByMetadataId(), typeName, mappedBy,
  1173. Cardinality.ONE_TO_ONE, null);
  1174. childFieldDetails.setFetch(fetch);
  1175. if (joinColumnName != null) {
  1176. if (referencedColumnName != null) {
  1177. Validate.notNull(joinColumnName,
  1178. "@JoinColumn name is required if specifying a referencedColumnName");
  1179. childFieldDetails.setJoinColumn(joinColumnName, referencedColumnName);
  1180. } else {
  1181. childFieldDetails.setJoinColumn(joinColumnName);
  1182. }
  1183. }
  1184. childFieldDetails.setNotNull(notNull);
  1185. // ROO-3868: New entity visualization support using a new format annotation
  1186. childFieldDetails.addAdditionaAnnotation(buildEntityFormatAnnotation(formatExpression,
  1187. formatMessage, fieldName.getSymbolName()));
  1188. // insert child field
  1189. insertField(childFieldDetails, permitReservedWords, false, true);
  1190. // insert parent field
  1191. insertField(parentFieldDetails, permitReservedWords, false, true);
  1192. }
  1193. @Override
  1194. public void createSetField(JavaType typeName, JavaType fieldType, JavaSymbolName fieldName,
  1195. Cardinality cardinality, Cascade[] cascadeType, boolean notNull, Integer sizeMin,
  1196. Integer sizeMax, JavaSymbolName mappedBy, Fetch fetch, String comment, String joinColumnName,
  1197. String referencedColumnName, String joinTable, String joinColumns, String referencedColumns,
  1198. String inverseJoinColumns, String inverseReferencedColumns, boolean permitReservedWords,
  1199. Boolean aggregation, Boolean orphanRemoval, boolean isForce, String formatExpression,
  1200. String formatMessage) {
  1201. createCollectionField(typeName, fieldType, fieldName, cardinality, cascadeType, notNull,
  1202. sizeMin, sizeMax, mappedBy, fetch, comment, joinColumnName, referencedColumnName,
  1203. joinTable, joinColumns, referencedColumns, inverseJoinColumns, inverseReferencedColumns,
  1204. permitReservedWords, aggregation, orphanRemoval, isForce, false, formatExpression,
  1205. formatMessage);
  1206. }
  1207. /**
  1208. * Implementation for {@link #createSetField(JavaType, JavaType, JavaSymbolName, Cardinality, Cascade[], boolean, Integer, Integer, JavaSymbolName, Fetch, String, String, String, String, String, String, boolean, Boolean, Boolean, boolean)}
  1209. * and
  1210. * {@link #createListField(ClassOrInterfaceTypeDetails, Cardinality, JavaType, JavaType, JavaSymbolName, Cascade, boolean, boolean, Integer, Integer, JavaSymbolName, Fetch, String, String, String, String, String, String, boolean, boolean)}
  1211. *
  1212. * @param typeName
  1213. * @param fieldType
  1214. * @param fieldName
  1215. * @param cardinality
  1216. * @param cascadeType
  1217. * @param notNull
  1218. * @param sizeMin
  1219. * @param sizeMax
  1220. * @param mappedBy
  1221. * @param fetch
  1222. * @param comment
  1223. * @param joinColumnName
  1224. * @param referencedColumnName
  1225. * @param joinTable
  1226. * @param joinColumns
  1227. * @param referencedColumns
  1228. * @param inverseJoinColumns
  1229. * @param inverseReferencedColumns
  1230. * @param permitReservedWords
  1231. * @param aggregation
  1232. * @param orphanRemoval
  1233. * @param isForce
  1234. * @param isList true generates List, false generates Set
  1235. * @param formatExpression
  1236. * @param formatMessage
  1237. */
  1238. public void createCollectionField(JavaType typeName, JavaType fieldType,
  1239. JavaSymbolName fieldName, Cardinality cardinality, Cascade[] cascadeType, boolean notNull,
  1240. Integer sizeMin, Integer sizeMax, JavaSymbolName mappedBy, Fetch fetch, String comment,
  1241. String joinColumnName, String referencedColumnName, String joinTable, String joinColumns,
  1242. String referencedColumns, String inverseJoinColumns, String inverseReferencedColumns,
  1243. boolean permitReservedWords, Boolean aggregation, Boolean orphanRemoval, boolean isForce,
  1244. boolean isList, String formatExpression, String formatMessage) {
  1245. // Check if property 'spring.roo.jpa.require.schema-object-name' is defined
  1246. // on
  1247. // project settings
  1248. String requiredSchemaObjectName =
  1249. projectSettings.getProperty(SPRING_ROO_JPA_REQUIRE_SCHEMA_OBJECT_NAME);
  1250. // 'joinTable' or 'joinColumnName' is required if property is true
  1251. if (requiredSchemaObjectName != null && requiredSchemaObjectName.equals(TRUE)
  1252. && joinTable == null && joinColumnName == null) {
  1253. throw new IllegalArgumentException("You must specify one of: 'joinTable' or 'joinColumnName'");
  1254. }
  1255. final ClassOrInterfaceTypeDetails childCid = typeLocationService.getTypeDetails(fieldType);
  1256. final ClassOrInterfaceTypeDetails parentCid = typeLocationService.getTypeDetails(typeName);
  1257. Validate.notNull(parentCid, "The type specified, '%s', doesn't exist", typeName);
  1258. Validate
  1259. .notNull(
  1260. childCid,
  1261. "The specified target '--type' does not exist or can not be found. Please create this type first.",
  1262. fieldType);
  1263. // Check if parent field exist
  1264. checkFieldExists(fieldName, isForce, parentCid, "fieldName");
  1265. // Check if the requested entity is a JPA @Entity
  1266. final MemberDetails childMemberDetails =
  1267. memberDetailsScanner.getMemberDetails(this.getClass().getName(), childCid);
  1268. final AnnotationMetadata entityAnnotation = childMemberDetails.getAnnotation(ENTITY);
  1269. final AnnotationMetadata persistentAnnotation = childMemberDetails.getAnnotation(PERSISTENT);
  1270. boolean isEnumeration = false;
  1271. if (childCid.getPhysicalTypeCategory() == PhysicalTypeCategory.ENUMERATION) {
  1272. isEnumeration = true;
  1273. } else if (entityAnnotation != null || persistentAnnotation != null) {
  1274. // Target is JPA entity
  1275. } else {
  1276. throw new IllegalStateException(
  1277. "The field set command is only applicable to enum, JPA @Entity or Spring Data @Persistence elements");
  1278. }
  1279. if (isEnumeration) {
  1280. // Enumeration
  1281. createCollectionEnumeration(parentCid, fieldType, fieldName, permitReservedWords, sizeMin,
  1282. sizeMax, comment, notNull, false);
  1283. } else {
  1284. // JPA
  1285. if (mappedBy == null) {
  1286. // generate mappedBy name from uncapitalized parentClass name
  1287. if (cardinality == Cardinality.MANY_TO_MANY) {
  1288. // Get plural
  1289. mappedBy =
  1290. new JavaSymbolName(StringUtils.uncapitalize(pluralService.getPlural(parentCid)));
  1291. } else {
  1292. mappedBy =
  1293. new JavaSymbolName(StringUtils.uncapitalize(parentCid.getType().getSimpleTypeName()));
  1294. }
  1295. }
  1296. // Check that child 'mappedBy' field isn't equal to child type name uncapitalized
  1297. Validate
  1298. .isTrue(
  1299. !StringUtils.uncapitalize(fieldType.getSimpleTypeName()).equals(
  1300. mappedBy.getSymbolName()),
  1301. "Child entity field can not have the same name as the referenced entity ('%s') name in "
  1302. + "lower camel case ('%s'). Please assign it other value using '--mappedBy' option.",
  1303. fieldType.getSimpleTypeName(), mappedBy.getSymbolName());
  1304. if (fetch == null) {
  1305. fetch = Fetch.LAZY;
  1306. }
  1307. switch (cardinality) {
  1308. case ONE_TO_MANY:
  1309. createParentFieldOfToManyRelation(parentCid, childCid, fieldName, fieldType,
  1310. Cardinality.ONE_TO_MANY, permitReservedWords, sizeMin, sizeMax, comment, notNull,
  1311. mappedBy, fetch, aggregation, orphanRemoval, cascadeType, isList);
  1312. createChildFieldOfOneToManyRelation(childCid, typeName, permitReservedWords, mappedBy,
  1313. fetch, joinColumnName, referencedColumnName, joinTable, joinColumns,
  1314. referencedColumns, inverseJoinColumns, inverseReferencedColumns, formatExpression,
  1315. formatMessage);
  1316. break;
  1317. case MANY_TO_MANY:
  1318. createParentFieldOfToManyRelation(parentCid, childCid, fieldName, fieldType,
  1319. Cardinality.MANY_TO_MANY, permitReservedWords, sizeMin, sizeMax, comment, notNull,
  1320. mappedBy, fetch, aggregation, orphanRemoval, cascadeType, isList);
  1321. createChildFieldOfManyToManyRelation(childCid, typeName, permitReservedWords, mappedBy,
  1322. fetch, joinTable, joinColumns, referencedColumns, inverseJoinColumns,
  1323. inverseReferencedColumns, isList);
  1324. break;
  1325. default:
  1326. throw new IllegalArgumentException(
  1327. "Cardinality must be ONE_TO_MANY or MANY_TO_MANY for the field set command");
  1328. }
  1329. // Add factory class for child entity if required
  1330. createChildEntityFactory(fieldType, typeName);
  1331. }
  1332. }
  1333. /**
  1334. * Create child field of an OneToMany relation
  1335. *
  1336. * @param childCid
  1337. * @param parentType
  1338. * @param permitReservedWords
  1339. * @param mappedBy
  1340. * @param fetch
  1341. * @param joinColumnName
  1342. * @param referencedColumnName
  1343. * @param joinTable
  1344. * @param joinColumns
  1345. * @param referencedColumns
  1346. * @param inverseJoinColumns
  1347. * @param inverseReferencedColumns
  1348. */
  1349. private void createChildFieldOfOneToManyRelation(ClassOrInterfaceTypeDetails childCid,
  1350. JavaType parentType, boolean permitReservedWords, JavaSymbolName mappedBy, Fetch fetch,
  1351. String joinColumnName, String referencedColumnName, String joinTable, String joinColumns,
  1352. String referencedColumns, String inverseJoinColumns, String inverseReferencedColumns,
  1353. String formatExpression, String formatMessage) {
  1354. final ReferenceField childFieldDetails =
  1355. new ReferenceField(childCid.getDeclaredByMetadataId(), parentType, mappedBy,
  1356. Cardinality.MANY_TO_ONE, null);
  1357. childFieldDetails.setFetch(fetch);
  1358. if (StringUtils.isNotBlank(joinTable) || StringUtils.isNotBlank(inverseJoinColumns)
  1359. || StringUtils.isNotBlank(joinColumns)) {
  1360. if (StringUtils.isNotBlank(inverseJoinColumns)) {
  1361. }
  1362. // Create strings arrays and set @JoinTable annotation
  1363. String[] joinColumnsArray = null;
  1364. String[] referencedColumnsArray = null;
  1365. String[] inverseJoinColumnsArray = null;
  1366. String[] inverseReferencedColumnsArray = null;
  1367. if (joinColumns != null) {
  1368. joinColumnsArray = joinColumns.replace(" ", "").split(",");
  1369. }
  1370. if (referencedColumns != null) {
  1371. referencedColumnsArray = referencedColumns.replace(" ", "").split(",");
  1372. }
  1373. if (inverseJoinColumns != null) {
  1374. inverseJoinColumnsArray = inverseJoinColumns.replace(" ", "").split(",");
  1375. }
  1376. if (inverseReferencedColumns != null) {
  1377. inverseReferencedColumnsArray = inverseReferencedColumns.replace(" ", "").split(",");
  1378. }
  1379. // Validate same number of elements
  1380. if (joinColumnsArray != null && referencedColumnsArray != null) {
  1381. Validate.isTrue(joinColumnsArray.length == referencedColumnsArray.length,
  1382. "--joinColumns and --referencedColumns must have same number of column values");
  1383. }
  1384. if (inverseJoinColumnsArray != null && inverseReferencedColumnsArray != null) {
  1385. Validate
  1386. .isTrue(inverseJoinColumnsArray.length == inverseReferencedColumnsArray.length,
  1387. "--inverseJoinColumns and --inverseReferencedColumns must have same number of column values");
  1388. }
  1389. // JoinTable set
  1390. childFieldDetails.setJoinAnnotations(joinTable, joinColumnsArray, referencedColumnsArray,
  1391. inverseJoinColumnsArray, inverseReferencedColumnsArray);
  1392. } else if (StringUtils.isNotBlank(joinColumnName)) {
  1393. if (StringUtils.isNotBlank(referencedColumnName)) {
  1394. childFieldDetails.setJoinColumn(joinColumnName, referencedColumnName);
  1395. } else {
  1396. childFieldDetails.setJoinColumn(joinColumnName);
  1397. }
  1398. }
  1399. childFieldDetails.addAdditionaAnnotation(buildEntityFormatAnnotation(formatExpression,
  1400. formatMessage, mappedBy.getSymbolName()));
  1401. insertField(childFieldDetails, permitReservedWords, false, true);
  1402. }
  1403. /**
  1404. * Create child field of a ManyToMany relation
  1405. *
  1406. * @param childCid
  1407. * @param parentType
  1408. * @param permitReservedWords
  1409. * @param mappedBy
  1410. * @param fetch
  1411. * @param joinTable
  1412. * @param joinColumns
  1413. * @param referencedColumns
  1414. * @param inverseJoinColumns
  1415. * @param inverseReferencedColumns
  1416. * @param isList
  1417. */
  1418. private void createChildFieldOfManyToManyRelation(ClassOrInterfaceTypeDetails childCid,
  1419. JavaType parentType, boolean permitReservedWords, JavaSymbolName mappedBy, Fetch fetch,
  1420. String joinTable, String joinColumns, String referencedColumns, String inverseJoinColumns,
  1421. String inverseReferencedColumns, boolean isList) {
  1422. SetField childFieldDetails;
  1423. if (isList) {
  1424. childFieldDetails =
  1425. new ListField(childCid.getDeclaredByMetadataId(), new JavaType(
  1426. LIST.getFullyQualifiedTypeName(), 0, DataType.TYPE, null, Arrays.asList(parentType)),
  1427. mappedBy, parentType, Cardinality.MANY_TO_MANY, null, false);
  1428. } else {
  1429. childFieldDetails =
  1430. new SetField(childCid.getDeclaredByMetadataId(), new JavaType(
  1431. SET.getFullyQualifiedTypeName(), 0, DataType.TYPE, null, Arrays.asList(parentType)),
  1432. mappedBy, parentType, Cardinality.MANY_TO_MANY, null, false);
  1433. }
  1434. childFieldDetails.setFetch(fetch);
  1435. if (StringUtils.isNotBlank(joinTable) || StringUtils.isNotBlank(inverseJoinColumns)
  1436. || StringUtils.isNotBlank(joinColumns)) {
  1437. if (StringUtils.isNotBlank(inverseJoinColumns)) {
  1438. }
  1439. // Create strings arrays and set @JoinTable annotation
  1440. String[] joinColumnsArray = null;
  1441. String[] referencedColumnsArray = null;
  1442. String[] inverseJoinColumnsArray = null;
  1443. String[] inverseReferencedColumnsArray = null;
  1444. if (joinColumns != null) {
  1445. joinColumnsArray = joinColumns.replace(" ", "").split(",");
  1446. }
  1447. if (referencedColumns != null) {
  1448. referencedColumnsArray = referencedColumns.replace(" ", "").split(",");
  1449. }
  1450. if (inverseJoinColumns != null) {
  1451. inverseJoinColumnsArray = inverseJoinColumns.replace(" ", "").split(",");
  1452. }
  1453. if (inverseReferencedColumns != null) {
  1454. inverseReferencedColumnsArray = inverseReferencedColumns.replace(" ", "").split(",");
  1455. }
  1456. // Validate same number of elements
  1457. if (joinColumnsArray != null && referencedColumnsArray != null) {
  1458. Validate.isTrue(joinColumnsArray.length == referencedColumnsArray.length,
  1459. "--joinColumns and --referencedColumns must have same number of column values");
  1460. }
  1461. if (inverseJoinColumnsArray != null && inverseReferencedColumnsArray != null) {
  1462. Validate
  1463. .isTrue(inverseJoinColumnsArray.length == inverseReferencedColumnsArray.length,
  1464. "--inverseJoinColumns and --inverseReferencedColumns must have same number of column values");
  1465. }
  1466. // JoinTable set
  1467. childFieldDetails.setJoinAnnotations(joinTable, joinColumnsArray, referencedColumnsArray,
  1468. inverseJoinColumnsArray, inverseReferencedColumnsArray);
  1469. }
  1470. insertField(childFieldDetails, permitReservedWords, false, true);
  1471. }
  1472. /**
  1473. * Creates the Factory class of the child entity of relationship, only if parent entity has JPA unit tests.
  1474. *
  1475. * @param childType
  1476. * @param parentType
  1477. */
  1478. private void createChildEntityFactory(JavaType childType, JavaType parentType) {
  1479. // Find current JPA unit tests
  1480. Set<JavaType> unitTestTypes =
  1481. typeLocationService.findTypesWithAnnotation(RooJavaType.ROO_JPA_UNIT_TEST);
  1482. for (JavaType unitTestType : unitTestTypes) {
  1483. // Get the annotation @RooJpaUnitTest
  1484. ClassOrInterfaceTypeDetails cid = typeLocationService.getTypeDetails(unitTestType);
  1485. AnnotationMetadata rooUnitTestAnnotation = cid.getAnnotation(RooJavaType.ROO_JPA_UNIT_TEST);
  1486. // Check if parent entity has JPA unit test class
  1487. AnnotationAttributeValue<Object> targetClass =
  1488. rooUnitTestAnnotation.getAttribute("targetClass");
  1489. Validate.notNull(targetClass, String.format(
  1490. "'targetClass' attribute can't be found for annotation @RooJpaUnitTest in class %s",
  1491. unitTestType.getSimpleTypeName()));
  1492. if (parentType.equals(targetClass.getValue())) {
  1493. if (jpaEntityFactoryLocator.getFirstJpaEntityFactoryForEntity(childType) == null) {
  1494. // Create factory class for child entity if doesn't exist
  1495. dataOnDemandCreatorProvider.createEntityFactory(childType);
  1496. }
  1497. break;
  1498. }
  1499. }
  1500. }
  1501. /**
  1502. * Create parent field of a *ToMany relation
  1503. *
  1504. * @param parentCid
  1505. * @param childCid
  1506. * @param fieldName
  1507. * @param fieldType
  1508. * @param cardinality
  1509. * @param permitReservedWords
  1510. * @param sizeMin
  1511. * @param sizeMax
  1512. * @param comment
  1513. * @param notNull
  1514. * @param mappedBy
  1515. * @param fetch
  1516. * @param aggregation
  1517. * @param orphanRemoval
  1518. * @param cascadeType
  1519. * @param isList
  1520. */
  1521. private void createParentFieldOfToManyRelation(ClassOrInterfaceTypeDetails parentCid,
  1522. ClassOrInterfaceTypeDetails childCid, JavaSymbolName fieldName, JavaType fieldType,
  1523. Cardinality cardinality, boolean permitReservedWords, Integer sizeMin, Integer sizeMax,
  1524. String comment, boolean notNull, JavaSymbolName mappedBy, Fetch fetch, Boolean aggregation,
  1525. Boolean orphanRemoval, Cascade[] cascadeType, boolean isList) {
  1526. if (cascadeType == null) {
  1527. // prepare cascadType
  1528. if (aggregation) {
  1529. cascadeType = Cascade.MERGE_PERSIST;
  1530. } else {
  1531. // Composition
  1532. cascadeType = Cascade.ALL_ARRAY;
  1533. }
  1534. }
  1535. // Check if child field exist
  1536. checkFieldExists(mappedBy, false, childCid, "mappedBy");
  1537. SetField parentFieldDetails;
  1538. if (isList) {
  1539. parentFieldDetails =
  1540. new ListField(parentCid.getDeclaredByMetadataId(), new JavaType(
  1541. LIST.getFullyQualifiedTypeName(), 0, DataType.TYPE, null, Arrays.asList(fieldType)),
  1542. fieldName, fieldType, cardinality, cascadeType, false);
  1543. } else {
  1544. parentFieldDetails =
  1545. new SetField(parentCid.getDeclaredByMetadataId(), new JavaType(
  1546. SET.getFullyQualifiedTypeName(), 0, DataType.TYPE, null, Arrays.asList(fieldType)),
  1547. fieldName, fieldType, cardinality, cascadeType, false);
  1548. }
  1549. parentFieldDetails.setNotNull(notNull);
  1550. if (comment != null) {
  1551. parentFieldDetails.setComment(comment);
  1552. }
  1553. if (sizeMin != null) {
  1554. parentFieldDetails.setSizeMin(sizeMin);
  1555. }
  1556. if (sizeMax != null) {
  1557. parentFieldDetails.setSizeMax(sizeMax);
  1558. }
  1559. parentFieldDetails.setMappedBy(mappedBy);
  1560. parentFieldDetails.setFetch(fetch);
  1561. if (orphanRemoval == null) {
  1562. if (aggregation) {
  1563. orphanRemoval = false;
  1564. } else {
  1565. orphanRemoval = true;
  1566. }
  1567. }
  1568. AnnotationMetadataBuilder rooJpaRelationAnnotation =
  1569. new AnnotationMetadataBuilder(RooJavaType.ROO_JPA_RELATION);
  1570. if (aggregation) {
  1571. rooJpaRelationAnnotation.addEnumAttribute("type", RooEnumDetails.RELATION_TYPE_AGGREGATION);
  1572. } else {
  1573. rooJpaRelationAnnotation.addEnumAttribute("type", RooEnumDetails.RELATION_TYPE_COMPOSITION);
  1574. }
  1575. parentFieldDetails.addAdditionaAnnotation(rooJpaRelationAnnotation);
  1576. // insert parent field
  1577. insertField(parentFieldDetails, permitReservedWords, false, true);
  1578. }
  1579. /**
  1580. * Create a field for a List or Set of a enumeration
  1581. *
  1582. * @param parentCid
  1583. * @param fieldType
  1584. * @param fieldName
  1585. * @param permitReservedWords
  1586. * @param sizeMin
  1587. * @param sizeMax
  1588. * @param comment
  1589. * @param notNull
  1590. * @param isList
  1591. */
  1592. private void createCollectionEnumeration(final ClassOrInterfaceTypeDetails parentCid,
  1593. JavaType fieldType, JavaSymbolName fieldName, boolean permitReservedWords, Integer sizeMin,
  1594. Integer sizeMax, String comment, boolean notNull, boolean isList) {
  1595. SetField parentFieldDetails;
  1596. if (isList) {
  1597. parentFieldDetails =
  1598. new SetField(parentCid.getDeclaredByMetadataId(), new JavaType(
  1599. LIST.getFullyQualifiedTypeName(), 0, DataType.TYPE, null, Arrays.asList(fieldType)),
  1600. fieldName, fieldType, null, null, false);
  1601. } else {
  1602. parentFieldDetails =
  1603. new ListField(parentCid.getDeclaredByMetadataId(), new JavaType(
  1604. SET.getFullyQualifiedTypeName(), 0, DataType.TYPE, null, Arrays.asList(fieldType)),
  1605. fieldName, fieldType, null, null, false);
  1606. }
  1607. parentFieldDetails.setNotNull(notNull);
  1608. if (comment != null) {
  1609. parentFieldDetails.setComment(comment);
  1610. }
  1611. if (sizeMin != null) {
  1612. parentFieldDetails.setSizeMin(sizeMin);
  1613. }
  1614. if (sizeMax != null) {
  1615. parentFieldDetails.setSizeMax(sizeMax);
  1616. }
  1617. // Handle enumeration Set
  1618. insertField(parentFieldDetails, permitReservedWords, false, true);
  1619. }
  1620. @Override
  1621. public void createListField(JavaType typeName, JavaType fieldType, JavaSymbolName fieldName,
  1622. Cardinality cardinality, Cascade[] cascadeType, boolean notNull, Integer sizeMin,
  1623. Integer sizeMax, JavaSymbolName mappedBy, Fetch fetch, String comment, String joinColumnName,
  1624. String referencedColumnName, String joinTable, String joinColumns, String referencedColumns,
  1625. String inverseJoinColumns, String inverseReferencedColumns, boolean permitReservedWords,
  1626. Boolean aggregation, Boolean orphanRemoval, boolean isForce, String formatExpression,
  1627. String formatMessage) {
  1628. createCollectionField(typeName, fieldType, fieldName, cardinality, cascadeType, notNull,
  1629. sizeMin, sizeMax, mappedBy, fetch, comment, joinColumnName, referencedColumnName,
  1630. joinTable, joinColumns, referencedColumns, inverseJoinColumns, inverseReferencedColumns,
  1631. permitReservedWords, aggregation, orphanRemoval, isForce, true, formatExpression,
  1632. formatMessage);
  1633. };
  1634. @Override
  1635. public void createStringField(ClassOrInterfaceTypeDetails cid, JavaSymbolName fieldName,
  1636. boolean notNull, boolean nullRequired, String decimalMin, String decimalMax, Integer sizeMin,
  1637. Integer sizeMax, String regexp, String column, String comment, boolean unique, String value,
  1638. boolean lob, boolean permitReservedWords, boolean transientModifier) {
  1639. createStringField(cid, fieldName, notNull, nullRequired, decimalMin, decimalMax, sizeMin,
  1640. sizeMax, regexp, column, comment, unique, value, lob, permitReservedWords,
  1641. transientModifier, null);
  1642. }
  1643. @Override
  1644. public void createStringField(ClassOrInterfaceTypeDetails cid, JavaSymbolName fieldName,
  1645. boolean notNull, boolean nullRequired, String decimalMin, String decimalMax, Integer sizeMin,
  1646. Integer sizeMax, String regexp, String column, String comment, boolean unique, String value,
  1647. boolean lob, boolean permitReservedWords, boolean transientModifier,
  1648. List<AnnotationMetadataBuilder> extraAnnotations) {
  1649. final String physicalTypeIdentifier = cid.getDeclaredByMetadataId();
  1650. final StringField fieldDetails = new StringField(physicalTypeIdentifier, fieldName);
  1651. fieldDetails.setNotNull(notNull);
  1652. fieldDetails.setNullRequired(nullRequired);
  1653. if (decimalMin != null) {
  1654. fieldDetails.setDecimalMin(decimalMin);
  1655. }
  1656. if (decimalMax != null) {
  1657. fieldDetails.setDecimalMax(decimalMax);
  1658. }
  1659. if (sizeMin != null) {
  1660. fieldDetails.setSizeMin(sizeMin);
  1661. }
  1662. if (sizeMax != null) {
  1663. fieldDetails.setSizeMax(sizeMax);
  1664. }
  1665. if (regexp != null) {
  1666. fieldDetails.setRegexp(regexp.replace("\\", "\\\\"));
  1667. }
  1668. if (column != null) {
  1669. fieldDetails.setColumn(column);
  1670. }
  1671. if (comment != null) {
  1672. fieldDetails.setComment(comment);
  1673. }
  1674. if (unique) {
  1675. fieldDetails.setUnique(true);
  1676. }
  1677. if (value != null) {
  1678. fieldDetails.setValue(value);
  1679. }
  1680. if (lob) {
  1681. fieldDetails.getInitedAnnotations().add(
  1682. new AnnotationMetadataBuilder("javax.persistence.Lob"));
  1683. // ROO-3722: Add LAZY load in @Lob fields using @Basic
  1684. AnnotationMetadataBuilder basicAnnotation =
  1685. new AnnotationMetadataBuilder("javax.persistence.Basic");
  1686. basicAnnotation.addEnumAttribute("fetch", new EnumDetails(new JavaType(
  1687. "javax.persistence.FetchType"), new JavaSymbolName("LAZY")));
  1688. fieldDetails.getInitedAnnotations().add(basicAnnotation);
  1689. }
  1690. if (extraAnnotations != null && !extraAnnotations.isEmpty()) {
  1691. fieldDetails.addAnnotations(extraAnnotations);
  1692. }
  1693. insertField(fieldDetails, permitReservedWords, transientModifier);
  1694. }
  1695. @Override
  1696. public void createFileField(ClassOrInterfaceTypeDetails cid, JavaSymbolName fieldName,
  1697. UploadedFileContentType contentType, boolean autoUpload, boolean notNull, String column,
  1698. boolean permitReservedWords) {
  1699. createFileField(cid, fieldName, contentType, autoUpload, notNull, column, permitReservedWords,
  1700. null);
  1701. }
  1702. @Override
  1703. public void createFileField(ClassOrInterfaceTypeDetails cid, JavaSymbolName fieldName,
  1704. UploadedFileContentType contentType, boolean autoUpload, boolean notNull, String column,
  1705. boolean permitReservedWords, List<AnnotationMetadataBuilder> extraAnnotations) {
  1706. final String physicalTypeIdentifier = cid.getDeclaredByMetadataId();
  1707. final UploadedFileField fieldDetails =
  1708. new UploadedFileField(physicalTypeIdentifier, fieldName, contentType);
  1709. fieldDetails.setAutoUpload(autoUpload);
  1710. fieldDetails.setNotNull(notNull);
  1711. if (column != null) {
  1712. fieldDetails.setColumn(column);
  1713. }
  1714. if (extraAnnotations != null && !extraAnnotations.isEmpty()) {
  1715. fieldDetails.addAnnotations(extraAnnotations);
  1716. }
  1717. insertField(fieldDetails, permitReservedWords, false);
  1718. }
  1719. @Override
  1720. public void createOtherField(ClassOrInterfaceTypeDetails cid, JavaType fieldType,
  1721. JavaSymbolName fieldName, boolean notNull, boolean nullRequired, String comment,
  1722. String column, boolean permitReservedWords, boolean transientModifier) {
  1723. createOtherField(cid, fieldType, fieldName, notNull, nullRequired, comment, column,
  1724. permitReservedWords, transientModifier, null);
  1725. }
  1726. @Override
  1727. public void createOtherField(ClassOrInterfaceTypeDetails cid, JavaType fieldType,
  1728. JavaSymbolName fieldName, boolean notNull, boolean nullRequired, String comment,
  1729. String column, boolean permitReservedWords, boolean transientModifier,
  1730. List<AnnotationMetadataBuilder> extraAnnotations) {
  1731. final String physicalTypeIdentifier = cid.getDeclaredByMetadataId();
  1732. final FieldDetails fieldDetails =
  1733. new FieldDetails(physicalTypeIdentifier, fieldType, fieldName);
  1734. fieldDetails.setNotNull(notNull);
  1735. fieldDetails.setNullRequired(nullRequired);
  1736. if (comment != null) {
  1737. fieldDetails.setComment(comment);
  1738. }
  1739. if (column != null) {
  1740. fieldDetails.setColumn(column);
  1741. }
  1742. if (extraAnnotations != null && !extraAnnotations.isEmpty()) {
  1743. fieldDetails.addAnnotations(extraAnnotations);
  1744. }
  1745. insertField(fieldDetails, permitReservedWords, transientModifier);
  1746. }
  1747. /**
  1748. * Generates Field builder based on fieldDetails
  1749. *
  1750. * @param fieldDetails
  1751. * @param permitReservedWords
  1752. * @param transientModifier
  1753. * @return
  1754. */
  1755. private FieldMetadataBuilder generateFieldBuilder(final FieldDetails fieldDetails,
  1756. final boolean permitReservedWords, final boolean transientModifier) {
  1757. if (!permitReservedWords) {
  1758. ReservedWords.verifyReservedWordsNotPresent(fieldDetails.getFieldName());
  1759. if (fieldDetails.getColumn() != null) {
  1760. ReservedWords.verifyReservedWordsNotPresent(fieldDetails.getColumn());
  1761. }
  1762. }
  1763. final List<AnnotationMetadataBuilder> annotations = fieldDetails.getInitedAnnotations();
  1764. fieldDetails.decorateAnnotationsList(annotations);
  1765. fieldDetails.setAnnotations(annotations);
  1766. String initializer = null;
  1767. if (fieldDetails instanceof CollectionField) {
  1768. final CollectionField collectionField = (CollectionField) fieldDetails;
  1769. initializer = "new " + collectionField.getInitializer() + "()";
  1770. } else if (fieldDetails instanceof DateField
  1771. && fieldDetails.getFieldName().getSymbolName().equals("created")) {
  1772. initializer = "new Date()";
  1773. }
  1774. int modifier = Modifier.PRIVATE;
  1775. if (transientModifier) {
  1776. modifier += Modifier.TRANSIENT;
  1777. }
  1778. fieldDetails.setModifiers(modifier);
  1779. // Format the passed-in comment (if given)
  1780. formatFieldComment(fieldDetails);
  1781. final FieldMetadataBuilder fieldBuilder = new FieldMetadataBuilder(fieldDetails);
  1782. fieldBuilder.setFieldInitializer(initializer);
  1783. return fieldBuilder;
  1784. }
  1785. private String getFieldModule(final FieldDetails fieldDetails) {
  1786. String module = null;
  1787. if (fieldDetails.getFieldType() != null) {
  1788. module = fieldDetails.getFieldType().getModule();
  1789. }
  1790. if (fieldDetails instanceof CollectionField) {
  1791. final CollectionField collectionField = (CollectionField) fieldDetails;
  1792. module = collectionField.getGenericParameterTypeName().getModule();
  1793. }
  1794. return module;
  1795. }
  1796. public void insertField(final FieldDetails fieldDetails, final boolean permitReservedWords,
  1797. final boolean transientModifier) {
  1798. insertField(fieldDetails, permitReservedWords, transientModifier, false);
  1799. }
  1800. public void insertField(final FieldDetails fieldDetails, final boolean permitReservedWords,
  1801. final boolean transientModifier, boolean evictCacheForTargetClass) {
  1802. String module = getFieldModule(fieldDetails);
  1803. final FieldMetadataBuilder fieldBuilder =
  1804. generateFieldBuilder(fieldDetails, permitReservedWords, transientModifier);
  1805. typeManagementService.addField(fieldBuilder.build(), evictCacheForTargetClass);
  1806. if (module != null) {
  1807. projectOperations.addModuleDependency(module);
  1808. }
  1809. }
  1810. public void formatFieldComment(FieldDetails fieldDetails) {
  1811. // If a comment was defined, we need to format it
  1812. if (fieldDetails.getComment() != null) {
  1813. // First replace all "" with the proper escape sequence \"
  1814. String unescapedMultiLineComment = fieldDetails.getComment().replaceAll("\"\"", "\\\\\"");
  1815. // Then unescape all characters
  1816. unescapedMultiLineComment = StringEscapeUtils.unescapeJava(unescapedMultiLineComment);
  1817. CommentFormatter commentFormatter = new CommentFormatter();
  1818. String javadocComment = commentFormatter.formatStringAsJavadoc(unescapedMultiLineComment);
  1819. fieldDetails.setComment(commentFormatter.format(javadocComment, 1));
  1820. }
  1821. }
  1822. @Override
  1823. public List<String> getFieldSetTypeAllPossibleValues(ShellContext shellContext) {
  1824. // Get current value of class
  1825. String currentText = shellContext.getParameters().get("type");
  1826. List<String> allPossibleValues = new ArrayList<String>();
  1827. // Getting all existing entities
  1828. Set<ClassOrInterfaceTypeDetails> entitiesInProject =
  1829. typeLocationService.findClassesOrInterfaceDetailsWithAnnotation(RooJavaType.ROO_JPA_ENTITY);
  1830. for (ClassOrInterfaceTypeDetails entity : entitiesInProject) {
  1831. String name = replaceTopLevelPackageString(entity, currentText);
  1832. if (!allPossibleValues.contains(name)) {
  1833. allPossibleValues.add(name);
  1834. }
  1835. }
  1836. // Getting all existing dtos
  1837. Set<ClassOrInterfaceTypeDetails> dtosInProject =
  1838. typeLocationService.findClassesOrInterfaceDetailsWithAnnotation(RooJavaType.ROO_DTO);
  1839. for (ClassOrInterfaceTypeDetails dto : dtosInProject) {
  1840. String name = replaceTopLevelPackageString(dto, currentText);
  1841. if (!allPossibleValues.contains(name)) {
  1842. allPossibleValues.add(name);
  1843. }
  1844. }
  1845. // Getting all existing embeddable classes
  1846. Set<ClassOrInterfaceTypeDetails> embeddableClassesInProject =
  1847. typeLocationService.findClassesOrInterfaceDetailsWithAnnotation(JpaJavaType.EMBEDDABLE);
  1848. for (ClassOrInterfaceTypeDetails embeddableClass : embeddableClassesInProject) {
  1849. String name = replaceTopLevelPackageString(embeddableClass, currentText);
  1850. if (!allPossibleValues.contains(name)) {
  1851. allPossibleValues.add(name);
  1852. }
  1853. }
  1854. return allPossibleValues;
  1855. }
  1856. @Override
  1857. public List<String> getFieldListTypeAllPossibleValues(ShellContext shellContext) {
  1858. // Get current value of class
  1859. String currentText = shellContext.getParameters().get("type");
  1860. List<String> allPossibleValues = new ArrayList<String>();
  1861. // Getting all existing entities
  1862. Set<ClassOrInterfaceTypeDetails> entitiesInProject =
  1863. typeLocationService.findClassesOrInterfaceDetailsWithAnnotation(RooJavaType.ROO_JPA_ENTITY);
  1864. for (ClassOrInterfaceTypeDetails entity : entitiesInProject) {
  1865. String name = replaceTopLevelPackageString(entity, currentText);
  1866. if (!allPossibleValues.contains(name)) {
  1867. allPossibleValues.add(name);
  1868. }
  1869. }
  1870. // Getting all existing dtos
  1871. Set<ClassOrInterfaceTypeDetails> dtosInProject =
  1872. typeLocationService.findClassesOrInterfaceDetailsWithAnnotation(RooJavaType.ROO_DTO);
  1873. for (ClassOrInterfaceTypeDetails dto : dtosInProject) {
  1874. String name = replaceTopLevelPackageString(dto, currentText);
  1875. if (!allPossibleValues.contains(name)) {
  1876. allPossibleValues.add(name);
  1877. }
  1878. }
  1879. // Getting all existing embeddable classes
  1880. Set<ClassOrInterfaceTypeDetails> embeddableClassesInProject =
  1881. typeLocationService.findClassesOrInterfaceDetailsWithAnnotation(JpaJavaType.EMBEDDABLE);
  1882. for (ClassOrInterfaceTypeDetails embeddableClass : embeddableClassesInProject) {
  1883. String name = replaceTopLevelPackageString(embeddableClass, currentText);
  1884. if (!allPossibleValues.contains(name)) {
  1885. allPossibleValues.add(name);
  1886. }
  1887. }
  1888. return allPossibleValues;
  1889. }
  1890. @Override
  1891. public List<String> getFieldEmbeddedAllPossibleValues(ShellContext shellContext) {
  1892. // Get current value of class
  1893. String currentText = shellContext.getParameters().get("type");
  1894. List<String> allPossibleValues = new ArrayList<String>();
  1895. // Getting all existing embeddable classes
  1896. Set<ClassOrInterfaceTypeDetails> embeddableClassesInProject =
  1897. typeLocationService.findClassesOrInterfaceDetailsWithAnnotation(JpaJavaType.EMBEDDABLE);
  1898. for (ClassOrInterfaceTypeDetails embeddableClass : embeddableClassesInProject) {
  1899. String name = replaceTopLevelPackageString(embeddableClass, currentText);
  1900. if (!allPossibleValues.contains(name)) {
  1901. allPossibleValues.add(name);
  1902. }
  1903. }
  1904. return allPossibleValues;
  1905. }
  1906. /**
  1907. * Replaces a JavaType fullyQualifiedName for a shorter name using '~' for TopLevelPackage
  1908. *
  1909. * @param cid ClassOrInterfaceTypeDetails of a JavaType
  1910. * @param currentText String current text for option value
  1911. * @return the String representing a JavaType with its name shortened
  1912. */
  1913. private String replaceTopLevelPackageString(ClassOrInterfaceTypeDetails cid, String currentText) {
  1914. String javaTypeFullyQualilfiedName = cid.getType().getFullyQualifiedTypeName();
  1915. String javaTypeString = "";
  1916. String topLevelPackageString = "";
  1917. // Add module value to topLevelPackage when necessary
  1918. if (StringUtils.isNotBlank(cid.getType().getModule())
  1919. && !cid.getType().getModule().equals(projectOperations.getFocusedModuleName())) {
  1920. // Target module is not focused
  1921. javaTypeString = cid.getType().getModule().concat(LogicalPath.MODULE_PATH_SEPARATOR);
  1922. topLevelPackageString =
  1923. projectOperations.getTopLevelPackage(cid.getType().getModule())
  1924. .getFullyQualifiedPackageName();
  1925. } else if (StringUtils.isNotBlank(cid.getType().getModule())
  1926. && cid.getType().getModule().equals(projectOperations.getFocusedModuleName())
  1927. && (currentText.startsWith(cid.getType().getModule()) || cid.getType().getModule()
  1928. .startsWith(currentText)) && StringUtils.isNotBlank(currentText)) {
  1929. // Target module is focused but user wrote it
  1930. javaTypeString = cid.getType().getModule().concat(LogicalPath.MODULE_PATH_SEPARATOR);
  1931. topLevelPackageString =
  1932. projectOperations.getTopLevelPackage(cid.getType().getModule())
  1933. .getFullyQualifiedPackageName();
  1934. } else {
  1935. // Not multimodule project
  1936. topLevelPackageString =
  1937. projectOperations.getFocusedTopLevelPackage().getFullyQualifiedPackageName();
  1938. }
  1939. // Autocomplete with abbreviate or full qualified mode
  1940. String auxString =
  1941. javaTypeString.concat(StringUtils.replace(javaTypeFullyQualilfiedName,
  1942. topLevelPackageString, "~"));
  1943. if ((StringUtils.isBlank(currentText) || auxString.startsWith(currentText))
  1944. && StringUtils.contains(javaTypeFullyQualilfiedName, topLevelPackageString)) {
  1945. // Value is for autocomplete only or user wrote abbreviate value
  1946. javaTypeString = auxString;
  1947. } else {
  1948. // Value could be for autocomplete or for validation
  1949. javaTypeString = String.format("%s%s", javaTypeString, javaTypeFullyQualilfiedName);
  1950. }
  1951. return javaTypeString;
  1952. }
  1953. /**
  1954. * Checks if entity has already a field with the same name and throws an exception
  1955. * in that case.
  1956. *
  1957. * @param fieldName
  1958. * @param isforce
  1959. * @param javaTypeDetails
  1960. * @param parameterName
  1961. */
  1962. private void checkFieldExists(final JavaSymbolName fieldName, final boolean isForce,
  1963. final ClassOrInterfaceTypeDetails javaTypeDetails, final String parameterName) {
  1964. MemberDetails memberDetails =
  1965. memberDetailsScanner.getMemberDetails(this.getClass().getName(), javaTypeDetails);
  1966. List<FieldMetadata> fields = memberDetails.getFields();
  1967. for (FieldMetadata field : fields) {
  1968. if (field.getFieldName().equals(fieldName) && !isForce) {
  1969. throw new IllegalArgumentException(
  1970. String
  1971. .format(
  1972. "Field '%s' already exists and cannot be created. Try to use a "
  1973. + "different field name on --%s parameter or use --force parameter to overwrite it.",
  1974. fieldName, parameterName));
  1975. }
  1976. }
  1977. }
  1978. private AnnotationMetadataBuilder buildEntityFormatAnnotation(
  1979. final String entityFormatExpression, final String entityFormatMessage, final String fieldName) {
  1980. final AnnotationMetadataBuilder entityFormatBuilder =
  1981. new AnnotationMetadataBuilder(SpringletsJavaType.SPRINGLETS_ENTITY_FORMAT);
  1982. // Check for each attribute individually
  1983. if (StringUtils.isNotBlank(entityFormatExpression)) {
  1984. entityFormatBuilder.addStringAttribute("value", entityFormatExpression);
  1985. }
  1986. if (StringUtils.isNotBlank(entityFormatMessage)) {
  1987. entityFormatBuilder.addStringAttribute("message", entityFormatMessage);
  1988. }
  1989. return entityFormatBuilder;
  1990. }
  1991. @SuppressWarnings("unchecked")
  1992. public Converter<JavaType> getJavaTypeConverter() {
  1993. if (javaTypeConverter == null) {
  1994. // Get all Services implement JavaTypeConverter interface
  1995. try {
  1996. ServiceReference<?>[] references =
  1997. this.context.getAllServiceReferences(Converter.class.getName(), null);
  1998. for (ServiceReference<?> ref : references) {
  1999. Converter<?> converter = (Converter<?>) this.context.getService(ref);
  2000. if (converter.supports(JavaType.class, PROJECT)) {
  2001. javaTypeConverter = (Converter<JavaType>) converter;
  2002. return javaTypeConverter;
  2003. }
  2004. }
  2005. return null;
  2006. } catch (InvalidSyntaxException e) {
  2007. LOGGER.warning("ERROR: Cannot load JavaTypeConverter on JpaFieldCreatorProvider.");
  2008. return null;
  2009. }
  2010. } else {
  2011. return javaTypeConverter;
  2012. }
  2013. }
  2014. }