Search in sources :

Example 1 with LazyValue

use of org.eclipse.ceylon.model.loader.model.LazyValue in project ceylon by eclipse.

the class Metamodel method getTypeDescriptorForProducedType.

public static TypeDescriptor getTypeDescriptorForProducedType(org.eclipse.ceylon.model.typechecker.model.Type type) {
    TypeDeclaration declaration = type.getDeclaration();
    if (type.isNothing()) {
        return TypeDescriptor.NothingType;
    }
    if (type.isUnion()) {
        TypeDescriptor[] tdArgs = getTypeDescriptorsForProducedTypes(type.getCaseTypes());
        return TypeDescriptor.union(tdArgs);
    }
    if (type.isIntersection()) {
        TypeDescriptor[] tdArgs = getTypeDescriptorsForProducedTypes(type.getSatisfiedTypes());
        return TypeDescriptor.intersection(tdArgs);
    }
    if (declaration instanceof LazyClass) {
        ReflectionClass classMirror = (ReflectionClass) ((LazyClass) declaration).classMirror;
        TypeDescriptor[] tdArgs = getTypeDescriptorsForProducedTypes(type.getTypeArgumentList());
        TypeDescriptor ret = TypeDescriptor.klass(classMirror.klass, tdArgs);
        if (type.getQualifyingType() != null)
            return TypeDescriptor.member(getTypeDescriptorForProducedType(type.getQualifyingType()), ret);
        return ret;
    }
    if (declaration instanceof LazyInterface) {
        ReflectionClass classMirror = (ReflectionClass) ((LazyInterface) declaration).classMirror;
        TypeDescriptor[] tdArgs = getTypeDescriptorsForProducedTypes(type.getTypeArgumentList());
        TypeDescriptor ret = TypeDescriptor.klass(classMirror.klass, tdArgs);
        if (type.getQualifyingType() != null)
            return TypeDescriptor.member(getTypeDescriptorForProducedType(type.getQualifyingType()), ret);
        return ret;
    }
    if (declaration instanceof FunctionOrValueInterface) {
        TypedDeclaration underlyingDeclaration = ((FunctionOrValueInterface) declaration).getUnderlyingDeclaration();
        TypeDescriptor[] tdArgs = getTypeDescriptorsForProducedTypes(type.getTypeArgumentList());
        TypeDescriptor ret;
        if (underlyingDeclaration.isToplevel()) {
            ReflectionClass classMirror;
            // type arguments
            if (underlyingDeclaration instanceof Setter)
                underlyingDeclaration = ((Setter) underlyingDeclaration).getGetter();
            if (underlyingDeclaration instanceof LazyValue)
                classMirror = (ReflectionClass) ((LazyValue) underlyingDeclaration).classMirror;
            else if (underlyingDeclaration instanceof LazyFunction)
                classMirror = (ReflectionClass) ((LazyFunction) underlyingDeclaration).classMirror;
            else
                throw Metamodel.newModelError("Unsupported underlying declaration type: " + underlyingDeclaration);
            ret = TypeDescriptor.functionOrValue(classMirror.klass, tdArgs);
        } else
            ret = TypeDescriptor.functionOrValue(underlyingDeclaration.getPrefixedName(), tdArgs);
        if (type.getQualifyingType() != null)
            return TypeDescriptor.member(getTypeDescriptorForProducedType(type.getQualifyingType()), ret);
        return ret;
    }
    if (declaration instanceof UnknownType) {
        ((UnknownType) declaration).reportErrors();
    }
    throw Metamodel.newModelError("Unsupported declaration type: " + (declaration == null ? "null" : declaration.getClass()));
}
Also used : FunctionOrValueInterface(org.eclipse.ceylon.model.loader.model.FunctionOrValueInterface) UnknownType(org.eclipse.ceylon.model.typechecker.model.UnknownType) TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) LazyValue(org.eclipse.ceylon.model.loader.model.LazyValue) TypeDescriptor(org.eclipse.ceylon.compiler.java.runtime.model.TypeDescriptor) ReflectionClass(org.eclipse.ceylon.model.loader.impl.reflect.mirror.ReflectionClass) LazyInterface(org.eclipse.ceylon.model.loader.model.LazyInterface) Setter(org.eclipse.ceylon.model.typechecker.model.Setter) LazyFunction(org.eclipse.ceylon.model.loader.model.LazyFunction) LazyClass(org.eclipse.ceylon.model.loader.model.LazyClass) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration)

Example 2 with LazyValue

use of org.eclipse.ceylon.model.loader.model.LazyValue in project ceylon by eclipse.

the class AbstractModelLoader method findLocalContainerFromAnnotationAndSetCompanionClass.

private Scope findLocalContainerFromAnnotationAndSetCompanionClass(Package pkg, Interface declaration, AnnotationMirror localContainerAnnotation) {
    @SuppressWarnings("unchecked") List<String> path = (List<String>) localContainerAnnotation.getValue("path");
    // we start at the package
    Scope scope = pkg;
    for (String name : path) {
        scope = (Scope) getDirectMember(scope, name);
    }
    String companionClassName = (String) localContainerAnnotation.getValue("companionClassName");
    if (companionClassName == null || companionClassName.isEmpty()) {
        declaration.setCompanionClassNeeded(false);
        return scope;
    }
    ClassMirror container;
    Scope javaClassScope;
    if (scope instanceof TypedDeclaration && ((TypedDeclaration) scope).isMember())
        javaClassScope = scope.getContainer();
    else
        javaClassScope = scope;
    if (javaClassScope instanceof LazyInterface) {
        container = ((LazyInterface) javaClassScope).companionClass;
    } else if (javaClassScope instanceof LazyClass) {
        container = ((LazyClass) javaClassScope).classMirror;
    } else if (javaClassScope instanceof LazyValue) {
        container = ((LazyValue) javaClassScope).classMirror;
    } else if (javaClassScope instanceof LazyFunction) {
        container = ((LazyFunction) javaClassScope).classMirror;
    } else if (javaClassScope instanceof SetterWithLocalDeclarations) {
        container = ((SetterWithLocalDeclarations) javaClassScope).classMirror;
    } else {
        throw new ModelResolutionException("Unknown scope class: " + javaClassScope);
    }
    String qualifiedCompanionClassName = container.getQualifiedName() + "$" + companionClassName;
    ClassMirror companionClassMirror = lookupClassMirror(pkg.getModule(), qualifiedCompanionClassName);
    if (companionClassMirror == null)
        throw new ModelResolutionException("Could not find companion class mirror: " + qualifiedCompanionClassName);
    ((LazyInterface) declaration).companionClass = companionClassMirror;
    return scope;
}
Also used : TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) LazyValue(org.eclipse.ceylon.model.loader.model.LazyValue) LazyFunction(org.eclipse.ceylon.model.loader.model.LazyFunction) ClassMirror(org.eclipse.ceylon.model.loader.mirror.ClassMirror) Scope(org.eclipse.ceylon.model.typechecker.model.Scope) LazyInterface(org.eclipse.ceylon.model.loader.model.LazyInterface) SetterWithLocalDeclarations(org.eclipse.ceylon.model.loader.model.SetterWithLocalDeclarations) List(java.util.List) ParameterList(org.eclipse.ceylon.model.typechecker.model.ParameterList) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) LazyClass(org.eclipse.ceylon.model.loader.model.LazyClass)

Example 3 with LazyValue

use of org.eclipse.ceylon.model.loader.model.LazyValue in project ceylon by eclipse.

the class ValueConstructorImpl method getJavaMethod.

// /////////////////////////////////////////
/**
 * Gets the getter {@code java.lang.reflect.Method} for the
 * given value constructor.
 */
@Ignore
public static Method getJavaMethod(ValueConstructorDeclarationImpl declaration) {
    org.eclipse.ceylon.model.typechecker.model.Value decl = (org.eclipse.ceylon.model.typechecker.model.Value) declaration.declaration;
    String getterName = "";
    try {
        if (decl instanceof JavaBeanValue) {
            java.lang.Class<?> javaClass = Metamodel.getJavaClass((org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) decl.getContainer());
            getterName = ((JavaBeanValue) decl).getGetterName();
            java.lang.Class<?>[] params = NO_PARAMS;
            boolean isJavaArray = MethodHandleUtil.isJavaArray(javaClass);
            if (isJavaArray)
                params = MethodHandleUtil.getJavaArrayGetArrayParameterTypes(javaClass, getterName);
            // if it is shared we may want to get an inherited getter, but if it's private we need the declared method to return it
            Method m = decl.isShared() ? javaClass.getMethod(getterName, params) : javaClass.getDeclaredMethod(getterName, params);
            return m;
        } else if (decl instanceof LazyValue) {
            LazyValue lazyDecl = (LazyValue) decl;
            java.lang.Class<?> javaClass = ((ReflectionClass) lazyDecl.classMirror).klass;
            // FIXME: we should really save the getter name in the LazyDecl
            getterName = NamingBase.getGetterName(lazyDecl);
            // toplevels don't have inheritance
            Method m = javaClass.getDeclaredMethod(getterName);
            return m;
        } else if (ModelUtil.isEnumeratedConstructor(decl)) {
            java.lang.Class<?> javaClass = Metamodel.getJavaClass((org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) decl.getContainer());
            Class constructedClass = ModelUtil.getConstructedClass(decl);
            if (constructedClass.isMember()) {
                // the getter for member classes is on the enclosing class.
                javaClass = javaClass.getEnclosingClass();
            } else if (ModelUtil.isLocalNotInitializer(constructedClass))
                // local class has no way to get the value
                return null;
            getterName = NamingBase.getGetterName(decl);
            java.lang.Class<?>[] params = NO_PARAMS;
            // if it is shared we may want to get an inherited getter, but if it's private we need the declared method to return it
            Method m = javaClass.getDeclaredMethod(getterName, params);
            return m;
        } else {
            throw new StorageException("Attribute " + decl.getName() + " is neither captured nor shared so it has no physical storage allocated and cannot be read by the metamodel");
        }
    } catch (NoSuchMethodException | SecurityException e) {
        throw Metamodel.newModelError("Failed to find getter method " + getterName + " for: " + decl, e);
    }
}
Also used : LazyValue(org.eclipse.ceylon.model.loader.model.LazyValue) Method(java.lang.reflect.Method) LazyValue(org.eclipse.ceylon.model.loader.model.LazyValue) JavaBeanValue(org.eclipse.ceylon.model.loader.model.JavaBeanValue) Metamodel(org.eclipse.ceylon.compiler.java.runtime.metamodel.Metamodel) Class(org.eclipse.ceylon.model.typechecker.model.Class) ReflectionClass(org.eclipse.ceylon.model.loader.impl.reflect.mirror.ReflectionClass) JavaBeanValue(org.eclipse.ceylon.model.loader.model.JavaBeanValue) StorageException(ceylon.language.meta.model.StorageException) Ignore(org.eclipse.ceylon.compiler.java.metadata.Ignore)

Example 4 with LazyValue

use of org.eclipse.ceylon.model.loader.model.LazyValue in project ceylon by eclipse.

the class ValueImpl method initField.

private void initField(Object instance, Type valueType) {
    org.eclipse.ceylon.model.typechecker.model.Value decl = (org.eclipse.ceylon.model.typechecker.model.Value) declaration.declaration;
    String name = decl.getName();
    if (decl instanceof JavaBeanValue) {
        java.lang.Class<?> javaClass = Metamodel.getJavaClass((org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) decl.getContainer());
        if (javaClass == ceylon.language.Object.class || javaClass == ceylon.language.Basic.class || javaClass == ceylon.language.Identifiable.class) {
            if ("string".equals(name) || "hash".equals(name)) {
                // look it up on j.l.Object, getterName should work
                javaClass = java.lang.Object.class;
            } else {
                throw Metamodel.newModelError("Object/Basic/Identifiable member not supported: " + name);
            }
        } else if (javaClass == ceylon.language.Throwable.class) {
            if ("cause".equals(name) || "message".equals(name) || "suppressed".equals(name)) {
                javaClass = instance.getClass();
                isSuppressed = "suppressed".equals(name);
            }
        }
        String getterName = ((JavaBeanValue) decl).getGetterName();
        try {
            Class<?>[] params;
            if (!declaration.getStatic()) {
                params = NO_PARAMS;
            } else {
                int numCapturedTypeParams = ((ClassOrInterface) declaration.declaration.getContainer()).getTypeParameters().size();
                params = new Class[numCapturedTypeParams];
                Arrays.fill(params, TypeDescriptor.class);
            }
            boolean isJavaArray = MethodHandleUtil.isJavaArray(javaClass);
            if (isJavaArray)
                params = MethodHandleUtil.getJavaArrayGetArrayParameterTypes(javaClass, getterName);
            // if it is shared we may want to get an inherited getter, but if it's private we need the declared method to return it
            Method m = decl.isShared() ? javaClass.getMethod(getterName, params) : javaClass.getDeclaredMethod(getterName, params);
            m.setAccessible(true);
            getter = MethodHandles.lookup().unreflect(m);
            java.lang.Class<?> getterType = m.getReturnType();
            getter = MethodHandleUtil.boxReturnValue(getter, getterType, valueType);
            if (instance != null && // XXXArray.getArray is static but requires an instance as first param
            (isJavaArray || !Modifier.isStatic(m.getModifiers()))) {
                getter = getter.bindTo(instance);
            }
            if (declaration.getStatic()) {
                getter = getter.asType(MethodType.methodType(Object.class, params));
                TypeDescriptor[] typeArguments = ((TypeDescriptor.Class) ((ClassOrInterfaceImpl<?>) container).$reifiedType).getTypeArguments();
                getter = getter.asSpreader(TypeDescriptor[].class, typeArguments.length);
                getter = getter.bindTo(typeArguments);
            } else {
                // we need to cast to Object because this is what comes out when calling it in $call
                getter = getter.asType(MethodType.methodType(Object.class));
            }
            initSetter(decl, javaClass, getterType, instance, valueType);
        } catch (NoSuchMethodException | SecurityException | IllegalAccessException e) {
            throw Metamodel.newModelError("Failed to find getter method " + getterName + " for: " + decl, e);
        }
    } else if (decl instanceof LazyValue) {
        LazyValue lazyDecl = (LazyValue) decl;
        java.lang.Class<?> javaClass = ((ReflectionClass) lazyDecl.classMirror).klass;
        // FIXME: we should really save the getter name in the LazyDecl
        String getterName = NamingBase.getGetterName(lazyDecl);
        try {
            // toplevels don't have inheritance
            Method m = javaClass.getDeclaredMethod(getterName);
            m.setAccessible(true);
            getter = MethodHandles.lookup().unreflect(m);
            java.lang.Class<?> getterType = m.getReturnType();
            getter = MethodHandleUtil.boxReturnValue(getter, getterType, valueType);
            // we need to cast to Object because this is what comes out when calling it in $call
            getter = getter.asType(MethodType.methodType(Object.class));
            initSetter(decl, javaClass, getterType, null, valueType);
        } catch (NoSuchMethodException | SecurityException | IllegalAccessException e) {
            throw Metamodel.newModelError("Failed to find getter method " + getterName + " for: " + decl, e);
        }
    } else if (decl instanceof FieldValue) {
        FieldValue fieldDecl = (FieldValue) decl;
        java.lang.Class<?> javaClass = Metamodel.getJavaClass((org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) decl.getContainer());
        String fieldName = fieldDecl.getRealName();
        if (MethodHandleUtil.isJavaArray(javaClass)) {
            try {
                Method method = Array.class.getDeclaredMethod("getLength", Object.class);
                getter = MethodHandles.lookup().unreflect(method);
                java.lang.Class<?> getterType = method.getReturnType();
                getter = MethodHandleUtil.boxReturnValue(getter, getterType, valueType);
                // this one is static but requires an instance a first param
                if (instance != null)
                    getter = getter.bindTo(instance);
                // we need to cast to Object because this is what comes out when calling it in $call
                getter = getter.asType(MethodType.methodType(Object.class));
            } catch (NoSuchMethodException | SecurityException | IllegalAccessException e) {
                throw Metamodel.newModelError("Failed to find Array.getLength method for: " + decl, e);
            }
        } else {
            try {
                // fields are not inherited
                Field f = javaClass.getDeclaredField(fieldName);
                f.setAccessible(true);
                getter = MethodHandles.lookup().unreflectGetter(f);
                java.lang.Class<?> getterType = f.getType();
                getter = MethodHandleUtil.boxReturnValue(getter, getterType, valueType);
                if (instance != null && !Modifier.isStatic(f.getModifiers()))
                    getter = getter.bindTo(instance);
                // we need to cast to Object because this is what comes out when calling it in $call
                getter = getter.asType(MethodType.methodType(Object.class));
                initSetter(decl, javaClass, getterType, instance, valueType);
            } catch (NoSuchFieldException | SecurityException | IllegalAccessException e) {
                throw Metamodel.newModelError("Failed to find field " + fieldName + " for: " + decl, e);
            }
        }
    } else if (ModelUtil.isEnumeratedConstructor(decl)) {
        java.lang.Class<?> javaClass = Metamodel.getJavaClass((org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) decl.getContainer());
        String getterName = NamingBase.getGetterName(decl);
        try {
            Class<?>[] params = NO_PARAMS;
            // if it is shared we may want to get an inherited getter, but if it's private we need the declared method to return it
            Method m = decl.isShared() ? javaClass.getMethod(getterName, params) : javaClass.getDeclaredMethod(getterName, params);
            m.setAccessible(true);
            getter = MethodHandles.lookup().unreflect(m);
            java.lang.Class<?> getterType = m.getReturnType();
            getter = MethodHandleUtil.boxReturnValue(getter, getterType, valueType);
            if (instance != null && // XXXArray.getArray is static but requires an instance as first param
            (!Modifier.isStatic(m.getModifiers()))) {
                getter = getter.bindTo(instance);
            }
            // we need to cast to Object because this is what comes out when calling it in $call
            getter = getter.asType(MethodType.methodType(Object.class));
            initSetter(decl, javaClass, getterType, instance, valueType);
        } catch (NoSuchMethodException | SecurityException | IllegalAccessException e) {
            throw Metamodel.newModelError("Failed to find getter method " + getterName + " for: " + decl, e);
        }
    } else
        throw new StorageException("Attribute " + name + " is neither captured nor shared so it has no physical storage allocated and cannot be read by the metamodel");
}
Also used : ClassOrInterface(org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) LazyValue(org.eclipse.ceylon.model.loader.model.LazyValue) Field(java.lang.reflect.Field) Metamodel(org.eclipse.ceylon.compiler.java.runtime.metamodel.Metamodel) FieldValue(org.eclipse.ceylon.model.loader.model.FieldValue) Method(java.lang.reflect.Method) TypeDescriptor(org.eclipse.ceylon.compiler.java.runtime.model.TypeDescriptor) LazyValue(org.eclipse.ceylon.model.loader.model.LazyValue) JavaBeanValue(org.eclipse.ceylon.model.loader.model.JavaBeanValue) FieldValue(org.eclipse.ceylon.model.loader.model.FieldValue) ReflectionClass(org.eclipse.ceylon.model.loader.impl.reflect.mirror.ReflectionClass) JavaBeanValue(org.eclipse.ceylon.model.loader.model.JavaBeanValue) StorageException(ceylon.language.meta.model.StorageException)

Example 5 with LazyValue

use of org.eclipse.ceylon.model.loader.model.LazyValue in project ceylon by eclipse.

the class ValueImpl method initSetter.

private void initSetter(org.eclipse.ceylon.model.typechecker.model.Value decl, java.lang.Class<?> javaClass, java.lang.Class<?> getterReturnType, Object instance, Type valueType) {
    if (!decl.isVariable() && !decl.isLate())
        return;
    if (ModelUtil.isEnumeratedConstructor(decl)) {
        return;
    }
    if (decl instanceof JavaBeanValue) {
        String setterName = ((JavaBeanValue) decl).getSetterName();
        try {
            Method m = javaClass.getMethod(setterName, getterReturnType);
            m.setAccessible(true);
            setter = MethodHandles.lookup().unreflect(m);
            if (instance != null && !Modifier.isStatic(m.getModifiers()))
                setter = setter.bindTo(instance);
            setter = setter.asType(MethodType.methodType(void.class, getterReturnType));
            setter = MethodHandleUtil.unboxArguments(setter, 0, 0, new java.lang.Class[] { getterReturnType }, Arrays.asList(valueType));
        } catch (NoSuchMethodException | SecurityException | IllegalAccessException e) {
            throw Metamodel.newModelError("Failed to find setter method " + setterName + " for: " + decl, e);
        }
    } else if (decl instanceof LazyValue) {
        // FIXME: we should really save the getter name in the LazyDecl
        String setterName = NamingBase.getSetterName(decl);
        try {
            Method m = javaClass.getMethod(setterName, getterReturnType);
            m.setAccessible(true);
            setter = MethodHandles.lookup().unreflect(m);
            setter = setter.asType(MethodType.methodType(void.class, getterReturnType));
            setter = MethodHandleUtil.unboxArguments(setter, 0, 0, new java.lang.Class[] { getterReturnType }, Arrays.asList(valueType));
        } catch (NoSuchMethodException | SecurityException | IllegalAccessException e) {
            throw Metamodel.newModelError("Failed to find setter method " + setterName + " for: " + decl, e);
        }
    } else if (decl instanceof FieldValue) {
        String fieldName = ((FieldValue) decl).getRealName();
        try {
            Field f = javaClass.getField(fieldName);
            f.setAccessible(true);
            setter = MethodHandles.lookup().unreflectSetter(f);
            if (instance != null && !Modifier.isStatic(f.getModifiers()))
                setter = setter.bindTo(instance);
            setter = setter.asType(MethodType.methodType(void.class, getterReturnType));
            setter = MethodHandleUtil.unboxArguments(setter, 0, 0, new java.lang.Class[] { getterReturnType }, Arrays.asList(valueType));
        } catch (NoSuchFieldException | SecurityException | IllegalAccessException e) {
            throw Metamodel.newModelError("Failed to find field " + fieldName + " for: " + decl, e);
        }
    } else
        throw Metamodel.newModelError("Unsupported attribute type: " + decl);
}
Also used : LazyValue(org.eclipse.ceylon.model.loader.model.LazyValue) Method(java.lang.reflect.Method) Field(java.lang.reflect.Field) ReflectionClass(org.eclipse.ceylon.model.loader.impl.reflect.mirror.ReflectionClass) JavaBeanValue(org.eclipse.ceylon.model.loader.model.JavaBeanValue) FieldValue(org.eclipse.ceylon.model.loader.model.FieldValue)

Aggregations

LazyValue (org.eclipse.ceylon.model.loader.model.LazyValue)7 ReflectionClass (org.eclipse.ceylon.model.loader.impl.reflect.mirror.ReflectionClass)4 Method (java.lang.reflect.Method)3 JavaBeanValue (org.eclipse.ceylon.model.loader.model.JavaBeanValue)3 LazyFunction (org.eclipse.ceylon.model.loader.model.LazyFunction)3 TypedDeclaration (org.eclipse.ceylon.model.typechecker.model.TypedDeclaration)3 StorageException (ceylon.language.meta.model.StorageException)2 Field (java.lang.reflect.Field)2 Metamodel (org.eclipse.ceylon.compiler.java.runtime.metamodel.Metamodel)2 TypeDescriptor (org.eclipse.ceylon.compiler.java.runtime.model.TypeDescriptor)2 AnnotationMirror (org.eclipse.ceylon.model.loader.mirror.AnnotationMirror)2 ClassMirror (org.eclipse.ceylon.model.loader.mirror.ClassMirror)2 FieldValue (org.eclipse.ceylon.model.loader.model.FieldValue)2 LazyClass (org.eclipse.ceylon.model.loader.model.LazyClass)2 LazyInterface (org.eclipse.ceylon.model.loader.model.LazyInterface)2 ClassOrInterface (org.eclipse.ceylon.model.typechecker.model.ClassOrInterface)2 TypeDeclaration (org.eclipse.ceylon.model.typechecker.model.TypeDeclaration)2 ArrayList (java.util.ArrayList)1 LinkedList (java.util.LinkedList)1 List (java.util.List)1