Skip to content

Commit

Permalink
MERGE: remote-tracking branch 'origin/multiplicities'
Browse files Browse the repository at this point in the history
  • Loading branch information
tsaglam committed Feb 1, 2018
2 parents 307e52e + ace935f commit e3083db
Show file tree
Hide file tree
Showing 9 changed files with 151 additions and 45 deletions.
6 changes: 3 additions & 3 deletions src/main/java/eme/extractor/JDTUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@ public static String getName(IType type) {
* @return the {@link WildcardStatus}.
*/
public static WildcardStatus getWildcardStatus(String signature) {
if (signature.contains(Character.toString(Signature.C_STAR))) {
if (signature.startsWith(Character.toString(Signature.C_STAR))) {
return WildcardStatus.UNBOUND; // is unbound wildcard
} else if (signature.contains(Character.toString(Signature.C_EXTENDS))) {
} else if (signature.startsWith(Character.toString(Signature.C_EXTENDS))) {
return WildcardStatus.UPPER_BOUND; // is upper bound wildcard
} else if (signature.contains(Character.toString(Signature.C_SUPER))) {
} else if (signature.startsWith(Character.toString(Signature.C_SUPER))) {
return WildcardStatus.LOWER_BOUND; // is lower bound wildcard
} // else:
return WildcardStatus.NO_WILDCARD; // is no wildcard
Expand Down
11 changes: 6 additions & 5 deletions src/main/java/eme/generator/EDataTypeGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public void addGenericArguments(EGenericType genericType, ExtractedDataType data
for (ExtractedDataType genericArgument : dataType.getGenericArguments()) { // for every generic argument
EGenericType eArgument = ecoreFactory.createEGenericType(); // create ETypeArgument as EGenericType
if (genericArgument.isWildcard()) { // wildcard argument:
addWildcardBound(eArgument, genericArgument);
addWildcardBound(eArgument, genericArgument, source);
} else { // normal argument or type parameter
generateBoundType(eArgument, genericArgument, source);
}
Expand Down Expand Up @@ -141,11 +141,11 @@ private void addBounds(ETypeParameter eTypeParameter, ExtractedTypeParameter typ
/**
* Adds a bound to an wild card argument if it has one.
*/
private void addWildcardBound(EGenericType eArgument, ExtractedDataType genericArgument) {
private void addWildcardBound(EGenericType eArgument, ExtractedDataType genericArgument, TypeParameterSource source) {
WildcardStatus status = genericArgument.getWildcardStatus(); // get wild card status
if (status != WildcardStatus.UNBOUND) { // if has bounds:
EGenericType bound = ecoreFactory.createEGenericType(); // create bound
bound.setEClassifier(generate(genericArgument)); // generate bound type
generateBoundType(bound, genericArgument, source); // generate bound type
if (status == WildcardStatus.LOWER_BOUND) {
eArgument.setELowerBound(bound); // add lower bound
} else {
Expand Down Expand Up @@ -210,8 +210,9 @@ private EClassifier generate(ExtractedDataType extractedDataType) {
}

/**
* Sets the type of an {@link EGenericType} from an bound {@link ExtractedDataType}. This is either an
* {@link ETypeParameter} if the {@link ExtractedDataType} is a type parameter or {@link EClassifier}.
* Sets the type of an {@link EGenericType} from a bound {@link ExtractedDataType}. This is either an
* {@link ETypeParameter} if the {@link ExtractedDataType} is a type parameter in the {@link TypeParameterSource} or
* {@link EClassifier} if not.
*/
private void generateBoundType(EGenericType genericType, ExtractedDataType boundType, TypeParameterSource source) {
if (source.containsTypeParameter(boundType)) {
Expand Down
117 changes: 86 additions & 31 deletions src/main/java/eme/generator/EMemberGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.List;
import java.util.Map;

import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EEnum;
Expand All @@ -11,6 +12,7 @@
import org.eclipse.emf.ecore.EParameter;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.ETypedElement;
import org.eclipse.emf.ecore.EcoreFactory;
import org.eclipse.emf.ecore.EcorePackage;

Expand Down Expand Up @@ -44,41 +46,27 @@ public EMemberGenerator(EDataTypeGenerator typeGenerator, SelectionHelper select
}

/**
* Adds the fields of an {@link ExtractedType} to a specific {@link EClass}.
* Adds any {@link ExtractedField} of an {@link ExtractedType} to a specific {@link EClass}.
* @param type is the {@link ExtractedType}
* @param eClass is the {@link EClass}.
*/
public void addFields(ExtractedType type, EClass eClass) {
for (ExtractedField field : type.getFields()) { // for every attribute
if (selector.allowsGenerating(field)) { // if should be generated:
if (isEClass(field.getFullType())) { // if type is EClass:
EReference reference = ecoreFactory.createEReference();
reference.setContainment(true); // has to be contained
addStructuralFeature(reference, field, eClass); // build reference
} else { // if it is EDataType:
addStructuralFeature(ecoreFactory.createEAttribute(), field, eClass); // build attribute
}
for (ExtractedField field : type.getFields()) { // for every field
if (selector.allowsGenerating(field)) { // if it is selected
addField(field, eClass); // add to EClass by creating an Ecore representation
}
}
}

/**
* Adds the operations of an {@link ExtractedType} to an {@link EClass}.
* Adds any {@link ExtractedMethod} of an {@link ExtractedType} to an {@link EClass}.
* @param type is the {@link ExtractedType}.
* @param eClass is the {@link EClass}.
*/
public void addOperations(ExtractedType type, EClass eClass) {
EOperation operation;
for (ExtractedMethod method : type.getMethods()) { // for every method
if (selector.allowsGenerating(method)) { // if should be generated.
operation = ecoreFactory.createEOperation(); // create object
operation.setName(method.getName()); // set name
eClass.getEOperations().add(operation);
typeGenerator.addTypeParameters(operation, method);
TypeParameterSource source = new TypeParameterSource(operation); // source of type parameters
addReturnType(operation, method.getReturnType(), source); // add return type
addExceptions(operation, method, source); // add throws declarations
addParameters(method, operation.getEParameters(), source); // add parameters
addOperation(method, eClass);
}
}
}
Expand All @@ -105,6 +93,37 @@ private void addExceptions(EOperation operation, ExtractedMethod method, TypePar
}
}

/**
* Adds a field to a {@link EClass} by creating a {@link EStructuralFeature} as Ecore representation, which is
* either a {@link EReference} or an {@link EAttribute}. List types are represented by an {@link EStructuralFeature}
* with an undefined upper bound property, which represents an one-to-many reference. If it is a reference,
* containment has to be set manually.
*/
private void addField(ExtractedField field, EClass eClass) {
ExtractedDataType dataType = getRelevantDataType(field);
EStructuralFeature representation = createFieldRepresentation(dataType);
representation.setName(field.getIdentifier()); // set name
representation.setChangeable(!(field.isFinal() && selector.allowsUnchangeable())); // make unchangeable if final
setUpperBound(representation, field);
typeGenerator.addDataType(representation, dataType, new TypeParameterSource(eClass)); // add type to attribute
eClass.getEStructuralFeatures().add(representation); // add feature to EClass
}

/**
* Adds a single {@link ExtractedMethod} to a {@link EClass} by creating a {@link EOperation} as Ecore
* representation.
*/
private void addOperation(ExtractedMethod method, EClass eClass) {
EOperation operation = ecoreFactory.createEOperation(); // create object
operation.setName(method.getName()); // set name
eClass.getEOperations().add(operation);
typeGenerator.addTypeParameters(operation, method);
TypeParameterSource source = new TypeParameterSource(operation); // source of type parameters
addReturnType(operation, method.getReturnType(), source); // add return type
addExceptions(operation, method, source); // add throws declarations
addParameters(method, operation.getEParameters(), source); // add parameters
}

/**
* Adds the parameters of an {@link ExtractedMethod} to a specific List of {@link EParameter}s.
*/
Expand All @@ -113,7 +132,8 @@ private void addParameters(ExtractedMethod method, List<EParameter> list, TypePa
for (ExtractedParameter parameter : method.getParameters()) { // for every parameter
eParameter = ecoreFactory.createEParameter();
eParameter.setName(parameter.getIdentifier()); // set identifier
typeGenerator.addDataType(eParameter, parameter, source); // add type type to EParameter
setUpperBound(eParameter, parameter);
typeGenerator.addDataType(eParameter, getRelevantDataType(parameter), source); // add type to EParameter
list.add(eParameter);
}
}
Expand All @@ -123,25 +143,60 @@ private void addParameters(ExtractedMethod method, List<EParameter> list, TypePa
*/
private void addReturnType(EOperation operation, ExtractedDataType returnType, TypeParameterSource source) {
if (returnType != null) { // if return type is not void
typeGenerator.addDataType(operation, returnType, source); // add type to return type
setUpperBound(operation, returnType);
typeGenerator.addDataType(operation, getRelevantDataType(returnType), source); // add type to return type
}
}

/**
* Builds a structural feature from an extracted attribute and adds it to an EClass. A structural feature can be an
* EAttribute or an EReference. If it is a reference, containment has to be set manually.
* Factory method for the Ecore representations of any {@link ExtractedDataType}.
*/
private void addStructuralFeature(EStructuralFeature feature, ExtractedField field, EClass eClass) {
feature.setName(field.getIdentifier()); // set name
feature.setChangeable(!(field.isFinal() && selector.allowUnchangeable())); // make unchangeable if final
typeGenerator.addDataType(feature, field, new TypeParameterSource(eClass)); // add type to attribute
eClass.getEStructuralFeatures().add(feature); // add feature to EClass
private EStructuralFeature createFieldRepresentation(ExtractedDataType dataType) {
if (isEClass(dataType)) { // if type is EClass:
return ecoreFactory.createEReference();
} else { // if it is EDataType:
return ecoreFactory.createEAttribute();
}
}

/**
* Checks whether a specific type name is an already created EClass.
* This method returns the list data type of any {@link ExtractedDataType} which is of type {@link List} when
* one-to-many multiplicities are allowed or the {@link ExtractedDataType} itself for any other case. This ensures
* that always the right data type is used for the Ecore representation of an {@link ExtractedDataType}. For
* example, a data type List<String> will return the data type String, but Map<String, String> will return
* Map<String, String>.
*/
private boolean isEClass(String typeName) {
private ExtractedDataType getRelevantDataType(ExtractedDataType dataType) {
if (isMultiplicityRepresentable(dataType)) {
return dataType.getGenericArguments().get(0); // get type of generic argument: List<String> => String
}
return dataType; // base case: return data type itself
}

/**
* Checks whether a specific {@link ExtractedDataType} is an already created EClass.
*/
private boolean isEClass(ExtractedDataType dataType) {
String typeName = dataType.getFullType();
return eClassifierMap.containsKey(typeName) && !(eClassifierMap.get(typeName) instanceof EEnum);
}

/**
* Checks whether a {@link ExtractedDataType} can be represented in the Ecore metamodel by using multiplicities.
* This depends on three conditions: The data type is a list type (@see {@link ExtractedDataType#isListType()}), the
* list is not a list of wild card types, and the user allowed the use of multiplicities in the settings.
*/
private boolean isMultiplicityRepresentable(ExtractedDataType dataType) {
return dataType.isListType() && !dataType.getGenericArguments().get(0).isWildcard() && selector.allowsMultiplicities(dataType);
}

/**
* Sets the upper bound of a {@link ETypedElement} depending on whether the {@link ExtractedDataType} represents is
* a list type and whether one-to-many multiplicities are allowed.
*/
private void setUpperBound(ETypedElement typedElement, ExtractedDataType dataType) {
if (isMultiplicityRepresentable(dataType)) {
typedElement.setUpperBound(-1); // set to one-to-many multiplicity
}
}
}
22 changes: 21 additions & 1 deletion src/main/java/eme/generator/SelectionHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.apache.log4j.LogManager;
Expand All @@ -21,7 +22,9 @@
import eme.model.ExtractedType;
import eme.model.MethodType;
import eme.model.datatypes.AccessLevelModifier;
import eme.model.datatypes.ExtractedDataType;
import eme.model.datatypes.ExtractedField;
import eme.model.datatypes.ExtractedParameter;
import eme.properties.BinaryProperty;
import eme.properties.ExtractionProperties;

Expand Down Expand Up @@ -109,11 +112,28 @@ public boolean allowsGenerating(ExtractedType type) {
return report(type.getClass().getSimpleName().substring(9).toLowerCase(), allowed); // class, interface, enum
}

/**
* Checks a {@link ExtractedDataType} that is a {@link List} type should be represented through one-to-many
* multiplicities depending on the actual type of the {@link ExtractedDataType}.
* @param dataType is the {@link ExtractedDataType}.
* @return true if they should.
* @see ExtractedDataType#isListType()
*/
public boolean allowsMultiplicities(ExtractedDataType dataType) {
if (dataType instanceof ExtractedField) {
return properties.get(BinaryProperty.FIELD_MULTIPLICITIES);
} else if (dataType instanceof ExtractedParameter) {
return properties.get(BinaryProperty.PARAMETER_MULTIPLICITIES);
} else {
return properties.get(BinaryProperty.RETURN_TYPE_MULTIPLICITIES);
}
}

/**
* Checks whether final fields are represented through unchangeable EStructuralFeatures.
* @return true if they are.
*/
public boolean allowUnchangeable() {
public boolean allowsUnchangeable() {
return properties.get(BinaryProperty.FINAL_AS_UNCHANGEABLE);
}

Expand Down
26 changes: 25 additions & 1 deletion src/main/java/eme/model/datatypes/ExtractedDataType.java
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,14 @@ public boolean isGeneric() {
return !genericArguments.isEmpty();
}

/**
* Checks whether the data type is a list type, which means it is of type {@link List}.
* @return true if it is.
*/
public boolean isListType() {
return List.class.getName().equals(fullTypeName) && genericArguments.size() == 1;
}

/**
* Checks whether the data type is an wild card.
* @return true if it is an wild card.
Expand All @@ -123,7 +131,23 @@ public void setWildcardStatus(WildcardStatus status) {

@Override
public String toString() {
return getClass().getSimpleName() + "(" + fullTypeName + ")";
return getClass().getSimpleName() + "(" + typeString() + ")";
}

/**
* Generates a type string for this {@link ExtractedDataType}. For example "Map<String, Object>".
* @return the type string.
*/
protected String typeString() {
String result = fullTypeName;
if (!genericArguments.isEmpty()) {
result += '<';
for (ExtractedDataType argument : genericArguments) {
result += argument.getFullType() + ", ";
}
result = result.substring(0, result.length() - 2) + '>';
}
return result;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/eme/model/datatypes/ExtractedField.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,6 @@ public void setStatic(boolean staticAttribute) {

@Override
public String toString() {
return getClass().getSimpleName() + "(" + modifier + " " + getFullType() + " " + getIdentifier() + ")";
return getClass().getSimpleName() + "(" + modifier + " " + typeString() + " " + getIdentifier() + ")";
}
}
2 changes: 1 addition & 1 deletion src/main/java/eme/model/datatypes/ExtractedVariable.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,6 @@ public String getIdentifier() {

@Override
public String toString() {
return getClass().getSimpleName() + "(" + getFullType() + " " + identifier + ")";
return getClass().getSimpleName() + "(" + typeString() + " " + identifier + ")";
}
}
5 changes: 4 additions & 1 deletion src/main/java/eme/properties/BinaryProperty.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ public enum BinaryProperty implements IBinaryProperty {
STATIC_FIELDS("ExtractStaticFields", false),
STATIC_METHODS("ExtractStaticMethods", false),
THROWABLES("ExtractThrowables", false),
FINAL_AS_UNCHANGEABLE("FinalAsUnchangeable", true);
FINAL_AS_UNCHANGEABLE("FinalAsUnchangeable", true),
FIELD_MULTIPLICITIES("FieldMultiplicities", true),
PARAMETER_MULTIPLICITIES("ParameterMultiplicities", true),
RETURN_TYPE_MULTIPLICITIES("ReturnTypeMultiplicities", true);

private final boolean defaultValue;
private final String key;
Expand Down
5 changes: 4 additions & 1 deletion user.properties
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ ExtractInterfaces=true
ExtractEnumerations=true
ExtractThrowables=false
#METHODS:
ReturnTypeMultiplicities=true
ParameterMultiplicities=true
ExtractConstructors=false
ExtractAbstractMethods=true
ExtractStaticMethods=false
Expand All @@ -27,7 +29,8 @@ ExtractPublicMethods=true
ExtractProtectedMethods=false
ExtractPrivateMethods=false
ExtractAccessMethods=false
#ATTRIBUTES:
#FIELDS:
FieldMultiplicities=true
ExtractStaticFields=false
ExtractDefaultFields=false
ExtractPublicFields=false
Expand Down

0 comments on commit e3083db

Please sign in to comment.