Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » TMF (Xtext) » Annotation with Enum values(Problems generating annotations with enum values)
Annotation with Enum values [message #809803] Wed, 29 February 2012 09:27 Go to next message
Ingo Boegemann is currently offline Ingo Boegemann
Messages: 7
Registered: February 2012
Junior Member
I'm trying to create some JPA classes from my model.
When creating the annotations for Temporal types I run into a problem to create the correct annotation values @Temporal(TemporalType.DATE).

I can see the various EnumerationValues I can create but none of these seem to work for me. The closest seems to be:
TypesFactory::eINSTANCE.createJvmEnumAnnotationValue
but I have no idea how to create the correct literal.
The below code fails to generate the class without any exception being thrown (commenting anno.values+=v out generates the code but obviously doesn't add the value ...)

Any clues as to what I do wrong how to overcome this issue are very appreciated

Thanks
Ingo

   			val anno = property.toAnnotation("javax.persistence.Temporal")	   			
			val v  = TypesFactory::eINSTANCE.createJvmEnumAnnotationValue
			val op = anno.annotation.members.filter(typeof(JvmOperation)).filter(o|o.simpleName == "value").head
			v.operation = op			
			val lit = typesFactory.createJvmEnumerationLiteral
			lit.setSimpleName("Date")
			lit.setType(property.newTypeRef(typeof(TemporalType)))
			v.values+=lit	
			anno.values+=v
   			annotations+=anno	
   			body=['''return this.dateCreated;''']
Re: Annotation with Enum values [message #809854 is a reply to message #809803] Wed, 29 February 2012 11:00 Go to previous messageGo to next message
Jan Koehnlein is currently offline Jan Koehnlein
Messages: 656
Registered: July 2009
Senior Member
val anno = property.toAnnotation("javax.persistence.Temporal")

will create a new Annotation, but you want to refer to an existing one.

Use
val temporal =
typeReferences.getTypeForName("javax.persistence.Temporal",
property)
to get the JvmModel representation of the annotation and
val temporalType =
typeReferences.getTypeForName("javax.persistence.TemporalType",
property)
to get the enum class.
Then set the value of the JvmEnumAnnotationValue to a literal from
temproralType.

Am 29.02.12 10:27, schrieb Ingo Boegemann:
> I'm trying to create some JPA classes from my model.
> When creating the annotations for Temporal types I run into a problem to
> create the correct annotation values @Temporal(TemporalType.DATE).
>
> I can see the various EnumerationValues I can create but none of these
> seem to work for me. The closest seems to be:
> TypesFactory::eINSTANCE.createJvmEnumAnnotationValue
> but I have no idea how to create the correct literal.
> The below code fails to generate the class without any exception being
> thrown (commenting anno.values+=v out generates the code but obviously
> doesn't add the value ...)
>
> Any clues as to what I do wrong how to overcome this issue are very
> appreciated
>
> Thanks
> Ingo
>
>
> val anno = property.toAnnotation("javax.persistence.Temporal")
> val v = TypesFactory::eINSTANCE.createJvmEnumAnnotationValue
> val op =
> anno.annotation.members.filter(typeof(JvmOperation)).filter(o|o.simpleName
> == "value").head
> v.operation = op
> val lit = typesFactory.createJvmEnumerationLiteral
> lit.setSimpleName("Date")
> lit.setType(property.newTypeRef(typeof(TemporalType)))
> v.values+=lit
> anno.values+=v
> annotations+=anno
> body=['''return this.dateCreated;''']
>


--
Need professional support for Eclipse Modeling?
Go visit: http://xtext.itemis.com
Re: Annotation with Enum values [message #809883 is a reply to message #809854] Wed, 29 February 2012 11:51 Go to previous messageGo to next message
Ingo Boegemann is currently offline Ingo Boegemann
Messages: 7
Registered: February 2012
Junior Member
Thanks! that worked(mostly - see below) a treat

My full code looks now like:
   		members+= property.toMethod("get" + property.name.toFirstUpper,property.newTypeRef(typeof(Date)))[   			
   			val temporal = typeReferences.getTypeForName("javax.persistence.Temporal", property)			
			val op = (temporal.type as JvmAnnotationType).getDeclaredOperations().filter(o|o.simpleName == "value").head
   			val v  = TypesFactory::eINSTANCE.createJvmEnumAnnotationValue
			v.operation = op

			val anno = typesFactory.createJvmAnnotationReference		
			val annoType = 	temporal.type as JvmAnnotationType
			anno.setAnnotation(annoType)
			
   			val temporalType = typeReferences.getTypeForName("javax.persistence.TemporalType", property)
			val literal = (temporalType.type as JvmEnumerationTypeImplCustom).literals.filter(o|o.simpleName == "DATE").head
			v.values+=literal
			
			anno.values+=v
   			annotations+=anno	
   			body=['''return this.«property.name»;''']
   		]  	


Now to the catch - I get the following exception during generation now:
'java.lang.IllegalArgumentException: Unhandled parameter types: [org.eclipse.xtext.common.types.impl.JvmEnumAnnotationValueImpl@3a19e897, org.eclipse.xtext.xbase.compiler.ImportManager@6b74d6c0]'


It looks like the JvmEnumAnnotationValue has not been implemented in the JvmModelGenerator so far.

I did overcome this however by adding the type to my JvmModelGenerator extension by adding the following:
	def dispatch toJavaLiteral(JvmEnumAnnotationValueImpl it, ImportManager importManager) 
		'''«IF values.size==1»«values.head.qualifiedName»«ELSE»{«values.map(v|v.qualifiedName).join(',')»}«ENDIF»'''	

and now all is working perfectly!

Once again thanks for your help!
Ingo
Re: Annotation with Enum values [message #809963 is a reply to message #809883] Wed, 29 February 2012 14:02 Go to previous messageGo to next message
Ingo Boegemann is currently offline Ingo Boegemann
Messages: 7
Registered: February 2012
Junior Member
... and for whoever might need this ...

I abstracted the above code into a separate util class:

	@Inject TypeReferences typeReferences 
	
	
	def addJvmEnumValueToAnnotation(EObject sourceElement, JvmAnnotationReference annotationReference,
		String valueName, Class<?> enumerationClass, String literalName){
		
		val op = annotationReference.annotation.getDeclaredOperations().filter(o|o.simpleName == valueName).head
		val v  = TypesFactory::eINSTANCE.createJvmEnumAnnotationValue
		v.operation = op
		
		val enumType = typeReferences.getTypeForName(enumerationClass, sourceElement).type as JvmEnumerationTypeImplCustom
		val literal = enumType.literals.filter(o|o.simpleName == literalName).head
		v.values+=literal
		
		annotationReference.values+=v
	}


reducing the necessary code to add an enumeration value to:
			val anno = property.toAnnotation(typeof(javax.persistence.Temporal))
			property.addJvmEnumValueToAnnotation(anno,"value",typeof(javax.persistence.TemporalType),"TIMESTAMP")

[Updated on: Wed, 29 February 2012 14:04]

Report message to a moderator

JvmModelInferrer ConvenienceMethods for Annotations (Re: Annotation with Enum values) [message #1010587 is a reply to message #809803] Sun, 17 February 2013 19:40 Go to previous messageGo to next message
Michael A. is currently offline Michael A.
Messages: 8
Registered: June 2012
Junior Member
Thanks for the clue .. sorting out that stuff took me far too long.
Feel free to use that

Usage:
//Annotation with StrinParam
annotations += record.toAnnotation(typeof(javax.persistence.Table), 
   		newParamList.addStringParam("name", record.TableName) );

(.....)
//Annotation with AnnotationParam
for (q : entity.methods.filter( typeof(RecordQueryDeclaration)) )
	queryAnnotations += entity.toAnnotation(
				typeof(javax.persistence.NamedQuery), 
   				newParamList
   					.addStringParam("name", q.Identifier)
   					.addStringParam("query", q.QueryString) );

annotations += entity.toAnnotation(
		typeof(javax.persistence.NamedQueries), 
   		newParamList.addAnnotationParam("value", queryAnnotations) );

(.....)
//Annotation with EnumParam
annotations += field.toAnnotation(
			typeof(javax.persistence.Enumerated), 
			newParamList.addEnumParam(field, "value", EnumType::STRING)
		);



Lib :
import com.google.common.base.Function
import com.google.inject.internal.Nullable
import java.util.ArrayList
import java.util.Collection
import java.util.List
import java.util.Map
import java.util.TreeMap
import org.eclipse.emf.common.notify.Notifier
import org.eclipse.emf.ecore.EObject
import org.eclipse.xtext.common.types.JvmAnnotationAnnotationValue
import org.eclipse.xtext.common.types.JvmAnnotationReference
import org.eclipse.xtext.common.types.JvmAnnotationType
import org.eclipse.xtext.common.types.JvmAnnotationValue
import org.eclipse.xtext.common.types.JvmBooleanAnnotationValue
import org.eclipse.xtext.common.types.JvmEnumAnnotationValue
import org.eclipse.xtext.common.types.JvmOperation
import org.eclipse.xtext.common.types.JvmStringAnnotationValue
import org.eclipse.xtext.common.types.JvmTypeAnnotationValue
import org.eclipse.xtext.common.types.JvmTypeReference
import org.eclipse.xtext.common.types.TypesFactory
import org.eclipse.xtext.common.types.impl.JvmEnumerationTypeImplCustom
import javax.inject.Inject
import org.eclipse.xtext.common.types.util.TypeReferences
import org.eclipse.xtext.xbase.jvmmodel.JvmTypesBuilder

class CodeGenAnnotationHelpers {

 	@Inject extension TypeReferences

	@Inject extension JvmTypesBuilder typesBuilder


	def JvmAnnotationReference toAnnotation(@Nullable EObject sourceElement, Class<?> annotationType, Map<String, List<Function<JvmAnnotationType, JvmAnnotationValue>>> namedParams) {
		  
	 	val a = sourceElement.toAnnotation(annotationType) => [
	 			 		
			for(namedValue : namedParams.entrySet) {
			
				val annotationValueFactories = namedValue.value;

				values += annotationValueFactories.map([f|f.apply(annotation)]);
			} //for named param

	 	];
	 		 	
	 	return a;
	}

	def Map<String, List<Function<JvmAnnotationType, JvmAnnotationValue>>> newParamList() {
		
		return new TreeMap<String, List<Function<JvmAnnotationType, JvmAnnotationValue>>>();
	}

 
	def Map<String, List<Function<JvmAnnotationType, JvmAnnotationValue>>> addStringParam(Map<String, List<Function<JvmAnnotationType, JvmAnnotationValue>>> map, 
		String paramName, String... stringValues) {
		    		   
		return addValuesG(map, 
			TypesFactory::eINSTANCE.createJvmStringAnnotationValue, 
			paramName, stringValues, 
			[ p| return (p as JvmStringAnnotationValue).values; ]
		);   
	}
 	  
	def Map<String, List<Function<JvmAnnotationType, JvmAnnotationValue>>> addTypeParam(Map<String, List<Function<JvmAnnotationType, JvmAnnotationValue>>> map, 
		String paramName, JvmTypeReference... typeValues) {
		    		   
		return addValuesG(map,  
			TypesFactory::eINSTANCE.createJvmTypeAnnotationValue, 
			paramName, typeValues, 
			[ p| return (p as JvmTypeAnnotationValue).values; ]
		);   
	}

	def Map<String, List<Function<JvmAnnotationType, JvmAnnotationValue>>> addAnnotationParam(Map<String, List<Function<JvmAnnotationType, JvmAnnotationValue>>> map, 
		String paramName, Collection<JvmAnnotationReference> annotationValues) {
		
		return addValuesG(map, 
			TypesFactory::eINSTANCE.createJvmAnnotationAnnotationValue, 
			paramName, annotationValues, 
			[ p| return (p as JvmAnnotationAnnotationValue).annotations; ]
		);   
	}
	
	def Map<String, List<Function<JvmAnnotationType, JvmAnnotationValue>>> addAnnotationParam(Map<String, List<Function<JvmAnnotationType, JvmAnnotationValue>>> map, 
		String paramName, JvmAnnotationReference... annotationValues) {
		    		   
		val List<JvmAnnotationReference> valuesAsList = annotationValues;
		
		return addAnnotationParam(map, paramName, valuesAsList);
	}

	def Map<String, List<Function<JvmAnnotationType, JvmAnnotationValue>>> addBooleanParam(Map<String, List<Function<JvmAnnotationType, JvmAnnotationValue>>> map, 
		String paramName, Boolean... booleanValues) {
		    		    
		return addValuesG(map, 
			TypesFactory::eINSTANCE.createJvmBooleanAnnotationValue, 
			paramName, booleanValues, 
			[ p| return (p as JvmBooleanAnnotationValue).values; ]
		);   
	}
 
	def <T extends Enum<?>> Map<String, List<Function<JvmAnnotationType, JvmAnnotationValue>>> 
		addEnumParam(Map<String, List<Function<JvmAnnotationType, JvmAnnotationValue>>> map, 
		Notifier context,	
		String paramName, T... enumValues) {

		val trEnumValue = enumValues.head.getClass().canonicalName.getTypeForName(context);

		val enumType = trEnumValue.type as JvmEnumerationTypeImplCustom

		val packagedValues = enumValues.map([v| 
			
			val packagedValue = TypesFactory::eINSTANCE.createJvmEnumerationLiteral;
			packagedValue.setType(trEnumValue);

			return enumType.literals.filter([l| v.name.equals( l.simpleName )]).head;
		] );
		    		     
		return addValuesG(map, 
			TypesFactory::eINSTANCE.createJvmEnumAnnotationValue,
			paramName, packagedValues, 
			[ p|  return (p as JvmEnumAnnotationValue).values;]
		);   
	}
 
	def <ValueType, AnotationValueType extends JvmAnnotationValue> 
		Map<String, List<Function<JvmAnnotationType, JvmAnnotationValue>>> 
			addValuesG(	Map<String, List<Function<JvmAnnotationType, JvmAnnotationValue>>> map, 
						JvmAnnotationValue newAnotationParameterAssignment, 
						String paramName, ValueType[] valuesOfNamedAnnotationParameter,
						Function<JvmAnnotationValue, ? extends List<ValueType>> valuesExtr
						) {
	 
	 	val effMap = if (map != null) map else newParamList();
	 
	    if (valuesOfNamedAnnotationParameter.contains(null))
			throw new IllegalArgumentException("Value for Annotation-Param " + paramName + " must not be null.");
	 
		effMap.addValue2AnnotationParamMap(paramName, [aType | 
			
			val op = aType.members.filter(typeof(JvmOperation)).filter(o|paramName.equals(o.simpleName)).head;
			newAnotationParameterAssignment.operation = op;

			valuesExtr.apply(newAnotationParameterAssignment) += valuesOfNamedAnnotationParameter;
			
			return newAnotationParameterAssignment;	
		]); 
		  
		return effMap;
	}
    
	def	 Map<String, List<Function<JvmAnnotationType, JvmAnnotationValue>>> addValue2AnnotationParamMap(Map<String, List<Function<JvmAnnotationType, JvmAnnotationValue>>> map, String paramName, Function<JvmAnnotationType, JvmAnnotationValue> valueFactory) {
		 
		val effParamName = 
			if (paramName != null) {
				if (!"".equals(paramName)) paramName else "value";
			} else "value";
		 
		var List<Function<JvmAnnotationType, JvmAnnotationValue>> valueList = map.get(effParamName)
		if (valueList ==  null) {
			valueList = new ArrayList<Function<JvmAnnotationType, JvmAnnotationValue>>();				
			map.put(effParamName, valueList);
		} else throw new IllegalArgumentException("Duplicate creation of the '" + effParamName + "' parameter.");
		  
		valueList.add(valueFactory);
	
		return map;
	}
	
} //class
Re: JvmModelInferrer ConvenienceMethods for Annotations (Re: Annotation with Enum values) [message #1421344 is a reply to message #1010587] Thu, 11 September 2014 08:39 Go to previous message
Mohamed El-Beltagy is currently offline Mohamed El-Beltagy
Messages: 5
Registered: July 2014
Junior Member
I recommend reading this related post http://www.eclipse.org/forums/index.php/t/486005/
The Utils class seems very easy to use (although it's missing adding a list of values to an attribute)
Previous Topic:Validation problem
Next Topic:Implicit type conversion for Xbase
Goto Forum:
  


Current Time: Thu Oct 23 00:16:15 GMT 2014

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

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