如何避免JvmParameterizedTypeReference:java.util.List <jvmunknowntypereference:a =“”>在Xtext中生成方法时?</jvmunknowntypereference:>

时间:2014-03-07 14:01:57

标签: xtext xtend

在我的模型中,我有更多的对象,后来生成了Java类。 例如。在一个文件中定义

Object A {
    operation getList B
}

在其他文件中:

Object B {
    operation getList A
}

1)从这个2接口应该生成:

interface A {
    java.util.List<B> getListOfBs();
}

interface B {
    java.util.List<A> getListOfAs();
}

2)相反,它是新生成的:

interface A {
    /* java.util.List<B> */ Object getListOfBs();
}

interface B {
    /* java.util.List<A> */ Object getListOfAs();
}

仅当我运行 Project - &gt;时才会发生这种情况。在Eclipse中清理...... 动作 在我改变模型中的某些内容并保存后,一切都很好,它看起来像第一个例子。 当我调查我的推理时,我注意到创建方法的返回类型被定义为 JvmParameterizedTypeReference:java.util.List&lt; JvmUnknownTypeReference:A&gt;

有没有办法在Eclipse中清理后正确生成类?

修改的 我现在有一个复制我的问题的例子。真的需要有这么多的模型文件,否则一切都运行正常。 我使用默认值创建了新的Xtext项目。我的xtext文件:

grammar org.xtext.example.mydsl.MyDsl with org.eclipse.xtext.xbase.Xbase
generate myDsl "http://www.xtext.org/example/mydsl/MyDsl"
ModelDomain:
    SubPackageDeclaration
    elements+=DataModelItem*;
SubPackageDeclaration:
    'subPackage' subPackageName=ID;
DataModelItem:
    DataType | DataObject | DataEnum;
DataType:
    'DataType' name=ID type=JvmParameterizedTypeReference;
DataObject:
    'DataObject' name=ID '{'
    ('lists' '{'
    (lists+=DataAttribute)*
    '}')?
    '}';
DataEnum:
    'DataEnum' name=ID '{'
    values+=ID (',' values+=ID)*
    '}';
DataAttribute:
    (transient?='transient')? type=[DataModelItem|QualifiedName] name=ID;

和推理者:

package org.xtext.example.mydsl.jvmmodel
import com.google.inject.Inject
import org.eclipse.xtext.common.types.JvmTypeReference
import org.eclipse.xtext.common.types.TypesFactory
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.DataEnum
import org.xtext.example.mydsl.myDsl.DataModelItem
import org.xtext.example.mydsl.myDsl.DataObject
import org.xtext.example.mydsl.myDsl.DataType
import org.xtext.example.mydsl.myDsl.SubPackageDeclaration
class MyDslJvmModelInferrer extends AbstractModelInferrer {
    @Inject extension JvmTypesBuilder
    @Inject private TypesFactory typesFactory
    def dispatch void infer(DataEnum dataEnum, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
        var packageName = ""
        if (dataEnum.eContainer != null && dataEnum.eContainer instanceof SubPackageDeclaration) {
            var implDec = (dataEnum.eContainer as SubPackageDeclaration)
            packageName = "data.model." + implDec.subPackageName
        }
        val qualifiedName = packageName + "." + dataEnum.name.toFirstUpper
        acceptor.accept(
            dataEnum.toEnumerationType(qualifiedName) [
                for (value : dataEnum.values) {
                    val jvmLiteral = typesFactory.createJvmEnumerationLiteral
                    jvmLiteral.simpleName = value
                    jvmLiteral.^static = true
                    var t1 = typesFactory.createJvmParameterizedTypeReference
                    t1.type = it
                    jvmLiteral.type = t1
                    members += jvmLiteral
                }
            ])
    }
    def dispatch void infer(DataObject dataObject, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
        var packageName = ""
        if (dataObject.eContainer != null && dataObject.eContainer instanceof SubPackageDeclaration) {
            var implDec = (dataObject.eContainer as SubPackageDeclaration)
            packageName = "data.model." + implDec.subPackageName
        }
        val qualifiedName = packageName + "." + dataObject.name.toFirstUpper
        acceptor.accept(
            dataObject.toInterface(qualifiedName) [
                superTypes += dataObject.newTypeRef("data.model.core.IDataObject")
                for (list : dataObject.lists) {
                    val JvmTypeReference ^void = dataObject.newTypeRef(Void.TYPE)
                    val JvmTypeReference listTypeRef = convertToJvmType(list.type)
                    if (listTypeRef != null && !isPreIndexingPhase) {
                        val removeMethod = list.toMethod("remove" + list.name.toFirstUpper, ^void) [
                            parameters += list.toParameter(list.name, listTypeRef)
                        ]
                        members += removeMethod
                        removeMethod.setAbstract(true);
                        val returnType = dataObject.newTypeRef("java.util.List", listTypeRef)
                        val allMethod = list.toMethod("get" + list.name.toFirstUpper + "List", returnType)[]
                        allMethod.setAbstract(true);
                        members += allMethod
                    }
                }
                val denyLoading = dataObject.toMethod("denyLoading", dataObject.newTypeRef(Void.TYPE))[]
                denyLoading.setAbstract(true);
                members += denyLoading
            ])
    }
    def public JvmTypeReference convertToJvmType(DataModelItem modelItem) {
        var JvmTypeReference typeRef
        if (modelItem instanceof DataType) {
            var typeData = (modelItem as DataType)
            typeRef = typeData.type.cloneWithProxies
        } else if (modelItem instanceof DataEnum) {
            var typeDec = (modelItem.eContainer as SubPackageDeclaration)
            var typePackageName = "data.model." + typeDec.subPackageName
            val typeData = modelItem as DataEnum
            typeRef = typeData.newTypeRef(typePackageName + "." + typeData.name)
        } else if (modelItem.eContainer != null) {
            var typeDec = (modelItem.eContainer as SubPackageDeclaration)
            var typePackageName = "data.model." + typeDec.subPackageName
            var typeQName = typePackageName + "." + modelItem.name
            typeRef = modelItem.newTypeRef(typeQName)
        }
        return typeRef
    }
}

然后我有这6个mydsl文件:
地址.mydsl

subPackage address DataObject PhoneNumber { lists { PhoneNumberType types } } DataObject Contact { lists { PhoneNumber phoneNumber } } DataObject Address { lists { PhoneNumber phoneNumber } } DataEnum PhoneNumberType { BUSINESS_PHONE , BUSINESS_FAX , BUSINESS_MOBILE , HOME_PHONE , HOME_MOBILE , HOME_FAX } DataEnum Gender { FEMALE , MALE }

2。 asset.mydsl

subPackage asset DataObject Asset { lists { LiabilityCase liabilityCase} } DataObject VehicleEquipment { lists { Address address } } DataObject LiabilityCase { } DataObject AssetVehicle { lists { VehicleEquipment serial VehicleEquipment extra } } DataObject Tires { } DataObject RentalObject { lists { Asset vehicle Asset mob Asset prop Asset estate Asset asset } } DataEnum AssetCondition { NEW , USED , DEMO } DataEnum VehicleColorType { STANDARD , PEARL_EFFECT , METALLIC , SPECIAL } DataEnum TiresType { SUMMER , WINTER } DataEnum AssetClass { VEHICLE , MOB , PROPERTY , ESTATE }

3。 businessPartner.mydsl

subPackage businesspartner DataEnum BusinessPartnerType { INDIVIDUAL , ORGANISATION } DataObject BusinessPartner { lists { Address address  Contact contact BpTransactions transaction BpAdvisorRelation advisor } } DataObject BpRiskParameters { } DataObject BpTransactions { } DataObject BalanceDetails { } DataObject BpAdvisorRelation { } DataEnum AdvisorType { ADVISOR , ADVISOR_BO , ADMINISTRATOR }

4。 invoice.mydsl

subPackage invoice DataObject Invoice{ lists { Receipt receipt } } DataObject Receipt { lists { InvoiceItem item } } DataObject ReceiptFleet { } DataObject InvoiceItem{ } DataEnum InvoiceCategory { OBJECT, SERVICE ,INVOICES } DataEnum InvoiceType { INCOMING, OUTGOING } DataEnum InvoiceStatus { OPEN, PARTIALLY_COMPLETE, COMPLETE } DataEnum ItemUnit { UNIT, PALETTE, DOZEN, LITRE } DataEnum ItemIdType { LICENSE_PLATE, CARD_NUMBER, OBJECT_ID }

5。 securities.mydsl

subPackage securities DataObject Securities {} DataEnum SecuritiesType {PARTNER_APPLICANT, GUARANTOR,SOMETHING_ELSE}

6。 types.mydsl

subPackage types DataType String java.lang.String DataType Integer java.lang.Integer DataType Double java.lang.Double DataType Date java.util.Date DataType Boolean java.lang.Boolean DataType Void java.lang.Void

生成的接口扩展data.model.core.IDataObject。这个接口没有方法。在Eclipse中执行 clean 操作后,我可以看到 getPhoneNumberList 方法生成为

public abstract /* List<data.model.address.PhoneNumber> */Object getPhoneNumberList();

以及其他方法,但其他方法都可以 我用Xtext 2.5和2.3测试了它,结果相同。

我在控制台中收到错误说:

2    [Worker-4] ERROR org.eclipse.xtext.common.types.access.jdt.JdtTypeProvider  - [Working copy] PhoneNumber.java [in data.model.address [in src-gen [in test]]] does not exist
Java Model Exception: Java Model Status [[Working copy] PhoneNumber.java [in data.model.address [in src-gen [in test]]] does not exist]

但我不知道如何解决它。

1 个答案:

答案 0 :(得分:2)

您似乎尝试在索引阶段解决交叉引用。请注意在#toClass调用的初始化程序块中定义推断类型和接口的方法。这应该工作。您的代码应如下所示:

myObject.toClass(myObject.name) [ clazz |
  myObject.operations.forEach [ op |
    clazz.members += op.toMethod( getMethodName(op), getMethodType(op)) [
      ..
    ]
  ]
]

如果您想从初始化块中引用其他类型,则必须将初始化程序拆分为两部分。任何依赖于其他类型的代码都必须进入后面的初始化部分,例如

acceptor.accept( myObject.toClass(..) [ .. ]).initializeLater [
  // more code here
]

在您的特定示例中,如果我使用此方法,推理适用于我:

def dispatch void infer(DataObject dataObject, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
    var packageName = ""
    if (dataObject.eContainer != null && dataObject.eContainer instanceof SubPackageDeclaration) {
        var implDec = (dataObject.eContainer as SubPackageDeclaration)
        packageName = "data.model." + implDec.subPackageName
    }
    val qualifiedName = packageName + "." + dataObject.name.toFirstUpper
    acceptor.accept(
        dataObject.toInterface(qualifiedName) [
            superTypes += dataObject.newTypeRef("data.model.core.IDataObject")
        ]).initializeLater[
            for (list : dataObject.lists) {
                val JvmTypeReference ^void = dataObject.newTypeRef(Void.TYPE)
                if (!isPreIndexingPhase) {
                    val JvmTypeReference listTypeRef = convertToJvmType(list.type)
                    if (listTypeRef != null) {
                        val removeMethod = list.toMethod("remove" + list.name.toFirstUpper, ^void) [
                            parameters += list.toParameter(list.name, listTypeRef)
                        ]
                        members += removeMethod
                        removeMethod.setAbstract(true);
                        val returnType = dataObject.newTypeRef("java.util.List", listTypeRef)
                        val allMethod = list.toMethod("get" + list.name.toFirstUpper + "List", returnType)[]
                        allMethod.setAbstract(true);
                        members += allMethod
                    }
                }
            }
            val denyLoading = dataObject.toMethod("denyLoading", dataObject.newTypeRef(Void.TYPE))[]
            denyLoading.setAbstract(true);
            members += denyLoading
        ]
}

所有这一切都是必要的,因为必须先完全收集这些类型才能被引用。