private List<Identifier> getIdentifiers(final Table table, final boolean usePrimaryKeys) { final List<Identifier> result = new ArrayList<Identifier>(); // Add fields to the identifier class final Set<Column> columns = usePrimaryKeys ? table.getPrimaryKeys() : table.getColumns(); for (final Column column : columns) { final String columnName = column.getName(); JavaSymbolName fieldName; try { fieldName = new JavaSymbolName(DbreTypeUtils.suggestFieldName(columnName)); } catch (final RuntimeException e) { throw new IllegalArgumentException( "Failed to create field name for column '" + columnName + "' in table '" + table.getName() + "': " + e.getMessage()); } final JavaType fieldType = column.getJavaType(); final String columnDefinition = table.isIncludeNonPortableAttributes() ? column.getTypeName() : ""; result.add( new Identifier( fieldName, fieldType, columnName, column.getColumnSize(), column.getScale(), columnDefinition)); } return result; }
private boolean hasVersionField(final Table table) { if (!table.isDisableVersionFields()) { for (final Column column : table.getColumns()) { if (VERSION.equalsIgnoreCase(column.getName())) { return true; } } } return false; }
/** * Creates a new DBRE-managed entity from the given table * * @param javaType the name of the entity to be created (required) * @param table the table from which to create the entity (required) * @param activeRecord whether to create "active record" CRUD methods in the new entity * @return the newly created entity */ private ClassOrInterfaceTypeDetails createNewManagedEntityFromTable( final JavaType javaType, final Table table, final boolean activeRecord) { // Create type annotations for new entity final List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>(); annotations.add(new AnnotationMetadataBuilder(ROO_JAVA_BEAN)); annotations.add(new AnnotationMetadataBuilder(ROO_TO_STRING)); // Find primary key from db metadata and add identifier attributes to // @RooJpaEntity final AnnotationMetadataBuilder jpaAnnotationBuilder = new AnnotationMetadataBuilder(activeRecord ? ROO_JPA_ACTIVE_RECORD : ROO_JPA_ENTITY); manageIdentifier(javaType, jpaAnnotationBuilder, new HashSet<JavaSymbolName>(), table); if (!hasVersionField(table)) { jpaAnnotationBuilder.addStringAttribute(VERSION_FIELD, ""); } if (table.isDisableGeneratedIdentifiers()) { jpaAnnotationBuilder.addStringAttribute(SEQUENCE_NAME_FIELD, ""); } jpaAnnotationBuilder.addStringAttribute("table", table.getName()); if (!DbreModelService.NO_SCHEMA_REQUIRED.equals(table.getSchema().getName())) { jpaAnnotationBuilder.addStringAttribute("schema", table.getSchema().getName()); } annotations.add(jpaAnnotationBuilder); // Add @RooDbManaged annotations.add(getRooDbManagedAnnotation()); final JavaType superclass = OBJECT; final List<JavaType> extendsTypes = new ArrayList<JavaType>(); extendsTypes.add(superclass); // Create entity class final String declaredByMetadataId = PhysicalTypeIdentifier.createIdentifier( javaType, projectOperations.getPathResolver().getFocusedPath(Path.SRC_MAIN_JAVA)); final ClassOrInterfaceTypeDetailsBuilder cidBuilder = new ClassOrInterfaceTypeDetailsBuilder( declaredByMetadataId, Modifier.PUBLIC, javaType, PhysicalTypeCategory.CLASS); cidBuilder.setExtendsTypes(extendsTypes); cidBuilder.setAnnotations(annotations); final ClassOrInterfaceTypeDetails entity = cidBuilder.build(); typeManagementService.createOrUpdateTypeOnDisk(entity); shell.flash( Level.FINE, "Created " + javaType.getFullyQualifiedTypeName(), DbreDatabaseListenerImpl.class.getName()); shell.flash(Level.FINE, "", DbreDatabaseListenerImpl.class.getName()); return entity; }
private void manageIdentifier( final JavaType javaType, final AnnotationMetadataBuilder jpaAnnotationBuilder, final Set<JavaSymbolName> attributesToDeleteIfPresent, final Table table) { final JavaType identifierType = getIdentifierType(javaType); final PhysicalTypeMetadata identifierPhysicalTypeMetadata = getPhysicalTypeMetadata(identifierType); // Process primary keys and add 'identifierType' attribute final int pkCount = table.getPrimaryKeyCount(); if (pkCount == 1) { // Table has one primary key // Check for redundant, managed identifier class and delete if found if (isIdentifierDeletable(identifierType)) { deleteJavaType( identifierType, "the " + table.getName() + " table has only one primary key"); } attributesToDeleteIfPresent.add(new JavaSymbolName(IDENTIFIER_TYPE)); // We don't need a PK class, so we just tell the // JpaActiveRecordProvider via IdentifierService the column name, // field type and field name to use final List<Identifier> identifiers = getIdentifiersFromPrimaryKeys(table); identifierResults.put(javaType, identifiers); } else if (pkCount == 0 || pkCount > 1) { // Table has either no primary keys or more than one primary key so // create a composite key // Check if identifier class already exists and if not, create it if (identifierPhysicalTypeMetadata == null || !identifierPhysicalTypeMetadata.isValid() || identifierPhysicalTypeMetadata.getMemberHoldingTypeDetails() == null) { createIdentifierClass(identifierType); } jpaAnnotationBuilder.addClassAttribute(IDENTIFIER_TYPE, identifierType); // We need a PK class, so we tell the IdentifierMetadataProvider via // IdentifierService the various column names, field types and field // names to use // For tables with no primary keys, create a composite key using all // the table's columns final List<Identifier> identifiers = pkCount == 0 ? getIdentifiersFromColumns(table) : getIdentifiersFromPrimaryKeys(table); identifierResults.put(identifierType, identifiers); } }
private Table updateOrDeleteManagedEntity( final ClassOrInterfaceTypeDetails managedEntity, final Database database) { // Update the attributes of the existing JPA-related annotation final AnnotationMetadata jpaAnnotation = getJpaAnnotation(managedEntity); Validate.validState( jpaAnnotation != null, "Neither @%s nor @%s found on existing DBRE-managed entity %s", ROO_JPA_ACTIVE_RECORD.getSimpleTypeName(), ROO_JPA_ENTITY.getSimpleTypeName(), managedEntity.getName().getFullyQualifiedTypeName()); // Find table in database using 'table' and 'schema' attributes from the // JPA annotation final AnnotationAttributeValue<?> tableAttribute = jpaAnnotation.getAttribute(new JavaSymbolName("table")); final String errMsg = "Unable to maintain database-managed entity " + managedEntity.getName().getFullyQualifiedTypeName() + " because its associated table could not be found"; Validate.notNull(tableAttribute, errMsg); final String tableName = (String) tableAttribute.getValue(); Validate.notBlank(tableName, errMsg); final AnnotationAttributeValue<?> schemaAttribute = jpaAnnotation.getAttribute(new JavaSymbolName("schema")); final String schemaName = schemaAttribute != null ? (String) schemaAttribute.getValue() : null; final Table table = database.getTable(tableName, schemaName); if (table == null) { // Table is missing and probably has been dropped so delete managed // type and its identifier if applicable deleteManagedType(managedEntity, "no database table called '" + tableName + "'"); return null; } table.setIncludeNonPortableAttributes(database.isIncludeNonPortableAttributes()); table.setDisableVersionFields(database.isDisableVersionFields()); table.setDisableGeneratedIdentifiers(database.isDisableGeneratedIdentifiers()); // Update the @RooJpaEntity/@RooJpaActiveRecord attributes final AnnotationMetadataBuilder jpaAnnotationBuilder = new AnnotationMetadataBuilder(jpaAnnotation); final Set<JavaSymbolName> attributesToDeleteIfPresent = new LinkedHashSet<JavaSymbolName>(); manageIdentifier( managedEntity.getName(), jpaAnnotationBuilder, attributesToDeleteIfPresent, table); // Manage versionField attribute final AnnotationAttributeValue<?> versionFieldAttribute = jpaAnnotation.getAttribute(new JavaSymbolName(VERSION_FIELD)); if (versionFieldAttribute == null) { if (hasVersionField(table)) { attributesToDeleteIfPresent.add(new JavaSymbolName(VERSION_FIELD)); } else { jpaAnnotationBuilder.addStringAttribute(VERSION_FIELD, ""); } } else { final String versionFieldValue = (String) versionFieldAttribute.getValue(); if (hasVersionField(table) && (StringUtils.isBlank(versionFieldValue) || VERSION.equals(versionFieldValue))) { attributesToDeleteIfPresent.add(new JavaSymbolName(VERSION_FIELD)); } } final AnnotationAttributeValue<?> sequenceNameFieldAttribute = jpaAnnotation.getAttribute(new JavaSymbolName(SEQUENCE_NAME_FIELD)); if (sequenceNameFieldAttribute == null) { if (!table.isDisableGeneratedIdentifiers()) { attributesToDeleteIfPresent.add(new JavaSymbolName(SEQUENCE_NAME_FIELD)); } else { jpaAnnotationBuilder.addStringAttribute(SEQUENCE_NAME_FIELD, ""); } } else { final String sequenceNameFieldValue = (String) sequenceNameFieldAttribute.getValue(); if (!table.isDisableGeneratedIdentifiers() && ("".equals(sequenceNameFieldValue))) { attributesToDeleteIfPresent.add(new JavaSymbolName(SEQUENCE_NAME_FIELD)); } } // Update the annotation on disk final ClassOrInterfaceTypeDetailsBuilder cidBuilder = new ClassOrInterfaceTypeDetailsBuilder(managedEntity); cidBuilder.updateTypeAnnotation(jpaAnnotationBuilder.build(), attributesToDeleteIfPresent); typeManagementService.createOrUpdateTypeOnDisk(cidBuilder.build()); return table; }
private void reverseEngineer(final Database database) { final Set<ClassOrInterfaceTypeDetails> managedEntities = typeLocationService.findClassesOrInterfaceDetailsWithAnnotation(ROO_DB_MANAGED); // Determine whether to create "active record" CRUD methods database.setActiveRecord(isActiveRecord(database, managedEntities)); // Lookup the relevant destination package if not explicitly given final JavaPackage destinationPackage = getDestinationPackage(database, managedEntities); // Set the destination package in the database database.setDestinationPackage(destinationPackage); // Get tables from database final Set<Table> tables = new LinkedHashSet<Table>(database.getTables()); // Manage existing entities with @RooDbManaged annotation for (final ClassOrInterfaceTypeDetails managedEntity : managedEntities) { // Remove table from set as each managed entity is processed. // The tables that remain in the set will be used for creation of // new entities later final Table table = updateOrDeleteManagedEntity(managedEntity, database); if (table != null) { tables.remove(table); } } // Create new entities from tables final List<ClassOrInterfaceTypeDetails> newEntities = new ArrayList<ClassOrInterfaceTypeDetails>(); for (final Table table : tables) { // Don't create types from join tables in many-to-many associations if (!table.isJoinTable()) { JavaPackage schemaPackage = destinationPackage; if (database.hasMultipleSchemas()) { schemaPackage = new JavaPackage( destinationPackage.getFullyQualifiedPackageName() + "." + DbreTypeUtils.suggestPackageName(table.getSchema().getName())); } final JavaType javaType = DbreTypeUtils.suggestTypeNameForNewTable(table.getName(), schemaPackage); final boolean activeRecord = database.isActiveRecord() && !database.isRepository(); if (typeLocationService.getTypeDetails(javaType) == null) { table.setIncludeNonPortableAttributes(database.isIncludeNonPortableAttributes()); table.setDisableVersionFields(database.isDisableVersionFields()); table.setDisableGeneratedIdentifiers(database.isDisableGeneratedIdentifiers()); newEntities.add(createNewManagedEntityFromTable(javaType, table, activeRecord)); } } } // Create repositories if required if (database.isRepository()) { for (final ClassOrInterfaceTypeDetails entity : newEntities) { final JavaType type = entity.getType(); repositoryJpaOperations.setupRepository( new JavaType(type.getFullyQualifiedTypeName() + "Repository"), type); } } // Create services if required if (database.isService()) { for (final ClassOrInterfaceTypeDetails entity : newEntities) { final JavaType type = entity.getType(); final String typeName = type.getFullyQualifiedTypeName(); serviceOperations.setupService( new JavaType(typeName + "Service"), new JavaType(typeName + "ServiceImpl"), type, false, "", false, false); } } // Create integration tests if required if (database.isTestAutomatically()) { for (final ClassOrInterfaceTypeDetails entity : newEntities) { integrationTestOperations.newIntegrationTest(entity.getType()); } } // Notify final List<ClassOrInterfaceTypeDetails> allEntities = new ArrayList<ClassOrInterfaceTypeDetails>(); allEntities.addAll(newEntities); allEntities.addAll(managedEntities); notify(allEntities); }