Search in sources :

Example 1 with JavaBeanValue

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

the class AbstractModelLoader method addValue.

private JavaBeanValue addValue(ClassOrInterface klass, MethodMirror methodMirror, String methodName, boolean isCeylon, boolean isNativeHeader) {
    JavaBeanValue value = new JavaBeanValue(methodMirror);
    value.setGetterName(methodMirror.getName());
    value.setContainer(klass);
    value.setScope(klass);
    value.setUnit(klass.getUnit());
    Type type = null;
    try {
        setMethodOrValueFlags(klass, methodMirror, value, isCeylon);
    } catch (ModelResolutionException x) {
        // collect an error in its type
        type = logModelResolutionException(x, klass, "getter '" + methodName + "' (checking if it is an overriding method");
    }
    value.setName(JvmBackendUtil.strip(methodName, isCeylon, value.isShared()));
    Module module = ModelUtil.getModuleContainer(klass);
    // do not log an additional error if we had one from checking if it was overriding
    if (type == null)
        type = obtainType(methodMirror.getReturnType(), methodMirror, klass, module, "getter '" + methodName + "'", klass);
    if (type.isCached()) {
        type = type.clone();
    }
    // special case for hash attributes which we want to pretend are of type long internally
    if (value.isShared() && methodName.equals("hash"))
        type.setUnderlyingType("long");
    NullStatus nullPolicy = getUncheckedNullPolicy(isCeylon, methodMirror.getReturnType(), methodMirror);
    switch(nullPolicy) {
        case Optional:
            if (!isCeylon) {
                type = makeOptionalTypePreserveUnderlyingType(type, module);
            }
            break;
        case UncheckedNull:
            value.setUncheckedNullType(true);
            break;
    }
    value.setType(type);
    type.setRaw(isRaw(module, methodMirror.getReturnType()));
    markUnboxed(value, methodMirror, methodMirror.getReturnType());
    markSmall(value, methodMirror.getReturnType());
    markTypeErased(value, methodMirror, methodMirror.getReturnType());
    markUntrustedType(value, methodMirror, methodMirror.getReturnType());
    value.setDeprecated(isDeprecated(methodMirror));
    setAnnotations(value, methodMirror, isNativeHeader);
    klass.addMember(value);
    ModelUtil.setVisibleScope(value);
    return value;
}
Also used : Type(org.eclipse.ceylon.model.typechecker.model.Type) UnknownType(org.eclipse.ceylon.model.typechecker.model.UnknownType) FunctionalInterfaceType(org.eclipse.ceylon.model.loader.mirror.FunctionalInterfaceType) JavaBeanValue(org.eclipse.ceylon.model.loader.model.JavaBeanValue) Module(org.eclipse.ceylon.model.typechecker.model.Module) LazyModule(org.eclipse.ceylon.model.loader.model.LazyModule)

Example 2 with JavaBeanValue

use of org.eclipse.ceylon.model.loader.model.JavaBeanValue 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 3 with JavaBeanValue

use of org.eclipse.ceylon.model.loader.model.JavaBeanValue 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 4 with JavaBeanValue

use of org.eclipse.ceylon.model.loader.model.JavaBeanValue 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)

Example 5 with JavaBeanValue

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

the class NamingBase method getSetterName.

public static String getSetterName(Declaration decl) {
    // use the refined decl except when the current declaration is variable and the refined isn't
    Declaration refinedDecl = decl.getRefinedDeclaration();
    if (isValue(decl) && isValue(refinedDecl)) {
        Value v = (Value) decl;
        Value rv = (Value) refinedDecl;
        if (!v.isVariable() || rv.isVariable()) {
            decl = refinedDecl;
        }
    } else {
        decl = refinedDecl;
    }
    if (decl instanceof FieldValue) {
        return ((FieldValue) decl).getRealName();
    }
    if (decl instanceof JavaBeanValue && // one it will not. This is also used for late setters...
    ((JavaBeanValue) decl).getSetterName() != null) {
        return ((JavaBeanValue) decl).getSetterName();
    } else if (decl.isClassOrInterfaceMember() && !isLocalToInitializer(decl) || decl.isStatic()) {
        String setterName = getSetterName(decl.getName());
        if (decl.isMember() && !decl.isShared()) {
            setterName = suffixName(Suffix.$priv$, setterName);
        }
        return setterName;
    } else if (decl instanceof TypedDeclaration && isBoxedVariable((TypedDeclaration) decl)) {
        return name(Unfix.ref);
    } else {
        return name(Unfix.set_);
    }
}
Also used : TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) Value(org.eclipse.ceylon.model.typechecker.model.Value) JavaBeanValue(org.eclipse.ceylon.model.loader.model.JavaBeanValue) FieldValue(org.eclipse.ceylon.model.loader.model.FieldValue) JvmBackendUtil.isValue(org.eclipse.ceylon.model.loader.JvmBackendUtil.isValue) TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) Declaration(org.eclipse.ceylon.model.typechecker.model.Declaration) FieldValue(org.eclipse.ceylon.model.loader.model.FieldValue) JavaBeanValue(org.eclipse.ceylon.model.loader.model.JavaBeanValue)

Aggregations

JavaBeanValue (org.eclipse.ceylon.model.loader.model.JavaBeanValue)10 FieldValue (org.eclipse.ceylon.model.loader.model.FieldValue)6 Class (org.eclipse.ceylon.model.typechecker.model.Class)6 LazyValue (org.eclipse.ceylon.model.loader.model.LazyValue)5 TypedDeclaration (org.eclipse.ceylon.model.typechecker.model.TypedDeclaration)5 Method (java.lang.reflect.Method)4 ClassOrInterface (org.eclipse.ceylon.model.typechecker.model.ClassOrInterface)4 Declaration (org.eclipse.ceylon.model.typechecker.model.Declaration)4 Type (org.eclipse.ceylon.model.typechecker.model.Type)4 Value (org.eclipse.ceylon.model.typechecker.model.Value)4 StorageException (ceylon.language.meta.model.StorageException)3 Metamodel (org.eclipse.ceylon.compiler.java.runtime.metamodel.Metamodel)3 ReflectionClass (org.eclipse.ceylon.model.loader.impl.reflect.mirror.ReflectionClass)3 LazyInterface (org.eclipse.ceylon.model.loader.model.LazyInterface)3 TypeDeclaration (org.eclipse.ceylon.model.typechecker.model.TypeDeclaration)3 Field (java.lang.reflect.Field)2 ArrayList (java.util.ArrayList)2 JvmBackendUtil.isValue (org.eclipse.ceylon.model.loader.JvmBackendUtil.isValue)2 MethodMirror (org.eclipse.ceylon.model.loader.mirror.MethodMirror)2 AnnotationProxyClass (org.eclipse.ceylon.model.loader.model.AnnotationProxyClass)2