From 6e9ce07a41c988e981d2f697479f7ce05c424cdc Mon Sep 17 00:00:00 2001 From: "Michael H. Siemaszko" Date: Sun, 7 Jul 2024 20:31:57 +0200 Subject: [PATCH] Java to EMF EPackage converters (c.d.) - Construct and add 'nsURI' to each sub-package - Construct and add 'nsPrefix' to each sub-package - Instead of creating custom EDataTypes for array types, re-use "single instance" equivalents as type in such cases and set upperBound to 'ETypedElement.UNBOUNDED_MULTIPLICITY' - Reuse EDataTypes from EPackagesRegistry attached to ResourceSet - Use current Classloader when constructing URLClassLoader - When looking up EClassifier, check package name as well - Refactoring related to above mentioned, as well as minor fixes and improvements Signed-off-by: Michael H. Siemaszko --- cnf/central.mvn | 5 - ...aReferenceTypeToEPackageConverterTest.java | 49 ++++- org.gecko.emf.converter.tests/test.bndrun | 10 +- .../AbstractJavaToEPackageConverter.java | 193 ++++++++++++++---- .../JavaReferenceTypeToEPackageConverter.java | 97 ++++++--- .../converter/JavaToEPackageConverter.java | 6 + 6 files changed, 285 insertions(+), 75 deletions(-) diff --git a/cnf/central.mvn b/cnf/central.mvn index b339a88..7498b1a 100644 --- a/cnf/central.mvn +++ b/cnf/central.mvn @@ -1,5 +1,4 @@ biz.aQute.bnd:biz.aQute.bnd.annotation:7.0.0 -biz.aQute.bnd:biz.aQute.bnd.annotation:7.0.0 biz.aQute:biz.aQute.gogo.commands.provider:1.8.0 biz.aQute:biz.aQute.wrapper.hamcrest:1.9.0 biz.aQute.bnd:biz.aQute.bnd.javagen:7.0.0 @@ -33,10 +32,8 @@ org.apache.felix:org.apache.felix.framework:7.0.1 org.apache.felix:org.apache.felix.gogo.command:1.1.2 org.apache.felix:org.apache.felix.gogo.runtime:1.1.4 org.apache.felix:org.apache.felix.gogo.shell:1.1.4 -org.apache.felix:org.apache.felix.gogo.shell:1.1.4 org.apache.felix:org.apache.felix.http.jetty:4.1.14 org.apache.felix:org.apache.felix.http.servlet-api:1.1.2 -org.apache.felix:org.apache.felix.http.servlet-api:1.1.2 org.apache.felix:org.apache.felix.inventory:1.0.6 org.apache.felix:org.apache.felix.cm.json:1.0.6 org.apache.felix:org.apache.felix.log.extension:1.0.0 @@ -63,8 +60,6 @@ org.bouncycastle:bcprov-jdk15on:1.64 org.bouncycastle:bctls-jdk15on:1.64 org.bouncycastle:bcutil-jdk15on:1.69 - - org.opentest4j:opentest4j:1.2.0 org.osgi:org.osgi.annotation.bundle:1.1.0 diff --git a/org.gecko.emf.converter.tests/src/org/gecko/emf/converter/tests/JavaReferenceTypeToEPackageConverterTest.java b/org.gecko.emf.converter.tests/src/org/gecko/emf/converter/tests/JavaReferenceTypeToEPackageConverterTest.java index 077c98d..979fc36 100644 --- a/org.gecko.emf.converter.tests/src/org/gecko/emf/converter/tests/JavaReferenceTypeToEPackageConverterTest.java +++ b/org.gecko.emf.converter.tests/src/org/gecko/emf/converter/tests/JavaReferenceTypeToEPackageConverterTest.java @@ -108,7 +108,7 @@ public void testConvertJakartaRESTfulWSAPI( EPackage.Registry.INSTANCE.put(dynamicEPackageFromJavaReferenceTypes.getNsURI(), dynamicEPackageFromJavaReferenceTypes); - assertThat(eClassifiersTotalCount(dynamicEPackageFromJavaReferenceTypes)).isEqualTo(182); + assertThat(eClassifiersTotalCount(dynamicEPackageFromJavaReferenceTypes)).isEqualTo(213); } @Disabled @@ -143,7 +143,7 @@ public void testConvertJakartaRESTfulWSAPIAndSerializeToStaticEMF( EPackage.Registry.INSTANCE.put(dynamicEPackageFromJavaReferenceTypes.getNsURI(), dynamicEPackageFromJavaReferenceTypes); - assertThat(eClassifiersTotalCount(dynamicEPackageFromJavaReferenceTypes)).isEqualTo(182); + assertThat(eClassifiersTotalCount(dynamicEPackageFromJavaReferenceTypes)).isEqualTo(213); Resource resource = resourceSet.createResource(URI.createFileURI("jakarta.ws.rs-api-3.1.0.ecore")); @@ -188,7 +188,50 @@ public void testConvertOrgApacheFelixHttpServletApiAndSerializeToStaticEMF( EPackage.Registry.INSTANCE.put(dynamicEPackageFromJavaReferenceTypes.getNsURI(), dynamicEPackageFromJavaReferenceTypes); - assertThat(eClassifiersTotalCount(dynamicEPackageFromJavaReferenceTypes)).isEqualTo(119); + assertThat(eClassifiersTotalCount(dynamicEPackageFromJavaReferenceTypes)).isEqualTo(198); + + Resource resource = resourceSet + .createResource(URI.createFileURI("org.apache.felix.http.servlet-api-2.1.0.ecore")); + + resource.getContents().add(dynamicEPackageFromJavaReferenceTypes); + resource.save(null); + } + + @Disabled + @Test + public void testConvertOrgApacheFelixHttpServletApiAndSerializeToStaticEMFReusingEDataTypes( + @InjectService(cardinality = 1, timeout = 4000, filter = "(component.name=JavaReferenceTypeToEPackageConverter)") ServiceAware javaReferenceTypeToEPackageConverterAware, + @InjectService(timeout = 2000) ServiceAware rsAware) throws Exception { + assertThat(javaReferenceTypeToEPackageConverterAware.getServices()).hasSize(1); + JavaToEPackageConverter javaReferenceTypeToEPackageConverterService = javaReferenceTypeToEPackageConverterAware + .getService(); + assertThat(javaReferenceTypeToEPackageConverterService).isNotNull(); + + assertNotNull(rsAware); + assertThat(rsAware.getServices()).hasSize(1); + ResourceSet resourceSet = rsAware.getService(); + assertNotNull(resourceSet); + + String nsURI = "https://geckoprojects.org/jakarta/servlet/2.1.0/"; + + EPackage dynamicEPackageFromJavaReferenceTypes = javaReferenceTypeToEPackageConverterService.convert( + resourceSet.getPackageRegistry(), PACKAGE_NAME, nsURI, NS_PREFIX, + Paths.get(ORG_APACHE_FELIX_HTTP_SERVLET_API)); + assertNotNull(dynamicEPackageFromJavaReferenceTypes); + + EAnnotation versionEAnnotation = EcoreFactory.eINSTANCE.createEAnnotation(); + versionEAnnotation.setSource("Version"); + versionEAnnotation.getDetails().put("value", "2.1.0"); + dynamicEPackageFromJavaReferenceTypes.getEAnnotations().add(versionEAnnotation); + + assertEquals(PACKAGE_NAME, dynamicEPackageFromJavaReferenceTypes.getName()); + assertEquals(nsURI, dynamicEPackageFromJavaReferenceTypes.getNsURI()); + assertEquals(NS_PREFIX, dynamicEPackageFromJavaReferenceTypes.getNsPrefix()); + + EPackage.Registry.INSTANCE.put(dynamicEPackageFromJavaReferenceTypes.getNsURI(), + dynamicEPackageFromJavaReferenceTypes); + + assertThat(eClassifiersTotalCount(dynamicEPackageFromJavaReferenceTypes)).isEqualTo(198); Resource resource = resourceSet .createResource(URI.createFileURI("org.apache.felix.http.servlet-api-2.1.0.ecore")); diff --git a/org.gecko.emf.converter.tests/test.bndrun b/org.gecko.emf.converter.tests/test.bndrun index 0888b95..0c99eeb 100644 --- a/org.gecko.emf.converter.tests/test.bndrun +++ b/org.gecko.emf.converter.tests/test.bndrun @@ -45,13 +45,13 @@ assertj-core;version='[3.24.2,3.24.3)',\ net.bytebuddy.byte-buddy;version='[1.14.9,1.14.10)',\ slf4j.api;version='[1.7.36,1.7.37)',\ - slf4j.simple;version='[1.7.36,1.7.37)',\ org.apache.felix.scr;version='[2.2.6,2.2.7)',\ - org.eclipse.emf.ecore.xmi;version='[2.36.0,2.36.1)',\ org.gecko.emf.converter.model;version=snapshot,\ - org.gecko.emf.osgi.component.minimal;version='[6.1.1,6.1.2)',\ - org.osgi.service.cm;version='[1.6.1,1.6.2)',\ org.osgi.service.component;version='[1.5.1,1.5.2)',\ org.osgi.util.promise;version='[1.3.0,1.3.1)',\ org.osgi.util.converter;version='[1.0.9,1.0.10)',\ - org.apache.commons.lang3;version='[3.12.0,3.12.1)' + org.apache.commons.lang3;version='[3.12.0,3.12.1)',\ + org.eclipse.emf.ecore.xmi;version='[2.36.0,2.36.1)',\ + org.gecko.emf.osgi.component.minimal;version='[6.1.1,6.1.2)',\ + org.osgi.service.cm;version='[1.6.1,1.6.2)',\ + slf4j.simple;version='[1.7.36,1.7.37)' diff --git a/org.gecko.emf.converter/src/org/gecko/emf/converter/AbstractJavaToEPackageConverter.java b/org.gecko.emf.converter/src/org/gecko/emf/converter/AbstractJavaToEPackageConverter.java index 2f92c8b..9284441 100644 --- a/org.gecko.emf.converter/src/org/gecko/emf/converter/AbstractJavaToEPackageConverter.java +++ b/org.gecko.emf.converter/src/org/gecko/emf/converter/AbstractJavaToEPackageConverter.java @@ -157,18 +157,9 @@ public EPackage convert(String packageName, String nsURI, String nsPrefix, Class final EcoreFactory eFactory = EcoreFactory.eINSTANCE; - EPackage dynamicEPackage = eFactory.createEPackage(); - dynamicEPackage.setName(packageName); - dynamicEPackage.setNsURI(nsURI); - dynamicEPackage.setNsPrefix(nsPrefix); - - addBasePackageEAnnotation(dynamicEPackage, javaTypes); + EPackage dynamicEPackage = createEPackage(packageName, nsURI, nsPrefix, eFactory); - for (Class javaType : javaTypes) { - createEClassifier(eFactory, dynamicEPackage, javaType); - } - - return dynamicEPackage; + return convert(eFactory, dynamicEPackage, javaTypes); } /* @@ -185,16 +176,99 @@ public EPackage convert(String packageName, String nsURI, String nsPrefix, Path return convert(packageName, nsURI, nsPrefix, classes.toArray(Class[]::new)); } + /* + * (non-Javadoc) + * @see org.gecko.emf.converter.JavaToEPackageConverter#convert(org.eclipse.emf.ecore.EPackage.Registry, java.lang.String, java.lang.String, java.lang.String, java.lang.Class[]) + */ + @Override + public EPackage convert(EPackage.Registry attachedPackageRegistry, String packageName, String nsURI, + String nsPrefix, Class... javaTypes) { + Objects.requireNonNull(attachedPackageRegistry, "Package registry is required!"); + Objects.requireNonNull(packageName, "Package name is required!"); + Objects.requireNonNull(nsURI, "nsURI is required!"); + Objects.requireNonNull(nsPrefix, "nsPrefix is required!"); + Objects.requireNonNull(javaTypes, "At least one Java type is required!"); + + if (attachedPackageRegistry.isEmpty()) { + return convert(packageName, nsURI, nsPrefix, javaTypes); + } + + final EcoreFactory eFactory = EcoreFactory.eINSTANCE; + + EPackage dynamicEPackage = createEPackage(packageName, nsURI, nsPrefix, eFactory); + + addExistingEDataTypes(dynamicEPackage, attachedPackageRegistry); + + return convert(eFactory, dynamicEPackage, javaTypes); + } + + /* + * (non-Javadoc) + * @see org.gecko.emf.converter.JavaToEPackageConverter#convert(org.eclipse.emf.ecore.EPackage.Registry, java.lang.String, java.lang.String, java.lang.String, java.nio.file.Path, java.nio.file.Path[]) + */ + @Override + public EPackage convert(EPackage.Registry attachedPackageRegistry, String packageName, String nsURI, + String nsPrefix, Path mainJarFilePath, Path... dependenciesJarFilePaths) + throws ClassNotFoundException, IOException { + Objects.requireNonNull(attachedPackageRegistry, "Package registry is required!"); + Objects.requireNonNull(mainJarFilePath, "Main JAR file path is required!"); + + if (attachedPackageRegistry.isEmpty()) { + return convert(packageName, nsURI, nsPrefix, mainJarFilePath, dependenciesJarFilePaths); + } + + final EcoreFactory eFactory = EcoreFactory.eINSTANCE; + + EPackage dynamicEPackage = createEPackage(packageName, nsURI, nsPrefix, eFactory); + + addExistingEDataTypes(dynamicEPackage, attachedPackageRegistry); + + return convert(eFactory, dynamicEPackage, mainJarFilePath, dependenciesJarFilePaths); + } + + protected EPackage convert(EcoreFactory eFactory, EPackage ePackage, Class... javaTypes) { + addBasePackageEAnnotation(ePackage, javaTypes); + + for (Class javaType : javaTypes) { + createEClassifier(eFactory, ePackage, javaType); + } + + return ePackage; + } + + protected EPackage convert(EcoreFactory eFactory, EPackage ePackage, Path mainJarFilePath, + Path... dependenciesJarFilePaths) throws ClassNotFoundException, IOException { + Set> classes = getClassesFromJarFile(mainJarFilePath, dependenciesJarFilePaths); + + return convert(eFactory, ePackage, classes.toArray(Class[]::new)); + } + + protected EPackage createEPackage(String packageName, String nsURI, String nsPrefix, final EcoreFactory eFactory) { + EPackage dynamicEPackage = eFactory.createEPackage(); + dynamicEPackage.setName(packageName); + dynamicEPackage.setNsURI(nsURI); + dynamicEPackage.setNsPrefix(nsPrefix); + return dynamicEPackage; + } + + protected void addExistingEDataTypes(EPackage dynamicEPackage, EPackage.Registry attachedPackageRegistry) { + attachedPackageRegistry.forEach((attachedPackageNsURI, attachedPackage) -> { + ((EPackage) attachedPackage).getEClassifiers().stream().filter(EDataType.class::isInstance) + .map(EDataType.class::cast).forEach(dt -> dynamicEPackage.getEClassifiers().add(dt)); + }); + } + protected EClassifier createEClassifier(EcoreFactory eFactory, EPackage ePackage, Class javaType) { String eClassifierName = constructEClassifierName(javaType); + String eClassifierPackageName = javaType.getPackageName(); - if (dynamicEClassifierExists(ePackage, eClassifierName)) { + if (dynamicEClassifierExists(ePackage, eClassifierName, eClassifierPackageName)) { logger.debug("EClassifier {} already exists!", eClassifierName); if (isEnumType(javaType)) { - return (EEnum) findEClassifierByName(ePackage, eClassifierName); + return (EEnum) findEClassifierByName(ePackage, eClassifierName, eClassifierPackageName); } else { - return (EClass) findEClassifierByName(ePackage, eClassifierName); + return (EClass) findEClassifierByName(ePackage, eClassifierName, eClassifierPackageName); } } @@ -325,11 +399,12 @@ protected void createEReference(EcoreFactory eFactory, EPackage ePackage, EClass protected void createEEnum(EcoreFactory eFactory, EPackage ePackage, EClass eClass, Field field) { String eClassifierName = constructEClassifierName(field.getType()); + String eClassifierPackageName = field.getType().getPackageName(); EEnum eEnum = null; - if (dynamicEClassifierExists(ePackage, eClassifierName)) { - eEnum = (EEnum) findEClassifierByName(ePackage, eClassifierName); + if (dynamicEClassifierExists(ePackage, eClassifierName, eClassifierPackageName)) { + eEnum = (EEnum) findEClassifierByName(ePackage, eClassifierName, eClassifierPackageName); } else { eEnum = createEEnum(eFactory, ePackage, field.getType(), eClassifierName); } @@ -421,16 +496,17 @@ protected Integer getEnumCustomValue(Class enumType, Object[] enumTypeConstan protected void createArray(EcoreFactory eFactory, EPackage ePackage, EClass eClass, Field field) { String arrayTypeName = constructArrayTypeName(field); + String eClassifierPackageName = field.getType().getPackageName(); EDataType arrayType = null; - if (dynamicEClassifierExists(ePackage, arrayTypeName)) { - arrayType = (EDataType) findEClassifierByName(ePackage, arrayTypeName); + if (dynamicEClassifierExists(ePackage, arrayTypeName, eClassifierPackageName)) { + arrayType = (EDataType) findEClassifierByName(ePackage, arrayTypeName, eClassifierPackageName); } else { arrayType = eFactory.createEDataType(); arrayType.setName(arrayTypeName); - EPackage eSubPackage = getOrCreateESubPackage(eFactory, ePackage, field.getType().getPackageName()); + EPackage eSubPackage = getOrCreateESubPackage(eFactory, ePackage, eClassifierPackageName); eSubPackage.getEClassifiers().add(arrayType); } @@ -450,8 +526,9 @@ protected void createEMap(EcoreFactory eFactory, EPackage ePackage, EClass eClas EClass mapEntryEClass = null; - if (dynamicEClassifierExists(ePackage, mapEntryEClassName)) { - mapEntryEClass = (EClass) findEClassifierByName(ePackage, mapEntryEClassName); + if (dynamicEClassifierExists(ePackage, mapEntryEClassName, "java.util")) { // TODO: extract to constant + mapEntryEClass = (EClass) findEClassifierByName(ePackage, mapEntryEClassName, "java.util"); // TODO: extract + // to constant } else { mapEntryEClass = eFactory.createEClass(); mapEntryEClass.setName(mapEntryEClassName); @@ -469,8 +546,7 @@ protected void createEMap(EcoreFactory eFactory, EPackage ePackage, EClass eClas dynamicMapEntryValueEAttribute.setEType(getEClassifierForJavaType(eFactory, ePackage, mapValueActualType)); mapEntryEClass.getEStructuralFeatures().add(dynamicMapEntryValueEAttribute); - EPackage eSubPackage = getOrCreateESubPackage(eFactory, ePackage, "java.util"); -// EPackage eSubPackage = getOrCreateESubPackage(eFactory, ePackage, field.getType().getPackageName()); // TODO: verify regarding package name for map entry class + EPackage eSubPackage = getOrCreateESubPackage(eFactory, ePackage, "java.util"); // TODO: extract to constant eSubPackage.getEClassifiers().add(mapEntryEClass); } @@ -488,12 +564,15 @@ protected String constructMapEntryEClassName(Class mapKeyActualType, Class return sb.toString(); } - protected boolean dynamicEClassifierExists(EPackage ePackage, String eClassifierName) { + protected boolean dynamicEClassifierExists(EPackage ePackage, String eClassifierName, + String eClassifierPackageName) { + String eClassifierPackageSanitizedName = sanitizePackageName(eClassifierPackageName); + // @formatter:off return Stream .concat(ePackage.getEClassifiers().stream(), ePackage.getESubpackages().stream().flatMap(p -> p.getEClassifiers().stream())) - .anyMatch(eClassifier -> eClassifierName.equals(eClassifier.getName())); + .anyMatch(eClassifier -> eClassifierMatches(eClassifier, eClassifierName, eClassifierPackageSanitizedName) ); // @formatter:on } @@ -512,27 +591,35 @@ protected boolean dynamicEClassifierExistsInESubpackages(EPackage ePackage, Stri // @formatter:on } - protected EClassifier findEClassifierByName(EPackage ePackage, String eClassifierName) { + protected EClassifier findEClassifierByName(EPackage ePackage, String eClassifierName, + String eClassifierPackageName) { + String eClassifierPackageSanitizedName = sanitizePackageName(eClassifierPackageName); + // @formatter:off return Stream .concat(ePackage.getEClassifiers().stream(), ePackage.getESubpackages().stream().flatMap(p -> p.getEClassifiers().stream())) - .filter(eClassifier -> eClassifierName.equals(eClassifier.getName())) + .filter(eClassifier -> eClassifierMatches(eClassifier, eClassifierName, eClassifierPackageSanitizedName) ) .findFirst() .orElseThrow(); // @formatter:on } + protected boolean eClassifierMatches(EClassifier eClassifier, String typeName, String packageName) { + return (typeName.equals(eClassifier.getName()) && packageName.equals(eClassifier.getEPackage().getName())); + } + protected EClassifier getEClassifierForJavaType(EcoreFactory eFactory, EPackage ePackage, Class javaType) { String eClassifierName = constructEClassifierName(javaType); + String eClassifierPackageName = javaType.getPackageName(); - if (JAVATYPE_TO_EDATATYPE.containsKey(javaType)) { + if (isPredefinedEDataType(javaType)) { return JAVATYPE_TO_EDATATYPE.get(javaType); - } else if (dynamicEClassifierExists(ePackage, eClassifierName)) { + } else if (dynamicEClassifierExists(ePackage, eClassifierName, eClassifierPackageName)) { if (isEnumType(javaType)) { - return (EEnum) findEClassifierByName(ePackage, eClassifierName); + return (EEnum) findEClassifierByName(ePackage, eClassifierName, eClassifierPackageName); } else { - return (EClass) findEClassifierByName(ePackage, eClassifierName); + return (EClass) findEClassifierByName(ePackage, eClassifierName, eClassifierPackageName); } } else { if (isEnumType(javaType)) { @@ -544,13 +631,17 @@ protected EClassifier getEClassifierForJavaType(EcoreFactory eFactory, EPackage } protected EDataType getEDataTypeForJavaType(Class javaType) { - if (JAVATYPE_TO_EDATATYPE.containsKey(javaType)) { + if (isPredefinedEDataType(javaType)) { return JAVATYPE_TO_EDATATYPE.get(javaType); } else { throw new IllegalArgumentException(String.format("Type %s is not supported!", javaType.getName())); } } + protected boolean isPredefinedEDataType(Class javaType) { + return JAVATYPE_TO_EDATATYPE.containsKey(javaType); + } + protected boolean isAttributeType(Class javaType) { return ATTRIBUTE_TYPES.contains(javaType); } @@ -676,7 +767,8 @@ public int compare(Class c1, Class c2) { } }); - try (URLClassLoader cl = URLClassLoader.newInstance(jarFilesURLs.toArray(URL[]::new))) { + try (URLClassLoader cl = URLClassLoader.newInstance(jarFilesURLs.toArray(URL[]::new), + this.getClass().getClassLoader())) { for (String name : classNames) { Class clazz = cl.loadClass(name); classes.add(clazz); @@ -748,22 +840,45 @@ protected Optional findESubPackageByName(EPackage ePackage, String sub } protected EPackage getOrCreateESubPackage(EcoreFactory eFactory, EPackage ePackage, String subPackageName) { - Optional eSubPackageOptional = findESubPackageByName(ePackage, subPackageName); + String subPackageSanitizedName = sanitizePackageName(subPackageName); + + Optional eSubPackageOptional = findESubPackageByName(ePackage, subPackageSanitizedName); if (eSubPackageOptional.isPresent()) { return eSubPackageOptional.get(); } - EPackage eSubPackage = eFactory.createEPackage(); - eSubPackage.setName(subPackageName); -// eSubPackage.setNsURI(null); // TODO: if needed -// eSubPackage.setNsPrefix(null); // TODO: if needed + String subPackageNsPrefix = constructSubPackageNsPrefix(subPackageName); + String subPackageNsURI = constructSubPackageNsURI(ePackage.getNsURI(), subPackageNsPrefix); + + EPackage eSubPackage = eFactory.createEPackage(); + eSubPackage.setName(subPackageSanitizedName); + eSubPackage.setNsURI(subPackageNsURI); + eSubPackage.setNsPrefix(subPackageNsPrefix); + ePackage.getESubpackages().add(eSubPackage); return eSubPackage; } - // TODO: clarify if this is needed at all ( i.e. abbreviated package names, instead of full names / same as those found in JAR ) + protected String sanitizePackageName(String packageName) { + return packageName.replaceAll("\\.", "_"); + } + + protected String constructSubPackageNsPrefix(String subPackageName) { + // @formatter:off + return Arrays.stream(StringUtils.split(subPackageName, '.')) + .map(s -> StringUtils.capitalize(s)) + .collect(Collectors.joining()); + // @formatter:on + } + + protected String constructSubPackageNsURI(String nsUri, String suffix) { + return StringUtils.join(StringUtils.appendIfMissing(nsUri, "/"), suffix); + } + + // TODO: clarify if this is needed at all ( i.e. abbreviated package names, + // instead of full names / same as those found in JAR ) protected Set constructEPackageNames(Set packageNames, String basePackageName) { // @formatter:off return packageNames.stream() diff --git a/org.gecko.emf.converter/src/org/gecko/emf/converter/JavaReferenceTypeToEPackageConverter.java b/org.gecko.emf.converter/src/org/gecko/emf/converter/JavaReferenceTypeToEPackageConverter.java index bb8e831..15fd28c 100644 --- a/org.gecko.emf.converter/src/org/gecko/emf/converter/JavaReferenceTypeToEPackageConverter.java +++ b/org.gecko.emf.converter/src/org/gecko/emf/converter/JavaReferenceTypeToEPackageConverter.java @@ -30,6 +30,7 @@ import org.eclipse.emf.ecore.EOperation; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EParameter; +import org.eclipse.emf.ecore.ETypedElement; import org.eclipse.emf.ecore.EcoreFactory; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.ServiceScope; @@ -71,16 +72,17 @@ public JavaReferenceTypeToEPackageConverter() { @Override protected EClassifier createEClassifier(EcoreFactory eFactory, EPackage ePackage, Class javaType) { String eClassifierName = constructEClassifierName(javaType); + String eClassifierPackageName = javaType.getPackageName(); - if (dynamicEClassifierExists(ePackage, eClassifierName)) { - LOG.debug("EClassifier {} already exists!", eClassifierName); + if (dynamicEClassifierExists(ePackage, eClassifierName, eClassifierPackageName)) { + LOG.debug("EClassifier {} already exists in package {}!", eClassifierName, eClassifierPackageName); - if (isCustomEDataType(ePackage, eClassifierName)) { - return (EDataType) findEClassifierByName(ePackage, eClassifierName); + if (isCustomEDataType(ePackage, eClassifierName, eClassifierPackageName)) { + return (EDataType) findEClassifierByName(ePackage, eClassifierName, eClassifierPackageName); } else if (isEnumType(javaType)) { - return (EEnum) findEClassifierByName(ePackage, eClassifierName); + return (EEnum) findEClassifierByName(ePackage, eClassifierName, eClassifierPackageName); } else { - return (EClass) findEClassifierByName(ePackage, eClassifierName); + return (EClass) findEClassifierByName(ePackage, eClassifierName, eClassifierPackageName); } } @@ -112,20 +114,35 @@ private void createEOperation(EcoreFactory eFactory, EPackage ePackage, EClass e EOperation eOperation = eFactory.createEOperation(); eOperation.setName(method.getName()); - if ((method.getReturnType() != null) && !void.class.isAssignableFrom(method.getReturnType())) { - eOperation.setEType(getEClassifierForJavaType(eFactory, ePackage, method.getReturnType())); + Class methodReturnType = method.getReturnType(); + + if ((methodReturnType != null) && !void.class.isAssignableFrom(methodReturnType)) { + if (isArrayType(methodReturnType) && !isPredefinedEDataType(methodReturnType)) { + eOperation.setEType(getEClassifierForJavaType(eFactory, ePackage, methodReturnType.getComponentType())); + eOperation.setUpperBound(ETypedElement.UNBOUNDED_MULTIPLICITY); + } else { + eOperation.setEType(getEClassifierForJavaType(eFactory, ePackage, method.getReturnType())); + } } if (method.getParameterCount() > 0) { Parameter[] parameters = method.getParameters(); for (int i = 0; i < method.getParameterCount(); i++) { - Parameter parameter = parameters[i]; EParameter eParameter = eFactory.createEParameter(); eParameter.setName(parameter.getName()); - eParameter.setEType(getEClassifierForJavaType(eFactory, ePackage, parameter.getType())); + + Class parameterType = parameter.getType(); + + if (isArrayType(parameterType) && !isPredefinedEDataType(parameterType)) { + eParameter + .setEType(getEClassifierForJavaType(eFactory, ePackage, parameterType.getComponentType())); + eParameter.setUpperBound(ETypedElement.UNBOUNDED_MULTIPLICITY); + } else { + eParameter.setEType(getEClassifierForJavaType(eFactory, ePackage, parameterType)); + } eOperation.getEParameters().add(eParameter); } @@ -138,22 +155,53 @@ private void createEOperation(EcoreFactory eFactory, EPackage ePackage, EClass e } } - eClass.getEOperations().add(eOperation); + if (!eOperationExists(eClass, eOperation)) { + eClass.getEOperations().add(eOperation); + } + } + + protected boolean eOperationExists(EClass eClass, EOperation eOperation1) { + return eClass.getEOperations().stream().anyMatch(eOperation2 -> eOperationMatches(eOperation1, eOperation2)); + } + + protected boolean eOperationMatches(EOperation eOperation1, EOperation eOperation2) { + return (eOperation1.getName()).equals(eOperation2.getName()) + && eOperationParametersMatch(eOperation1, eOperation2); + } + + protected boolean eOperationParametersMatch(EOperation eOperation1, EOperation eOperation2) { + boolean parametersMatch = eOperation1.getEParameters().size() == eOperation2.getEParameters().size(); + + if (parametersMatch && (!eOperation1.getEParameters().isEmpty() && !eOperation2.getEParameters().isEmpty())) { + List eOperation1EParameters = eOperation1.getEParameters(); + List eOperation2EParameters = eOperation2.getEParameters(); + + for (int i = 0; i < eOperation1EParameters.size(); i++) { + parametersMatch = (eOperation1EParameters.get(i).getEType() == eOperation2EParameters.get(i) + .getEType()); + if (!parametersMatch) { + break; + } + } + } + + return parametersMatch; } @Override protected EClassifier getEClassifierForJavaType(EcoreFactory eFactory, EPackage ePackage, Class javaType) { String eClassifierName = constructEClassifierName(javaType); + String eClassifierPackageName = javaType.getPackageName(); - if (JAVATYPE_TO_EDATATYPE.containsKey(javaType)) { + if (isPredefinedEDataType(javaType)) { return JAVATYPE_TO_EDATATYPE.get(javaType); - } else if (dynamicEClassifierExists(ePackage, eClassifierName)) { - if (isCustomEDataType(ePackage, eClassifierName)) { - return (EDataType) findEClassifierByName(ePackage, eClassifierName); + } else if (dynamicEClassifierExists(ePackage, eClassifierName, eClassifierPackageName)) { + if (isCustomEDataType(ePackage, eClassifierName, eClassifierPackageName)) { + return (EDataType) findEClassifierByName(ePackage, eClassifierName, eClassifierPackageName); } else if (isEnumType(javaType)) { - return (EEnum) findEClassifierByName(ePackage, eClassifierName); + return (EEnum) findEClassifierByName(ePackage, eClassifierName, eClassifierPackageName); } else { - return (EClass) findEClassifierByName(ePackage, eClassifierName); + return (EClass) findEClassifierByName(ePackage, eClassifierName, eClassifierPackageName); } } else { if (maybeCustomEDataType(javaType)) { @@ -166,17 +214,19 @@ protected EClassifier getEClassifierForJavaType(EcoreFactory eFactory, EPackage } } - private boolean isCustomEDataType(EPackage ePackage, String eClassifierName) { + private boolean isCustomEDataType(EPackage ePackage, String eClassifierName, String eClassifierPackageName) { + String eClassifierPackageSanitizedName = sanitizePackageName(eClassifierPackageName); + // @formatter:off return Stream .concat(ePackage.getEClassifiers().stream(), ePackage.getESubpackages().stream().flatMap(p -> p.getEClassifiers().stream())) - .anyMatch(e -> eClassifierName.equals(e.getName()) && EDataType.class.isAssignableFrom(e.getClass())); + .anyMatch(eClassifier -> eClassifierMatches(eClassifier, eClassifierName, eClassifierPackageSanitizedName) && EDataType.class.isAssignableFrom(eClassifier.getClass())); // @formatter:on } private boolean maybeCustomEDataType(Class javaType) { - return (javaType.getPackageName().startsWith("java") || java.lang.Throwable.class.isAssignableFrom(javaType)); + return (javaType.getPackageName().startsWith("java.") || java.lang.Throwable.class.isAssignableFrom(javaType)); } private EDataType createCustomEDataType(EcoreFactory eFactory, EPackage ePackage, Class javaType) { @@ -192,12 +242,13 @@ private EDataType createCustomEDataType(EcoreFactory eFactory, EPackage ePackage private EDataType getEDataTypeForJavaType(EcoreFactory eFactory, EPackage ePackage, Class javaType) { String eClassifierName = constructEClassifierName(javaType); + String eClassifierPackageName = javaType.getPackageName(); - if (JAVATYPE_TO_EDATATYPE.containsKey(javaType)) { + if (isPredefinedEDataType(javaType)) { return JAVATYPE_TO_EDATATYPE.get(javaType); - } else if (dynamicEClassifierExists(ePackage, eClassifierName)) { + } else if (dynamicEClassifierExists(ePackage, eClassifierName, eClassifierPackageName)) { try { - return (EDataType) findEClassifierByName(ePackage, eClassifierName); + return (EDataType) findEClassifierByName(ePackage, eClassifierName, eClassifierPackageName); } catch (Throwable t) { return null; } diff --git a/org.gecko.emf.converter/src/org/gecko/emf/converter/JavaToEPackageConverter.java b/org.gecko.emf.converter/src/org/gecko/emf/converter/JavaToEPackageConverter.java index f733f9f..35fbd84 100644 --- a/org.gecko.emf.converter/src/org/gecko/emf/converter/JavaToEPackageConverter.java +++ b/org.gecko.emf.converter/src/org/gecko/emf/converter/JavaToEPackageConverter.java @@ -27,4 +27,10 @@ public interface JavaToEPackageConverter { EPackage convert(String packageName, String nsURI, String nsPrefix, Path mainJarFilePath, Path... dependenciesJarFilePaths) throws ClassNotFoundException, IOException; + + EPackage convert(EPackage.Registry attachedPackageRegistry, String packageName, String nsURI, String nsPrefix, + Class... javaTypes); + + EPackage convert(EPackage.Registry attachedPackageRegistry, String packageName, String nsURI, String nsPrefix, + Path mainJarFilePath, Path... dependenciesJarFilePaths) throws ClassNotFoundException, IOException; }