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;
}
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);
}
}
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");
}
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);
}
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_);
}
}
Aggregations