Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » TMF (Xtext) » Initialization of member JvmFields in constructor of a parent JvmGenericType(Initialization of fields with XExpression not via 'JvmTypesBuilder#setInitializer' method but at some other place)
Initialization of member JvmFields in constructor of a parent JvmGenericType [message #1841241] Fri, 07 May 2021 13:26 Go to next message
Alexander Gornostaev is currently offline Alexander GornostaevFriend
Messages: 2
Registered: December 2020
Junior Member
In short, a file of my DSL is compiled to a java class with a constructor that may receive some dependencies. This java class also has some fields - those are actually added during inferring a model. Each field (JvmField) maps to some ArbitraryTypeEntity entity that is described in the file. These fields are dynamically typed - my DSL should obtain types of these fields from their corresponding initialization expressions (here they are called 'constructor' but the real expression might be just a java method, not necessarily a java constructor).

The problem: I'd like to initialize JvmFields not directly (via 'JvmTypesBuilder#setInitializer' method) but from the other place - constructor of my model. I cannot use XExpression constructor directly in the body of my model constructor (it is shown in 'generated code for not working version of the inferrer' code block). May there be some kind of a workaround for this particular problem - reuse default type computation and initialize a field from the other place?

I've made a sample project to reproduce the case and added a snippet of 'desired generated code'.

The grammar of my language:
grammar org.xtext.stackoverflow.initializer_dsl.InitializeDsl with org.eclipse.xtext.xbase.Xbase

generate initializeDsl "http://www.xtext.org/stackoverflow/initializer_dsl/InitializeDsl"

InitializeModel:
	{InitializeModel}
	elements+=ArbitraryTypeEntity*;

ArbitraryTypeEntity:
	'arbitraty entity' name=ID '=' constructor=XOrExpression ';'?
; 


My inferrer (I'd like it to be like this):
/*
 * generated by Xtext 2.25.0
 */
package org.xtext.stackoverflow.initializer_dsl.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.stackoverflow.initializer_dsl.initializeDsl.InitializeModel
import org.eclipse.xtext.common.types.JvmVisibility
import java.util.ArrayList
import java.util.HashMap

class InitializeDslJvmModelInferrer extends AbstractModelInferrer {

	@Inject extension JvmTypesBuilder

	def dispatch void infer(InitializeModel element, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
		acceptor.accept(element.toClass("InitializeModel")) [
			for (nestedElement : element.elements) {
				members += nestedElement.toField(nestedElement.name, nestedElement.constructor.inferredType) [
					final = true
					static = false
				// don't want to use initializer here as the element will later be initialized in constructor 
				]
			}
			members += element.toConstructor [
				visibility = JvmVisibility.PUBLIC
// I'd like to use the code of constructor XExpression here but I can't - it is compiled to not what I want
				body = '''
				«FOR nestedElement : element.elements»
				this.«nestedElement.name» = «nestedElement.constructor»;
				«ENDFOR»
				'''
			]
		]
	}
}


But if use this version of my inferrer (with ArbitraryTypeEntity constructor not directly used as initializer of the field), I would get this generated code:
generated code for not working version of the inferrer :
@SuppressWarnings("all")
public class InitializeModel {
  private final Object/* type is 'null' */ entity;
  
  public InitializeModel() {
    this.entity = org.eclipse.xtext.xbase.impl.XConstructorCallImplCustom@16098231 (invalidFeatureIssueCode: null, validFeature: false, explicitConstructorCall: true, anonymousClassConstructorCall: false);
  }
}



Here the type of entity is lost (of course, I didn't associate it in any way with the expression).
Then, if use the JvmTypeBuilder setInitializer function directly and connect the XExpression to JvmField as a logicalChild, it will, of course, work.

working version of inferrer, but not what I'd like to achieve:
/*
 * generated by Xtext 2.25.0
 */
package org.xtext.stackoverflow.initializer_dsl.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.stackoverflow.initializer_dsl.initializeDsl.InitializeModel
import org.eclipse.xtext.common.types.JvmVisibility
import java.util.ArrayList
import java.util.HashMap

class InitializeDslJvmModelInferrer extends AbstractModelInferrer {

	@Inject extension JvmTypesBuilder

	def dispatch void infer(InitializeModel element, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
		acceptor.accept(element.toClass("InitializeModel")) [
			
			for (nestedElement : element.elements) {
				members += nestedElement.toField(nestedElement.name, nestedElement.constructor.inferredType) [
					final = true
					static = false
					initializer = nestedElement.constructor
				]
			}
			members += element.toConstructor [
				visibility = JvmVisibility.PUBLIC
				// now no body is set
//				body = '''
//				«FOR nestedElement : element.elements»
//				this.«nestedElement.name» = «nestedElement.constructor»;
//				«ENDFOR»
//				'''

			]
		]
	}
}


generated code with the working inferrer version:
import java.util.ArrayList;

@SuppressWarnings("all")
public class InitializeModel {
  private final ArrayList<String> entity = new ArrayList<String>();
}


but what I'd like to have is this desired generated code :
import java.util.ArrayList;

@SuppressWarnings("all")
public class InitializeModel {
  private final ArrayList<String> entity;
  public InitializeModel() {
    this.entity = new ArrayList<String>();
  }
}


A possible solution that I thought of is:
1. Modify the compiler to not generate the initializing part of code for fields that are mapped to entities of ArbitraryTypeEntity type, so the fields will only be declared
2. Set the initializer - but use a somehow overridden version of XExpression
3. Use in the model constructor body this 'somehow overridden version of XExpression that could be appended to ITreeAppendable of the constructor body.

I could possibly imagine what to do for the first step, but steps 2 and 3 seem to me not realizable for now.
Re: Initialization of member JvmFields in constructor of a parent JvmGenericType [message #1841242 is a reply to message #1841241] Fri, 07 May 2021 13:39 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14492
Registered: July 2009
Senior Member
is there any reason you insist to do it in constructor?
if yes what about move the init to a (static)element/method and call it from contructor?


Need professional support for Xtext, Xpand, EMF?
Go to: https://www.itemis.com/en/it-services/methods-and-tools/xtext
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de

[Updated on: Fri, 07 May 2021 13:47]

Report message to a moderator

Re: Initialization of member JvmFields in constructor of a parent JvmGenericType [message #1841245 is a reply to message #1841242] Fri, 07 May 2021 15:26 Go to previous message
Ed Willink is currently offline Ed WillinkFriend
Messages: 7594
Registered: July 2009
Senior Member
Hi

The EMF way is for EObjects to be default constructed and then initialized by setXXX methods. This is unfortunate in terms of having solid @NonNull fields, but pretty unavoidable if you want to able to load from XML.

If you insist on rich construction, you will throw away many of the facilities that EMF offers.

Regards

Ed Willink
Previous Topic:Proper way to install antlr-generator-3.2.0-patch.jar
Next Topic:Xtext Resource Storage
Goto Forum:
  


Current Time: Tue May 30 04:51:59 GMT 2023

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

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

Back to the top