Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » TMF (Xtext) » Error "Type Duplicate JvmIdentifiableElement '<unnamed>'"(Grammar with NamesAreUniqueValidator in GenerateMyDsl.mwe2 produces duplicate error when MyDslJvmModelInferrer infer method is implemented)
Error "Type Duplicate JvmIdentifiableElement '<unnamed>'" [message #1786965] Wed, 16 May 2018 14:37 Go to next message
Thomas Petrou is currently offline Thomas PetrouFriend
Messages: 12
Registered: April 2018
Junior Member
Hello all,

I am getting Error "Type Duplicate JvmIdentifiableElement '<unnamed>'" and no files are generated when i enable NamesAreUniqueValidator in GenerateMyDsl.mwe2. Same Error does not exist when the validator is not implemented.

Any ideas?

The grammar:
grammar org.xtext.example.mydsl.MyDsl with org.eclipse.xtext.xbase.Xbase

import "http://www.eclipse.org/xtext/xbase/Xbase"

generate myDsl "http://www.xtext.org/example/mydsl/MyDsl"

Model:
	greetings+=Greeting*;
	
Greeting:
	'Hello' name=ID 
	'expr' expr = XBlockExpression '!'
	'link' '[' linked+=[Greeting|FQN]* ']';
	
	
FQN: ID ('.'ID)*;


The GenerateMyDsl.mwe2:
module org.xtext.example.mydsl.GenerateMyDsl

import org.eclipse.xtext.xtext.generator.*
import org.eclipse.xtext.xtext.generator.model.project.*

var rootPath = ".."

Workflow {
	
	component = XtextGenerator {
		configuration = {
			project = StandardProjectConfig {
				baseName = "org.xtext.example.mydsl"
				rootPath = rootPath
				runtimeTest = {
					enabled = true
				}
				eclipsePlugin = {
					enabled = true
				}
				eclipsePluginTest = {
					enabled = true
				}
				createEclipseMetaData = true
			}
			code = {
				encoding = "UTF-8"
				lineDelimiter = "\n"
				fileHeader = "/*\n * generated by Xtext \${version}\n */"
			}
		}
		language = StandardLanguage {
			name = "org.xtext.example.mydsl.MyDsl"
			fileExtensions = "mydsl"

			serializer = {
				generateStub = false
			}
			validator = {
				 composedCheck = "org.eclipse.xtext.validation.NamesAreUniqueValidator"
			}
		}
	}
}



The MyDslJvmModelInferrer:
/*
 * generated by Xtext 2.13.0
 */
package org.xtext.example.mydsl.jvmmodel

import com.google.inject.Inject
import org.eclipse.xtext.xbase.jvmmodel.AbstractModelInferrer
import org.eclipse.xtext.xbase.jvmmodel.IJvmDeclaredTypeAcceptor
import org.eclipse.xtext.xbase.jvmmodel.JvmTypesBuilder
import org.xtext.example.mydsl.myDsl.Model

/**
 * <p>Infers a JVM model from the source model.</p> 
 *
 * <p>The JVM model should contain all elements that would appear in the Java code 
 * which is generated from the source model. Other models link against the JVM model rather than the source model.</p>     
 */
class MyDslJvmModelInferrer extends AbstractModelInferrer {

	/**
	 * convenience API to build and initialize JVM types and their members.
	 */
	@Inject extension JvmTypesBuilder

	/**
	 * The dispatch method {@code infer} is called for each instance of the
	 * given element's type that is contained in a resource.
	 * 
	 * @param element
	 *            the model to create one or more
	 *            {@link org.eclipse.xtext.common.types.JvmDeclaredType declared
	 *            types} from.
	 * @param acceptor
	 *            each created
	 *            {@link org.eclipse.xtext.common.types.JvmDeclaredType type}
	 *            without a container should be passed to the acceptor in order
	 *            get attached to the current resource. The acceptor's
	 *            {@link IJvmDeclaredTypeAcceptor#accept(org.eclipse.xtext.common.types.JvmDeclaredType)
	 *            accept(..)} method takes the constructed empty type for the
	 *            pre-indexing phase. This one is further initialized in the
	 *            indexing phase using the lambda you pass as the last argument.
	 * @param isPreIndexingPhase
	 *            whether the method is called in a pre-indexing phase, i.e.
	 *            when the global index is not yet fully updated. You must not
	 *            rely on linking using the index if isPreIndexingPhase is
	 *            <code>true</code>.
	 */
	def dispatch void infer(Model element, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
		// Here you explain how your model is mapped to Java elements, by writing the actual translation code.
		
		// An implementation for the initial hello world example could look like this:
 		acceptor.accept(element.toClass("my.company.greeting.MyGreetings")) [
 			for (greeting : element.greetings) {
 				members += greeting.toMethod("hello" + greeting.name, typeRef(String)) [
 					body = '''
						return "Hello «greeting.name»";
					'''
				]
			}
		]
	}
}



The Test data:
Hello Name expr { true } ! link [ Name ]  
Hello Name1 expr {false} ! link [ Name Name1] 
Hello Name2 expr {false} ! link [ Name Name1 Name2 Name]


The Screenshot with the errors:
index.php/fa/32833/0/


Thank you
Thomas
Re: Error "Type Duplicate JvmIdentifiableElement '<unnamed>'" [message #1786966 is a reply to message #1786965] Wed, 16 May 2018 14:45 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14665
Registered: July 2009
Senior Member
you should use ProjectAwareUniqueClassNameValidator / UniqueClassNameValidator with xbase and not the default unique name validator or you have to adap the latter

Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: Error "Type Duplicate JvmIdentifiableElement '<unnamed>'" [message #1786973 is a reply to message #1786966] Wed, 16 May 2018 16:55 Go to previous messageGo to next message
Thomas Petrou is currently offline Thomas PetrouFriend
Messages: 12
Registered: April 2018
Junior Member
Thanks for the prompt reply.

I have added the following in my UI project
@FinalFieldsConstructor
class MyDslUiModule extends AbstractMyDslUiModule {
	
	@SingletonBinding(eager = true)
	override public Class<? extends UniqueClassNameValidator> bindUniqueClassNameValidator() {
		return ProjectAwareUniqueClassNameValidator;
	}
}


I have also modified the inferer so it generates classes instead of a single file (i expect if the name is the same the class to have the same name hence to kick the validation)
def dispatch void infer(Model element, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
		// Here you explain how your model is mapped to Java elements, by writing the actual translation code.
		
		// An implementation for the initial hello world example could look like this:
 		for (greeting : element.greetings) {
 			acceptor.accept(element.toClass("my.company.greeting."+greeting.name)) [
 			
 				members += greeting.toMethod("hello" + greeting.name, typeRef(String)) [
 					body = '''
						return "Hello «greeting.name»";
					'''
				]
			
		]}
	}


Unfortuantely i dont get any errors for the following test data. I am only getting two classes (name and name2) generated but no error
Hello Name expr { true } ! link [ Name ]  
Hello Name  expr {false} ! link [ Name ] 
Hello Name2 expr {false} ! link [ Name  Name2 Name]


Any ideas?

Thomas
Re: Error "Type Duplicate JvmIdentifiableElement '<unnamed>'" [message #1786984 is a reply to message #1786973] Wed, 16 May 2018 19:24 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14665
Registered: July 2009
Senior Member
had a look. ProjectAwareUniqueClassNameValidator is alrwady bound by deault in xbase. so no need.
but it looks like this validator does not work for local duplicates.
org.eclipse.xtext.xbase.validation.UniqueClassNameValidator.checkUniqueInIndex(JvmDeclaredType, Iterable<IEObjectDescription>)
only checks for foreign resources
=> i think its best if you write an additional check for duplicates within a file


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: Error "Type Duplicate JvmIdentifiableElement '<unnamed>'" [message #1786985 is a reply to message #1786984] Wed, 16 May 2018 19:30 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14665
Registered: July 2009
Senior Member
created https://github.com/eclipse/xtext-eclipse/issues/675

Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: Error "Type Duplicate JvmIdentifiableElement '<unnamed>'" [message #1787002 is a reply to message #1786985] Thu, 17 May 2018 07:50 Go to previous messageGo to next message
Thomas Petrou is currently offline Thomas PetrouFriend
Messages: 12
Registered: April 2018
Junior Member
Thanks Christian! You saved me from days of work :)!!!

One note is that the link inside the bug redirecting back to this forum redirects to a different discussion.

In the meantime for my own requirements i have created the following method in my project validator. Hope it helps someone else. Note it s not exactly the same semantics (any element with the attribute name that has the same value in name as another element of any type) as either ProjectAwareUniqueClassNameValidator (which aims to find infered classes with the same name) and NamesAreUniqueValidator (which is finding duplicates for the same element type group and if i understood it correctly using the scoping rules)
package org.xtext.example.mydsl.validation

import org.eclipse.emf.ecore.EObject
import org.xtext.example.mydsl.myDsl.MyDslPackage
import org.eclipse.xtext.validation.Check
import org.xtext.example.mydsl.myDsl.Model
import org.eclipse.xtext.EcoreUtil2
import java.util.stream.Collectors
import java.util.List

class MyDslValidator extends AbstractMyDslValidator {

	public static val INVALID_NAME = 'invalidName'

	@Check
	def checkDuplicates(Model element) {

		val allElements = EcoreUtil2.eAllContentsAsList(element)
		val allNamedElements = allElements.filter[p|p.eClass.EAllAttributes.filter[a|a.name.equals("name")].length == 1]
		val allNamedElementsGroups = allNamedElements.groupBy[e|e?.eGet(e?.eClass?.getEStructuralFeature("name"))]
		val allNamedElementsDuplicate = allNamedElementsGroups.filter[p1, p2|p2.length>1]
		val onlytheEObjects = allNamedElementsDuplicate.values().stream().flatMap(e|e.stream).collect(
			Collectors.toList())
		onlytheEObjects.forEach [ e |

			val nameRef = e?.eClass?.getEStructuralFeature("name")
			val nameAttr = e?.eGet(nameRef)

			error('Duplicate name ' + nameAttr + " for " + e.eClass.name,e, nameRef, INVALID_NAME)

		]

	}

}

Re: Error "Type Duplicate JvmIdentifiableElement '<unnamed>'" [message #1787003 is a reply to message #1787002] Thu, 17 May 2018 08:00 Go to previous message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14665
Registered: July 2009
Senior Member
Fixed the backlink

Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Previous Topic:Xtend Active annotations: Statically import method
Next Topic:New Project Wizard not shown
Goto Forum:
  


Current Time: Tue Apr 23 10:17:29 GMT 2024

Powered by FUDForum. Page generated in 0.03522 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top