package my.home.dsl.generator;
import com.google.common.collect.Iterables;
import com.google.inject.Inject;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import my.home.dsl.deepClone.Body;
import my.home.dsl.deepClone.ClassCloner;
import my.home.dsl.deepClone.ComplexField;
import my.home.dsl.deepClone.ContainerType;
import my.home.dsl.deepClone.FieldClonerType;
import my.home.dsl.deepClone.PackageConfig;
import my.home.dsl.deepClone.ReferenceField;
import my.home.dsl.deepClone.SimpleField;
import my.home.dsl.utils.DeepCloneUtils;
import my.home.dsl.utils.ReflectionUtils;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.xtend2.lib.StringConcatenation;
import org.eclipse.xtext.common.types.JvmTypeReference;
import org.eclipse.xtext.common.types.util.TypeReferences;
import org.eclipse.xtext.generator.IFileSystemAccess;
import org.eclipse.xtext.generator.IGenerator;
import org.eclipse.xtext.naming.IQualifiedNameConverter;
import org.eclipse.xtext.naming.QualifiedName;
import org.eclipse.xtext.xbase.lib.Extension;
import org.eclipse.xtext.xbase.lib.IterableExtensions;
import org.eclipse.xtext.xbase.lib.IteratorExtensions;
import org.eclipse.xtext.xbase.lib.ObjectExtensions;
import org.eclipse.xtext.xbase.lib.StringExtensions;
/**
* Generate Java code for DeepClone DSL for cloning Java bean instances.
* Input is complete set of all cloning definitions, potentially spread across several physical DSL files.
* Output is set of physical Java files arranged to appropriate directory hierarchy.
*
* Note: on the input there is Resource, usually it is mapped to one file, one particular
* DSL file, but it can be created synthetically, merging contents of several DSL files, preferably all of the same type.
*
* @see http://code.google.com/p/google-guice/wiki/InjectionPoints
* @author espinosa, 17.10.2012, 18.10.2012, 19.10, 9.11.2012
*/
@SuppressWarnings("all")
public class DeepCloneGenerator implements IGenerator {
@Inject
@Extension
private IQualifiedNameConverter _iQualifiedNameConverter;
@Inject
@Extension
private DeepCloneUtils _deepCloneUtils;
@Inject
@Extension
private ReflectionUtils _reflectionUtils;
private String packageNamespace;
public void doGenerate(final Resource resource, final IFileSystemAccess fsa) {
String _elvis = null;
EList<EObject> _contents = resource.getContents();
Iterable<Body> _filter = Iterables.<Body>filter(_contents, Body.class);
Body _head = IterableExtensions.<Body>head(_filter);
PackageConfig _packageConfig = _head.getPackageConfig();
String _name = null;
if (_packageConfig!=null) {
_name=_packageConfig.getName();
}
if (_name != null) {
_elvis = _name;
} else {
_elvis = ObjectExtensions.<String>operator_elvis(_name, "default");
}
this.packageNamespace = _elvis;
TreeIterator<EObject> _allContents = resource.getAllContents();
Iterable<EObject> _iterable = IteratorExtensions.<EObject>toIterable(_allContents);
Iterable<ClassCloner> _filter_1 = Iterables.<ClassCloner>filter(_iterable, ClassCloner.class);
for (final ClassCloner cc : _filter_1) {
{
JvmTypeReference _classToClone = cc.getClassToClone();
final String clonedClassSimpleName = _classToClone.getSimpleName();
String _elvis_1 = null;
String _name_1 = cc.getName();
if (_name_1 != null) {
_elvis_1 = _name_1;
} else {
_elvis_1 = ObjectExtensions.<String>operator_elvis(_name_1, (clonedClassSimpleName + "Cloner"));
}
final String classClonerClassName = _elvis_1;
QualifiedName _qualifiedName = this._iQualifiedNameConverter.toQualifiedName(this.packageNamespace);
final QualifiedName clonerClassFQN = _qualifiedName.append(classClonerClassName);
String _string = clonerClassFQN.toString("/");
String _plus = (_string + ".java");
CharSequence _generateJavaFileContent = this.generateJavaFileContent(cc, clonerClassFQN);
fsa.generateFile(_plus, _generateJavaFileContent);
}
}
}
/**
* Generate root level cloner
*/
public CharSequence generateJavaFileContent(final ClassCloner cc, final QualifiedName clonerClassFQN) {
StringConcatenation _builder = new StringConcatenation();
_builder.append("package ");
QualifiedName _skipLast = clonerClassFQN.skipLast(1);
_builder.append(_skipLast, "");
_builder.append(";");
_builder.newLineIfNotEmpty();
_builder.append("public class ");
String _lastSegment = clonerClassFQN.getLastSegment();
_builder.append(_lastSegment, "");
_builder.append(" {");
_builder.newLineIfNotEmpty();
_builder.append("\t");
CharSequence _generateApplyMethodAndSubCloners = this.generateApplyMethodAndSubCloners(cc);
_builder.append(_generateApplyMethodAndSubCloners, "\t");
_builder.newLineIfNotEmpty();
_builder.append("}");
_builder.newLine();
return _builder;
}
/**
* Generate cloner for complex field, a sub-cloner.
*
* Current implementation generates static nested class inside main cloner class.
* Sub cloners are nested recursively. This is an ultimate prevention of any name conflicts.
* This method is recursively called for child complex fields.
*/
public CharSequence generateSubClonerClass(final ComplexField complexField) {
CharSequence _xblockexpression = null;
{
String _firstUpper = null;
String _fieldName = complexField.getFieldName();
if (_fieldName!=null) {
_firstUpper=StringExtensions.toFirstUpper(_fieldName);
}
final String fieldClonerClass = (_firstUpper + "Cloner");
String _firstLower = null;
String _fieldName_1 = complexField.getFieldName();
if (_fieldName_1!=null) {
_firstLower=StringExtensions.toFirstLower(_fieldName_1);
}
final String fieldClonerInstance = (_firstLower + "Cloner");
StringConcatenation _builder = new StringConcatenation();
_builder.newLine();
_builder.append("private final ");
_builder.append(fieldClonerClass, "");
_builder.append(" ");
_builder.append(fieldClonerInstance, "");
_builder.append(" = new ");
_builder.append(fieldClonerClass, "");
_builder.append("();");
_builder.newLineIfNotEmpty();
_builder.append("public static class ");
_builder.append(fieldClonerClass, "");
_builder.append(" {");
_builder.newLineIfNotEmpty();
_builder.append("\t");
CharSequence _generateApplyMethodAndSubCloners = this.generateApplyMethodAndSubCloners(complexField);
_builder.append(_generateApplyMethodAndSubCloners, "\t");
_builder.newLineIfNotEmpty();
_builder.append("}");
_builder.newLine();
_xblockexpression = (_builder);
}
return _xblockexpression;
}
/**
* Declare instance of cloner for referenced cloner.
* Example:
* {@code private final SectionDeep sectionDeepCloner = new SectionDeep();}
* for field:
* {@code §ion SectionDeep}
*/
public CharSequence generateReferenceClonerInstance(final ReferenceField referenceField) {
CharSequence _xblockexpression = null;
{
QualifiedName _qualifiedName = this._iQualifiedNameConverter.toQualifiedName(this.packageNamespace);
ClassCloner _clonerReference = referenceField.getClonerReference();
String _name = _clonerReference.getName();
final QualifiedName fieldClonerClass = _qualifiedName.append(_name);
String _firstLower = null;
String _fieldName = referenceField.getFieldName();
if (_fieldName!=null) {
_firstLower=StringExtensions.toFirstLower(_fieldName);
}
final String fieldClonerInstance = (_firstLower + "Cloner");
StringConcatenation _builder = new StringConcatenation();
_builder.newLine();
_builder.append("private final ");
_builder.append(fieldClonerClass, "");
_builder.append(" ");
_builder.append(fieldClonerInstance, "");
_builder.append(" = new ");
_builder.append(fieldClonerClass, "");
_builder.append("();");
_builder.newLineIfNotEmpty();
_xblockexpression = (_builder);
}
return _xblockexpression;
}
/**
* Generate content for root and sub cloners: apply() method and all sub-cloners (if any)
*/
public CharSequence generateApplyMethodAndSubCloners(final ContainerType container) {
CharSequence _xblockexpression = null;
{
JvmTypeReference _javaType = container.getJavaType();
JvmTypeReference _typeOrCollectionTypeParameter = this._reflectionUtils.getTypeOrCollectionTypeParameter(_javaType);
final String containerType = _typeOrCollectionTypeParameter.getQualifiedName();
StringConcatenation _builder = new StringConcatenation();
_builder.append("public ");
_builder.append(containerType, "");
_builder.append(" apply(");
_builder.append(containerType, "");
_builder.append(" other) {");
_builder.newLineIfNotEmpty();
_builder.append("\t");
_builder.append("if (other == null) return null;");
_builder.newLine();
_builder.append("\t");
_builder.append(containerType, "\t");
_builder.append(" it = new ");
_builder.append(containerType, "\t");
_builder.append("();");
_builder.newLineIfNotEmpty();
{
EList<FieldClonerType> _fields = container.getFields();
for(final FieldClonerType field : _fields) {
{
boolean _and = false;
if (!(field instanceof SimpleField)) {
_and = false;
} else {
boolean _isCollection = this._deepCloneUtils.isCollection(field);
boolean _not = (!_isCollection);
_and = ((field instanceof SimpleField) && _not);
}
if (_and) {
_builder.append("\t");
_builder.append("it.set");
String _fieldName = field.getFieldName();
String _firstUpper = StringExtensions.toFirstUpper(_fieldName);
_builder.append(_firstUpper, "\t");
_builder.append("(other.get");
String _fieldName_1 = field.getFieldName();
String _firstUpper_1 = StringExtensions.toFirstUpper(_fieldName_1);
_builder.append(_firstUpper_1, "\t");
_builder.append("());");
_builder.newLineIfNotEmpty();
} else {
boolean _and_1 = false;
if (!(field instanceof SimpleField)) {
_and_1 = false;
} else {
boolean _isCollection_1 = this._deepCloneUtils.isCollection(field);
_and_1 = ((field instanceof SimpleField) && _isCollection_1);
}
if (_and_1) {
_builder.append("\t");
_builder.append("it.set");
String _fieldName_2 = field.getFieldName();
String _firstUpper_2 = StringExtensions.toFirstUpper(_fieldName_2);
_builder.append(_firstUpper_2, "\t");
_builder.append("(");
String _fieldName_3 = field.getFieldName();
String _firstLower = StringExtensions.toFirstLower(_fieldName_3);
_builder.append(_firstLower, "\t");
_builder.append("CollectionCloner(it.get");
String _fieldName_4 = field.getFieldName();
String _firstUpper_3 = StringExtensions.toFirstUpper(_fieldName_4);
_builder.append(_firstUpper_3, "\t");
_builder.append("(), other.get");
String _fieldName_5 = field.getFieldName();
String _firstUpper_4 = StringExtensions.toFirstUpper(_fieldName_5);
_builder.append(_firstUpper_4, "\t");
_builder.append("()));");
_builder.newLineIfNotEmpty();
} else {
boolean _and_2 = false;
if (!(field instanceof ComplexField)) {
_and_2 = false;
} else {
boolean _isCollection_2 = this._deepCloneUtils.isCollection(field);
boolean _not_1 = (!_isCollection_2);
_and_2 = ((field instanceof ComplexField) && _not_1);
}
if (_and_2) {
_builder.append("\t");
_builder.append("it.set");
String _fieldName_6 = field.getFieldName();
String _firstUpper_5 = StringExtensions.toFirstUpper(_fieldName_6);
_builder.append(_firstUpper_5, "\t");
_builder.append("(");
String _fieldName_7 = field.getFieldName();
String _firstLower_1 = StringExtensions.toFirstLower(_fieldName_7);
_builder.append(_firstLower_1, "\t");
_builder.append("Cloner.apply(other.get");
String _fieldName_8 = field.getFieldName();
String _firstUpper_6 = StringExtensions.toFirstUpper(_fieldName_8);
_builder.append(_firstUpper_6, "\t");
_builder.append("()));");
_builder.newLineIfNotEmpty();
} else {
boolean _and_3 = false;
if (!(field instanceof ComplexField)) {
_and_3 = false;
} else {
boolean _isCollection_3 = this._deepCloneUtils.isCollection(field);
_and_3 = ((field instanceof ComplexField) && _isCollection_3);
}
if (_and_3) {
_builder.append("\t");
_builder.append("it.set");
String _fieldName_9 = field.getFieldName();
String _firstUpper_7 = StringExtensions.toFirstUpper(_fieldName_9);
_builder.append(_firstUpper_7, "\t");
_builder.append("(");
String _fieldName_10 = field.getFieldName();
String _firstLower_2 = StringExtensions.toFirstLower(_fieldName_10);
_builder.append(_firstLower_2, "\t");
_builder.append("CollectionCloner(it.get");
String _fieldName_11 = field.getFieldName();
String _firstUpper_8 = StringExtensions.toFirstUpper(_fieldName_11);
_builder.append(_firstUpper_8, "\t");
_builder.append("(), other.get");
String _fieldName_12 = field.getFieldName();
String _firstUpper_9 = StringExtensions.toFirstUpper(_fieldName_12);
_builder.append(_firstUpper_9, "\t");
_builder.append("()));");
_builder.newLineIfNotEmpty();
} else {
if ((field instanceof ReferenceField)) {
_builder.append("\t");
_builder.append("it.set");
String _fieldName_13 = field.getFieldName();
String _firstUpper_10 = StringExtensions.toFirstUpper(_fieldName_13);
_builder.append(_firstUpper_10, "\t");
_builder.append("(");
String _fieldName_14 = field.getFieldName();
String _firstLower_3 = StringExtensions.toFirstLower(_fieldName_14);
_builder.append(_firstLower_3, "\t");
_builder.append("Cloner.apply(other.get");
String _fieldName_15 = field.getFieldName();
String _firstUpper_11 = StringExtensions.toFirstUpper(_fieldName_15);
_builder.append(_firstUpper_11, "\t");
_builder.append("()));");
_builder.newLineIfNotEmpty();
}
}
}
}
}
}
}
}
_builder.append("\t");
_builder.append("return it;");
_builder.newLine();
_builder.append("}");
_builder.newLine();
{
EList<FieldClonerType> _fields_1 = container.getFields();
for(final FieldClonerType field_1 : _fields_1) {
{
boolean _and_4 = false;
if (!(field_1 instanceof SimpleField)) {
_and_4 = false;
} else {
boolean _isCollection_4 = this._deepCloneUtils.isCollection(field_1);
_and_4 = ((field_1 instanceof SimpleField) && _isCollection_4);
}
if (_and_4) {
CharSequence _generateCollectionFieldClonnerMethod = this.generateCollectionFieldClonnerMethod(((SimpleField) field_1));
_builder.append(_generateCollectionFieldClonnerMethod, "");
_builder.newLineIfNotEmpty();
} else {
boolean _and_5 = false;
if (!(field_1 instanceof ComplexField)) {
_and_5 = false;
} else {
boolean _isCollection_5 = this._deepCloneUtils.isCollection(field_1);
_and_5 = ((field_1 instanceof ComplexField) && _isCollection_5);
}
if (_and_5) {
CharSequence _generateCollectionComplexFieldClonnerMethod = this.generateCollectionComplexFieldClonnerMethod(((ComplexField) field_1));
_builder.append(_generateCollectionComplexFieldClonnerMethod, "");
_builder.newLineIfNotEmpty();
}
}
}
{
if ((field_1 instanceof ComplexField)) {
CharSequence _generateSubClonerClass = this.generateSubClonerClass(((ComplexField) field_1));
_builder.append(_generateSubClonerClass, "");
_builder.newLineIfNotEmpty();
}
}
{
if ((field_1 instanceof ReferenceField)) {
CharSequence _generateReferenceClonerInstance = this.generateReferenceClonerInstance(((ReferenceField) field_1));
_builder.append(_generateReferenceClonerInstance, "");
_builder.newLineIfNotEmpty();
}
}
}
}
_xblockexpression = (_builder);
}
return _xblockexpression;
}
/**
* Generate private method for a field representing 1:N relation.
* Every simple filed which is also a collection has a custom method generated.
* Items are transfered one by one.
*/
public CharSequence generateCollectionFieldClonnerMethod(final SimpleField field) {
CharSequence _xblockexpression = null;
{
JvmTypeReference _javaType = field.getJavaType();
final String collectionType = _javaType.getQualifiedName();
JvmTypeReference _javaType_1 = field.getJavaType();
JvmTypeReference _typeOrCollectionTypeParameter = this._reflectionUtils.getTypeOrCollectionTypeParameter(_javaType_1);
final String collectionItemType = _typeOrCollectionTypeParameter.getQualifiedName();
StringConcatenation _builder = new StringConcatenation();
_builder.newLine();
_builder.append("private ");
_builder.append(collectionType, "");
_builder.append(" ");
String _fieldName = field.getFieldName();
String _firstLower = StringExtensions.toFirstLower(_fieldName);
_builder.append(_firstLower, "");
_builder.append("CollectionCloner(");
_builder.append(collectionType, "");
_builder.append(" thisCollection, ");
_builder.append(collectionType, "");
_builder.append(" otherCollection) {");
_builder.newLineIfNotEmpty();
_builder.append("\t");
_builder.append("if (otherCollection == null) return null;");
_builder.newLine();
_builder.append("\t");
JvmTypeReference _javaType_2 = field.getJavaType();
CharSequence _createCollection = this.createCollection(_javaType_2);
_builder.append(_createCollection, "\t");
_builder.newLineIfNotEmpty();
_builder.append("\t");
_builder.append("for (");
_builder.append(collectionItemType, "\t");
_builder.append(" otherCollectionItem : otherCollection) {");
_builder.newLineIfNotEmpty();
_builder.append("\t\t");
_builder.append("thisCollection.add(otherCollectionItem);");
_builder.newLine();
_builder.append("\t");
_builder.append("}");
_builder.newLine();
_builder.append("\t");
_builder.append("return thisCollection;");
_builder.newLine();
_builder.append("}");
_builder.newLine();
_xblockexpression = (_builder);
}
return _xblockexpression;
}
/**
* Generate private method for a field representing 1:N relation. A complex field with its own sub-cloner.
* Every simple filed which is also a collection has a custom method generated.
* Items are transfered one by one calling sub-cloner apply() method.
*/
public CharSequence generateCollectionComplexFieldClonnerMethod(final ComplexField field) {
CharSequence _xblockexpression = null;
{
JvmTypeReference _javaType = field.getJavaType();
final String collectionType = _javaType.getQualifiedName();
JvmTypeReference _javaType_1 = field.getJavaType();
JvmTypeReference _typeOrCollectionTypeParameter = this._reflectionUtils.getTypeOrCollectionTypeParameter(_javaType_1);
final String collectionItemType = _typeOrCollectionTypeParameter.getQualifiedName();
StringConcatenation _builder = new StringConcatenation();
_builder.newLine();
_builder.append("private ");
_builder.append(collectionType, "");
_builder.append(" ");
String _fieldName = field.getFieldName();
String _firstLower = StringExtensions.toFirstLower(_fieldName);
_builder.append(_firstLower, "");
_builder.append("CollectionCloner(");
_builder.append(collectionType, "");
_builder.append(" thisCollection, ");
_builder.append(collectionType, "");
_builder.append(" otherCollection) {");
_builder.newLineIfNotEmpty();
_builder.append("\t");
_builder.append("if (otherCollection == null) return null;");
_builder.newLine();
_builder.append("\t");
JvmTypeReference _javaType_2 = field.getJavaType();
CharSequence _createCollection = this.createCollection(_javaType_2);
_builder.append(_createCollection, "\t");
_builder.newLineIfNotEmpty();
_builder.append("\t");
_builder.append("for (");
_builder.append(collectionItemType, "\t");
_builder.append(" otherCollectionItem : otherCollection) {");
_builder.newLineIfNotEmpty();
_builder.append("\t\t");
_builder.append("thisCollection.add(");
String _fieldName_1 = field.getFieldName();
String _firstLower_1 = StringExtensions.toFirstLower(_fieldName_1);
_builder.append(_firstLower_1, "\t\t");
_builder.append("Cloner.apply(otherCollectionItem));");
_builder.newLineIfNotEmpty();
_builder.append("\t");
_builder.append("}");
_builder.newLine();
_builder.append("\t");
_builder.append("return thisCollection;");
_builder.newLine();
_builder.append("}");
_builder.newLine();
_xblockexpression = (_builder);
}
return _xblockexpression;
}
@Inject
@Extension
private TypeReferences _typeReferences;
public CharSequence createCollection(final JvmTypeReference collectionType) {
CharSequence _switchResult = null;
boolean _matched = false;
if (!_matched) {
boolean _isInstanceOf = this._typeReferences.isInstanceOf(collectionType, List.class);
if (_isInstanceOf) {
_matched=true;
StringConcatenation _builder = new StringConcatenation();
_builder.append("if (thisCollection == null) thisCollection = new java.util.ArrayList<");
String _typeParameter = this._reflectionUtils.getTypeParameter(collectionType);
_builder.append(_typeParameter, "");
_builder.append(">();");
_builder.newLineIfNotEmpty();
_switchResult = _builder;
}
}
if (!_matched) {
boolean _isInstanceOf_1 = this._typeReferences.isInstanceOf(collectionType, Set.class);
if (_isInstanceOf_1) {
_matched=true;
StringConcatenation _builder_1 = new StringConcatenation();
_builder_1.append("if (thisCollection == null) thisCollection = new java.util.HashSet<");
String _typeParameter_1 = this._reflectionUtils.getTypeParameter(collectionType);
_builder_1.append(_typeParameter_1, "");
_builder_1.append(">();");
_builder_1.newLineIfNotEmpty();
_switchResult = _builder_1;
}
}
if (!_matched) {
boolean _isInstanceOf_2 = this._typeReferences.isInstanceOf(collectionType, Collection.class);
if (_isInstanceOf_2) {
_matched=true;
StringConcatenation _builder_2 = new StringConcatenation();
_builder_2.append("if (thisCollection == null) thisCollection = new java.util.ArrayList<");
String _typeParameter_2 = this._reflectionUtils.getTypeParameter(collectionType);
_builder_2.append(_typeParameter_2, "");
_builder_2.append(">();");
_builder_2.newLineIfNotEmpty();
_switchResult = _builder_2;
}
}
if (!_matched) {
StringConcatenation _builder_3 = new StringConcatenation();
_builder_3.append("// unrecognized collection type");
_switchResult = _builder_3;
}
return _switchResult;
}
}