Search in sources :

Example 1 with StorageException

use of ceylon.language.meta.model.StorageException 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 2 with StorageException

use of ceylon.language.meta.model.StorageException 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 3 with StorageException

use of ceylon.language.meta.model.StorageException in project ceylon by eclipse.

the class ValueConstructorImpl 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;
    Method m = getJavaMethod(declaration);
    // local classes have no getters
    if (m == null)
        return;
    String getterName = m.getName();
    try {
        if (decl instanceof JavaBeanValue) {
            java.lang.Class<?> javaClass = Metamodel.getJavaClass((org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) decl.getContainer());
            boolean isJavaArray = MethodHandleUtil.isJavaArray(javaClass);
            // 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
            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);
            }
            // we need to cast to Object because this is what comes out when calling it in $call
            getter = getter.asType(MethodType.methodType(Object.class));
        } else if (ModelUtil.isEnumeratedConstructor(decl)) {
            java.lang.Class<?> javaClass = Metamodel.getJavaClass((org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) decl.getContainer());
            if (ModelUtil.getConstructedClass(decl).isMember()) {
                // the getter for member classes is on the enclosing class.
                javaClass = javaClass.getEnclosingClass();
            }
            // 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
            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);
            }
            // if(!ModelUtil.getConstructedClass(decl).isMember()) {
            // we need to cast to Object because this is what comes out when calling it in $call
            getter = getter.asType(MethodType.methodType(Object.class));
        // }
        } 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 (SecurityException | IllegalAccessException e) {
        throw Metamodel.newModelError("Failed to find getter method " + getterName + " for: " + decl, e);
    }
}
Also used : 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)

Aggregations

StorageException (ceylon.language.meta.model.StorageException)3 Method (java.lang.reflect.Method)3 Metamodel (org.eclipse.ceylon.compiler.java.runtime.metamodel.Metamodel)3 ReflectionClass (org.eclipse.ceylon.model.loader.impl.reflect.mirror.ReflectionClass)3 JavaBeanValue (org.eclipse.ceylon.model.loader.model.JavaBeanValue)3 LazyValue (org.eclipse.ceylon.model.loader.model.LazyValue)3 Class (org.eclipse.ceylon.model.typechecker.model.Class)2 Field (java.lang.reflect.Field)1 Ignore (org.eclipse.ceylon.compiler.java.metadata.Ignore)1 TypeDescriptor (org.eclipse.ceylon.compiler.java.runtime.model.TypeDescriptor)1 FieldValue (org.eclipse.ceylon.model.loader.model.FieldValue)1 ClassOrInterface (org.eclipse.ceylon.model.typechecker.model.ClassOrInterface)1