Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » TMF (Xtext) » Generate includes for types referenced in body of inferred methods
Generate includes for types referenced in body of inferred methods [message #1386150] Fri, 13 June 2014 16:08 Go to next message
David Wegener is currently offline David WegenerFriend
Messages: 1445
Registered: July 2009
Senior Member
I have an XBased grammar that uses a JvmModelInferrer to generate .java files for the model elements. If the body of a method for an inferred type refers to a JVM type that isn't a field or method parameter of the class, I have to include the fully qualified name of the type. Is there any way to have these types added to the generated import statements of the generated .java file?

I have added the following method generation to the Domainmodel example to demonstrate. The method builds a List<String> of all the features in the entity and then converts the List to a String[] as the return. Both java.util.List<String> and java.util.ArrayList<String> have to be fully qualified in the generation text. These are the types I'm trying to get import statements generated for.

members += entity.toMethod("getFeatures", entity.newTypeRef(String).addArrayTypeDimension) [
	body = [append('''
		java.util.List<String> featureNames = new java.util.ArrayList<String>();
		«FOR f:entity.features»
			featureNames.add("«f.name»");
		«ENDFOR»
		return featureNames.toArray(new String[featureNames.size()]);
	''')]


The code generates a method similar to:
  public String[] getFeatures() {
    java.util.List<String> featureNames = new java.util.ArrayList<String>();
    featureNames.add("Name");
    featureNames.add("age");
    return featureNames.toArray(new String[featureNames.size()]);
    
  }


I'm trying to get something like

import java.util.List;
import java.util.ArrayList;
...
  public String[] getFeatures() {
    List<String> featureNames = new ArrayList<String>();
    featureNames.add("Name");
    featureNames.add("age");
    return featureNames.toArray(new String[featureNames.size()]);
    
  }
Re: Generate includes for types referenced in body of inferred methods [message #1386153 is a reply to message #1386150] Fri, 13 June 2014 17:15 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14665
Registered: July 2009
Senior Member
Hmmm it looks like all api for that is hidden. can you please file a enhancement request for better api (e.g. one that gives access to importmanager

as a workaround:

		body = [
		append(entity.newTypeRef(List, entity.newTypeRef(String)).type)
		append('''
		  featureNames = new ''')
		 append(entity.newTypeRef(ArrayList, entity.newTypeRef(String)).type)
		 .append('''();
		«FOR f:entity.features»
			featureNames.add("«f.name»");
		«ENDFOR»
		return featureNames.toArray(new String[featureNames.size()]);
	''')]]	


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: Generate includes for types referenced in body of inferred methods [message #1386154 is a reply to message #1386153] Fri, 13 June 2014 17:26 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14665
Registered: July 2009
Senior Member
hmmm actually it is not working but this is
package org.eclipse.xtext.example.domainmodel.jvmmodel

import com.google.inject.Inject
import java.util.ArrayList
import java.util.List
import org.eclipse.xtext.common.types.JvmField
import org.eclipse.xtext.example.domainmodel.domainmodel.Entity
import org.eclipse.xtext.example.domainmodel.domainmodel.Operation
import org.eclipse.xtext.example.domainmodel.domainmodel.Property
import org.eclipse.xtext.naming.IQualifiedNameProvider
import org.eclipse.xtext.xbase.jvmmodel.AbstractModelInferrer
import org.eclipse.xtext.xbase.jvmmodel.IJvmDeclaredTypeAcceptor
import org.eclipse.xtext.xbase.jvmmodel.JvmTypesBuilder
import org.eclipse.xtext.xbase.lib.Procedures.Procedure1
import org.eclipse.xtext.xbase.typesystem.legacy.StandardTypeReferenceOwner
import org.eclipse.xtext.xbase.typesystem.references.OwnedConverter
import org.eclipse.xtext.xbase.typesystem.util.CommonTypeComputationServices

class DomainmodelJvmModelInferrer extends AbstractModelInferrer {
	
	@Inject extension JvmTypesBuilder
	@Inject extension IQualifiedNameProvider

@Inject
	private CommonTypeComputationServices services;

	def dispatch infer(Entity entity, IJvmDeclaredTypeAcceptor acceptor, boolean prelinkingPhase) {
		acceptor.accept(
			entity.toClass( entity.fullyQualifiedName )
		).initializeLater [
			
			members += entity.toMethod("getFeatures", entity.newTypeRef(String).addArrayTypeDimension) [
				
				val that = it
				
		body = [
			val StandardTypeReferenceOwner owner = new StandardTypeReferenceOwner(services, that);
		val OwnedConverter converter = new OwnedConverter(owner);
		var t1 = converter.toLightweightReference(entity.newTypeRef(List, entity.newTypeRef(String)))
		var t2 = converter.toLightweightReference(entity.newTypeRef(ArrayList, entity.newTypeRef(String)))
			
		
			
		append(t1)
		append(''' featureNames = new ''')
		 append(t2)
		 .append('''();
		«FOR f:entity.features»
			featureNames.add("«f.name»");
		«ENDFOR»
		return featureNames.toArray(new String[featureNames.size()]);
	''')]]
			
			
			
			documentation = entity.documentation
			if (entity.superType != null)
				superTypes += entity.superType.cloneWithProxies
			val procedure = entity.newTypeRef(Procedure1, it.newTypeRef())
			members += entity.toConstructor() []
			members += entity.toConstructor() [
				parameters += entity.toParameter("initializer", procedure)
				body = '''initializer.apply(this);'''
			]
			val fields = <JvmField>newArrayList()
			for ( f : entity.features ) {
				switch f {
			
					Property : {
						val field = f.toField(f.name, f.type)
						fields += field
						members += field
						members += f.toGetter(f.name, f.type)
						members += f.toSetter(f.name, f.type)
					}
			
					Operation : {
						members += f.toMethod(f.name, f.type ?: inferredType) [
							documentation = f.documentation
							for (p : f.params) {
								parameters += p.toParameter(p.name, p.parameterType)
							}
							body = f.body
						]
					}
				}
			}
			members += entity.toToStringMethod(it)
		]
	}
	
}


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: Generate includes for types referenced in body of inferred methods [message #1386158 is a reply to message #1386154] Fri, 13 June 2014 18:44 Go to previous messageGo to next message
David Wegener is currently offline David WegenerFriend
Messages: 1445
Registered: July 2009
Senior Member
Here is the bugzilla link for the feature request:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=437413

I'll look into the suggested work around.
Re: Generate includes for types referenced in body of inferred methods [message #1386216 is a reply to message #1386153] Sun, 15 June 2014 08:53 Go to previous messageGo to next message
Lorenzo Bettini is currently offline Lorenzo BettiniFriend
Messages: 1812
Registered: July 2009
Location: Firenze, Italy
Senior Member
On 13/06/2014 19:15, Christian Dietrich wrote:
> Hmmm it looks like all api for that is hidden. can you please file a
> enhancement request for better api (e.g. one that gives access to
> importmanager
>
> as a workaround:
>
>
> body = [
> append(entity.newTypeRef(List, entity.newTypeRef(String)).type)
> append('''
> featureNames = new ''')
> append(entity.newTypeRef(ArrayList,
> entity.newTypeRef(String)).type)
> .append('''();
> «FOR f:entity.features»
> featureNames.add("«f.name»");
> «ENDFOR»
> return featureNames.toArray(new String[featureNames.size()]);
> ''')]]
>

If I remember correctly in Xtext 2.5.0 StringConcatenationClient has
been introduced to solve this issue.

In the inferrer you don't need to use it directly: you just use it for
the body, but you need to pass a multiline string directly (not using a
lambda); this should work (but I haven't tested it):

body = '''
«List<String>» featureNames = new «ArrayList<String>»();
'''

cheers
Lorenzo

--
Lorenzo Bettini, PhD in Computer Science, DI, Univ. Torino
HOME: http://www.lorenzobettini.it
Xtext Book:
http://www.packtpub.com/implementing-domain-specific-languages-with-xtext-and-xtend/book


Re: Generate includes for types referenced in body of inferred methods [message #1386218 is a reply to message #1386216] Sun, 15 June 2014 10:33 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14665
Registered: July 2009
Senior Member
Hi,

it actually works but you have to care about generics yourself

'''
«List»<«String»> featureNames = new «ArrayList»<«String»>();
'''


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: Generate includes for types referenced in body of inferred methods [message #1728101 is a reply to message #1386218] Thu, 31 March 2016 06:43 Go to previous messageGo to next message
Larry LeBron is currently offline Larry LeBronFriend
Messages: 124
Registered: October 2015
Senior Member
I am trying to solve a similar problem and came across this old thread.

Is there now a more general solution to this?

For example, I am building the body of a complicated method, and find it easier to rely on a StringBuilder than a multiline String.

So, in the end, my method creation looks like:

source.toMethod(methodName, typeRef(boolean)) [
   body =
'''
«methodBodyBuilder.toString»
return false;
''']


Depending on the control, a certain type may or may not be referenced to the String Builder. However, this is not triggering the auto-import of the type.

Is there any way to explicitly pass a type to the import manager so that the type will be imported in this case?
Re: Generate includes for types referenced in body of inferred methods [message #1728102 is a reply to message #1728101] Thu, 31 March 2016 06:47 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14665
Registered: July 2009
Senior Member
Make the Method builder of Type StringConcatenationClient and leave oft the toString


def StringConcatenationClient methodBuilder(....) {
'''...'''
}


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: Generate includes for types referenced in body of inferred methods [message #1728105 is a reply to message #1728102] Thu, 31 March 2016 07:17 Go to previous messageGo to next message
Larry LeBron is currently offline Larry LeBronFriend
Messages: 124
Registered: October 2015
Senior Member
Hmm, I'm not sure if I fully understand.

Are you saying I should use a StringConcatenationClient instead of using a StringBuilder for appending the bits of my method body?

I tried subclassing StringConcatenationClient to do this, but it does not offer the same interface as StringBuilder. There is an appendTo method, but it's not clear how to set things up to work properly.

Just to clarify, my current pattern is:


val StringBuilder methodBodyBuilder = new StringBuilder

// iterate through EObjects, appending Strings to the methodBodyBuilder
// e.g. which I would want to import "Type"
methodBodyBuilder.append('''«Type».method(«args»)'''

// Once this is all done, build the method, using the StringBuilder:

source.toMethod(methodName, typeRef(boolean)) [
   body =
'''
«methodBodyBuilder.toString»
return false;
''']


I also tried just dumping my StringBuilder's contents into a StringConcatenationClient, but that did not cause the type to be imported either.

Thanks yet again!

Re: Generate includes for types referenced in body of inferred methods [message #1728106 is a reply to message #1728105] Thu, 31 March 2016 07:23 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14665
Registered: July 2009
Senior Member
as i said. forget the damn string builder.

Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: Generate includes for types referenced in body of inferred methods [message #1728109 is a reply to message #1728106] Thu, 31 March 2016 07:46 Go to previous messageGo to next message
Larry LeBron is currently offline Larry LeBronFriend
Messages: 124
Registered: October 2015
Senior Member
Ok, fair enough.

So, is there a usage example for a StringConcatenationClient which is appended to incrementally in this way, to build up a method over time, without relying on one single multiline template?
Re: Generate includes for types referenced in body of inferred methods [message #1728110 is a reply to message #1728109] Thu, 31 March 2016 07:51 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14665
Registered: July 2009
Senior Member
StringConcatenationClient _client = new StringConcatenationClient() {
@Override
protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) {
_builder.append("binder.bind(");
_builder.append(IResourceDescriptions.class, "");
_builder.append(".class).to(");
_builder.append(ResourceSetBasedResourceDescriptions.class, "");
_builder.append(".class);");
}
};


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: Generate includes for types referenced in body of inferred methods [message #1728112 is a reply to message #1728110] Thu, 31 March 2016 07:52 Go to previous message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14665
Registered: July 2009
Senior Member
btw i dont get the over time argument

''''
<<firstSubMethod>>
<<secondSubMethid>>
<<IF ...>>
<<ENDIF>>
....
''


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Previous Topic:RPG, RPGLE and RPG Free Format
Next Topic:XMIException when binding two languages
Goto Forum:
  


Current Time: Thu Apr 25 06:51:26 GMT 2024

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

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

Back to the top