From 4d4473e9763e35d505d2aaa99cc05f301617c914 Mon Sep 17 00:00:00 2001 From: Olivier Prouvost Date: Fri, 18 Mar 2016 00:34:06 +0100 Subject: [PATCH] Fix issue #20 : The generics types are not managed Change-Id: I56e950f3234e4a19ed79bff6008851bd39aebf31 Signed-off-by: Olivier Prouvost --- .../TestInterfaceGeneration.launch | 2 +- .../core/test/TestInterfaceGeneration.java | 15 ++++ .../core/GenerateDevStructure.xtend | 42 +++++++-- .../core/GenerateDevStructure.java | 80 +++++++++++++++--- .../model/project.ecore | 15 ++++ .../model/project.genmodel | 6 ++ .../sampleProject.zip | Bin 14142 -> 5079 bytes 7 files changed, 137 insertions(+), 23 deletions(-) diff --git a/com.opcoach.genmodeladdon.core.test/TestInterfaceGeneration.launch b/com.opcoach.genmodeladdon.core.test/TestInterfaceGeneration.launch index 802d4d9..06e1bca 100644 --- a/com.opcoach.genmodeladdon.core.test/TestInterfaceGeneration.launch +++ b/com.opcoach.genmodeladdon.core.test/TestInterfaceGeneration.launch @@ -41,7 +41,7 @@ - + diff --git a/com.opcoach.genmodeladdon.core.test/src/com/opcoach/genmodeladdon/core/test/TestInterfaceGeneration.java b/com.opcoach.genmodeladdon.core.test/src/com/opcoach/genmodeladdon/core/test/TestInterfaceGeneration.java index 920a2dc..b9c0f61 100644 --- a/com.opcoach.genmodeladdon.core.test/src/com/opcoach/genmodeladdon/core/test/TestInterfaceGeneration.java +++ b/com.opcoach.genmodeladdon.core.test/src/com/opcoach/genmodeladdon/core/test/TestInterfaceGeneration.java @@ -219,6 +219,21 @@ public void implMDocProjectImplMustExtendProjectImplAndImplementsMDocProject() } + //------------------------------------------------------------- + // ------------------- Test dev classes for generic types -- + //------------------------------------------------------------- + + @Test public void theDevInterfaceMustBeGeneric() + { + assertFileContains("src/com/opcoach/project/Folder.java", "interface Folder extends MFolder"); + } + + @Test public void theDevClassMustBeGeneric() + { + assertFileContains("src/com/opcoach/project/impl/FolderImpl.java", "class FolderImpl extends MFolderImpl implements Folder"); + } + + } diff --git a/com.opcoach.genmodeladdon.core/src/com/opcoach/genmodeladdon/core/GenerateDevStructure.xtend b/com.opcoach.genmodeladdon.core/src/com/opcoach/genmodeladdon/core/GenerateDevStructure.xtend index 8be2a8d..ba476ca 100644 --- a/com.opcoach.genmodeladdon.core/src/com/opcoach/genmodeladdon/core/GenerateDevStructure.xtend +++ b/com.opcoach.genmodeladdon.core/src/com/opcoach/genmodeladdon/core/GenerateDevStructure.xtend @@ -20,6 +20,7 @@ import org.eclipse.core.runtime.Status import org.eclipse.emf.codegen.ecore.genmodel.GenClass import org.eclipse.emf.codegen.ecore.genmodel.GenModel import org.eclipse.emf.codegen.ecore.genmodel.GenPackage +import org.eclipse.emf.ecore.EClass import org.eclipse.emf.ecore.resource.Resource import org.eclipse.jdt.core.IClasspathEntry import org.eclipse.jdt.core.IJavaProject @@ -283,12 +284,12 @@ class GenerateDevStructure { def generateOverriddenClass(GenClass gc, String path) { - generateFile(path + gc.computeClassname + ".java", gc.generateClassContent) + generateFile(path + gc.computeClassFilename + ".java", gc.generateClassContent) } def generateOverriddenInterface(GenClass gc, String path) { - generateFile(path + gc.computeInterfaceName + ".java", gc.generateInterfaceContent) + generateFile(path + gc.computeInterfaceFilename + ".java", gc.generateInterfaceContent) } // Generate the file only if it does not exists.. If it exists keep the content and ask confirmation later @@ -431,15 +432,38 @@ class GenerateDevStructure { «ELSE»«ENDIF» ''' + /** Compute the class name to be generated */ + def computeClassFilename(GenClass gc) { + classPattern.replace("{0}", gc.ecoreClass.name) + } + + /** Compute the interface name to be generated */ + def computeInterfaceFilename(GenClass gc) { + interfacePattern.replace("{0}", gc.ecoreClass.name) + } + /** Compute the class name to be generated */ def computeClassname(GenClass gc) { - classPattern.replace("{0}", gc.ecoreClass.name) + gc.computeClassFilename() + gc.ecoreClass.computeGenericTypes } /** Compute the interface name to be generated */ def computeInterfaceName(GenClass gc) { - - interfacePattern.replace("{0}", gc.ecoreClass.name) + gc.computeInterfaceFilename + gc.ecoreClass.computeGenericTypes + } + + + def computeGenericTypes(EClass c) { + if (c.ETypeParameters.isEmpty) return "" + var sb = new StringBuffer("<") + var sep = "" + for (pt : c.ETypeParameters) + { + sb.append(pt.name).append(sep) + sep = "," + } + sb.append(">") + return sb } /** Compute the factory interface name to be generated */ @@ -482,9 +506,9 @@ class GenerateDevStructure { val classPattern = c.genPackage.genModel.classNamePattern if (classPattern != null) - classPattern.replace("{0}", c.ecoreClass.name) + classPattern.replace("{0}", c.ecoreClass.name) + c.ecoreClass.computeGenericTypes else - c.ecoreClass.name + "Impl" + c.ecoreClass.name + "Impl" + c.ecoreClass.computeGenericTypes } /** Compute the generated interface name depending on interfacePattern. */ @@ -494,9 +518,9 @@ class GenerateDevStructure { val interfaceNamePattern = c.genPackage.genModel.interfaceNamePattern if (interfaceNamePattern != null) - interfaceNamePattern.replace("{0}", c.ecoreClass.name) + interfaceNamePattern.replace("{0}", c.ecoreClass.name) + c.ecoreClass.computeGenericTypes else - c.ecoreClass.name + c.ecoreClass.name + c.ecoreClass.computeGenericTypes } /** Compute the generated factory class name depending on classpattern. */ diff --git a/com.opcoach.genmodeladdon.core/xtend-gen/com/opcoach/genmodeladdon/core/GenerateDevStructure.java b/com.opcoach.genmodeladdon.core/xtend-gen/com/opcoach/genmodeladdon/core/GenerateDevStructure.java index 780fba3..33a5717 100644 --- a/com.opcoach.genmodeladdon.core/xtend-gen/com/opcoach/genmodeladdon/core/GenerateDevStructure.java +++ b/com.opcoach.genmodeladdon.core/xtend-gen/com/opcoach/genmodeladdon/core/GenerateDevStructure.java @@ -37,6 +37,7 @@ import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.ecore.ETypeParameter; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaProject; @@ -423,16 +424,16 @@ public Object generateOverriddenPackageInterface(final GenPackage gp, final Stri } public Object generateOverriddenClass(final GenClass gc, final String path) { - String _computeClassname = this.computeClassname(gc); - String _plus = (path + _computeClassname); + String _computeClassFilename = this.computeClassFilename(gc); + String _plus = (path + _computeClassFilename); String _plus_1 = (_plus + ".java"); CharSequence _generateClassContent = this.generateClassContent(gc); return this.generateFile(_plus_1, _generateClassContent); } public Object generateOverriddenInterface(final GenClass gc, final String path) { - String _computeInterfaceName = this.computeInterfaceName(gc); - String _plus = (path + _computeInterfaceName); + String _computeInterfaceFilename = this.computeInterfaceFilename(gc); + String _plus = (path + _computeInterfaceFilename); String _plus_1 = (_plus + ".java"); CharSequence _generateInterfaceContent = this.generateInterfaceContent(gc); return this.generateFile(_plus_1, _generateInterfaceContent); @@ -866,7 +867,7 @@ public CharSequence computeCopyrightComment() { /** * Compute the class name to be generated */ - public String computeClassname(final GenClass gc) { + public String computeClassFilename(final GenClass gc) { EClass _ecoreClass = gc.getEcoreClass(); String _name = _ecoreClass.getName(); return this.classPattern.replace("{0}", _name); @@ -875,12 +876,53 @@ public String computeClassname(final GenClass gc) { /** * Compute the interface name to be generated */ - public String computeInterfaceName(final GenClass gc) { + public String computeInterfaceFilename(final GenClass gc) { EClass _ecoreClass = gc.getEcoreClass(); String _name = _ecoreClass.getName(); return this.interfacePattern.replace("{0}", _name); } + /** + * Compute the class name to be generated + */ + public String computeClassname(final GenClass gc) { + String _computeClassFilename = this.computeClassFilename(gc); + EClass _ecoreClass = gc.getEcoreClass(); + Object _computeGenericTypes = this.computeGenericTypes(_ecoreClass); + return (_computeClassFilename + _computeGenericTypes); + } + + /** + * Compute the interface name to be generated + */ + public String computeInterfaceName(final GenClass gc) { + String _computeInterfaceFilename = this.computeInterfaceFilename(gc); + EClass _ecoreClass = gc.getEcoreClass(); + Object _computeGenericTypes = this.computeGenericTypes(_ecoreClass); + return (_computeInterfaceFilename + _computeGenericTypes); + } + + public Object computeGenericTypes(final EClass c) { + EList _eTypeParameters = c.getETypeParameters(); + boolean _isEmpty = _eTypeParameters.isEmpty(); + if (_isEmpty) { + return ""; + } + StringBuffer sb = new StringBuffer("<"); + String sep = ""; + EList _eTypeParameters_1 = c.getETypeParameters(); + for (final ETypeParameter pt : _eTypeParameters_1) { + { + String _name = pt.getName(); + StringBuffer _append = sb.append(_name); + _append.append(sep); + sep = ","; + } + } + sb.append(">"); + return sb; + } + /** * Compute the factory interface name to be generated */ @@ -997,11 +1039,17 @@ public String computeGeneratedClassName(final GenClass c) { if (_notEquals) { EClass _ecoreClass = c.getEcoreClass(); String _name = _ecoreClass.getName(); - _xifexpression = classPattern.replace("{0}", _name); - } else { + String _replace = classPattern.replace("{0}", _name); EClass _ecoreClass_1 = c.getEcoreClass(); - String _name_1 = _ecoreClass_1.getName(); - _xifexpression = (_name_1 + "Impl"); + Object _computeGenericTypes = this.computeGenericTypes(_ecoreClass_1); + _xifexpression = (_replace + _computeGenericTypes); + } else { + EClass _ecoreClass_2 = c.getEcoreClass(); + String _name_1 = _ecoreClass_2.getName(); + String _plus = (_name_1 + "Impl"); + EClass _ecoreClass_3 = c.getEcoreClass(); + Object _computeGenericTypes_1 = this.computeGenericTypes(_ecoreClass_3); + _xifexpression = (_plus + _computeGenericTypes_1); } _xblockexpression = _xifexpression; } @@ -1022,10 +1070,16 @@ public String computeGeneratedInterfaceName(final GenClass c) { if (_notEquals) { EClass _ecoreClass = c.getEcoreClass(); String _name = _ecoreClass.getName(); - _xifexpression = interfaceNamePattern.replace("{0}", _name); - } else { + String _replace = interfaceNamePattern.replace("{0}", _name); EClass _ecoreClass_1 = c.getEcoreClass(); - _xifexpression = _ecoreClass_1.getName(); + Object _computeGenericTypes = this.computeGenericTypes(_ecoreClass_1); + _xifexpression = (_replace + _computeGenericTypes); + } else { + EClass _ecoreClass_2 = c.getEcoreClass(); + String _name_1 = _ecoreClass_2.getName(); + EClass _ecoreClass_3 = c.getEcoreClass(); + Object _computeGenericTypes_1 = this.computeGenericTypes(_ecoreClass_3); + _xifexpression = (_name_1 + _computeGenericTypes_1); } _xblockexpression = _xifexpression; } diff --git a/com.opcoach.genmodeladdon.sample/model/project.ecore b/com.opcoach.genmodeladdon.sample/model/project.ecore index 5b7cb82..7f67694 100644 --- a/com.opcoach.genmodeladdon.sample/model/project.ecore +++ b/com.opcoach.genmodeladdon.sample/model/project.ecore @@ -27,6 +27,21 @@ + + + + + + + + + + + + + + diff --git a/com.opcoach.genmodeladdon.sample/model/project.genmodel b/com.opcoach.genmodeladdon.sample/model/project.genmodel index 11a6a97..a74308c 100644 --- a/com.opcoach.genmodeladdon.sample/model/project.genmodel +++ b/com.opcoach.genmodeladdon.sample/model/project.genmodel @@ -30,6 +30,12 @@ + + + + + + diff --git a/com.opcoach.genmodeladdon.sample/sampleProject.zip b/com.opcoach.genmodeladdon.sample/sampleProject.zip index da61f816d0caa2d3e988e01dcf5e60eed1e91fd4..b7a11d44cd2196a40593267b8256d0e2ba10efa7 100644 GIT binary patch delta 3079 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