blob: c4e7de11af29f7e26cbf10b17a9cfbcb133a40a6 [file] [log] [blame]
/*
*
* Copyright (c) 2011, 2016 - Loetz GmbH&Co.KG (69115 Heidelberg, Germany)
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Florian Pirchner - Initial implementation
* Loetz GmbH&Co.KG
*
*/
package org.eclipse.osbp.vaadin.emf.data;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.xtext.common.types.JvmAnnotationReference;
import org.eclipse.xtext.common.types.JvmAnnotationType;
import org.eclipse.xtext.common.types.JvmDeclaredType;
import org.eclipse.xtext.common.types.JvmFeature;
import org.eclipse.xtext.common.types.JvmField;
import org.eclipse.xtext.common.types.JvmOperation;
import org.eclipse.xtext.common.types.JvmParameterizedTypeReference;
import org.eclipse.xtext.common.types.JvmPrimitiveType;
import org.eclipse.xtext.common.types.JvmType;
import org.eclipse.xtext.common.types.JvmVisibility;
import org.eclipse.xtext.common.types.util.RawSuperTypes;
import org.eclipse.xtext.xbase.lib.StringExtensions;
// TODO: Auto-generated Javadoc
/**
* Helper class to collect all properties for a given JvmType.
*/
@SuppressWarnings("restriction")
public class JvmTypeProperties {
/**
* Normalizes the method name.
*
* @param simpleName
* the simple name
* @return the string
*/
public static String toPropertyName(String simpleName) {
if (simpleName == null) {
return null;
}
String tempName = null;
if (isSetter(simpleName)) {
tempName = StringExtensions.toFirstLower(simpleName.replaceFirst(
"set", ""));
} else if (isGetter(simpleName)) {
if (simpleName.startsWith("get")) {
tempName = StringExtensions.toFirstLower(simpleName
.replaceFirst("get", ""));
} else {
tempName = StringExtensions.toFirstLower(simpleName
.replaceFirst("is", ""));
}
}
return tempName;
}
/**
* Checks if is getter.
*
* @param simpleName
* the simple name
* @return true, if is getter
*/
public static boolean isGetter(String simpleName) {
if (simpleName == null) {
return false;
}
return simpleName.startsWith("get") || simpleName.startsWith("is");
}
/**
* Checks if is setter.
*
* @param simpleName
* the simple name
* @return true, if is setter
*/
public static boolean isSetter(String simpleName) {
return simpleName != null && simpleName.startsWith("set");
}
/**
* Calculates the operation infos for the given type.
*
* @param type
* the type
* @return the operation infos
*/
public static Map<String, Info> getOperationInfos(JvmDeclaredType type) {
return getOperationInfos(type, null);
}
/**
* Calculates the operation infos for the given info.
*
* @param root
* the root
* @return the operation infos
*/
public static Map<String, Info> getOperationInfos(Info root) {
JvmType type = null;
if (root.isMany()) {
type = root.getParameterizedType();
} else {
type = root.getType();
}
Map<String, Info> result = null;
if (type instanceof JvmDeclaredType) {
result = getOperationInfos((JvmDeclaredType) type);
} else {
result = new HashMap<String, JvmTypeProperties.Info>();
}
// apply the info as a parent
for (Info temp : result.values()) {
temp.setParent(root);
}
return result;
}
/**
* Calculates the operation infos for the given type.
*
* @param type
* the type
* @param filterName
* - is used to filter only methods property names matching the
* filter name.
* @return the operation infos
*/
public static Map<String, Info> getOperationInfos(JvmDeclaredType type,
String filterName) {
Map<String, Info> infos = new HashMap<String, Info>();
for (JvmFeature feature : type.getAllFeatures()) {
if (!(feature instanceof JvmOperation)) {
continue;
}
JvmOperation operation = (JvmOperation) feature;
if (operation.getVisibility() != JvmVisibility.PUBLIC) {
continue;
}
if (!isSetter(operation.getSimpleName())
&& operation.getParameters().size() > 1) {
continue;
}
String propertyName = toPropertyName(operation.getSimpleName());
if (propertyName == null) {
continue;
}
if (filterName != null && !filterName.equals(propertyName)) {
continue;
}
if (operation.getSimpleName().equals("getClass")) {
continue;
}
if (!isGetter(operation.getSimpleName())
&& !isSetter(operation.getSimpleName())) {
continue;
}
String id = calcId(operation.getDeclaringType(),
operation.getSimpleName());
if (!infos.containsKey(id)) {
Info info = new Info();
info.id = id;
info.name = propertyName;
infos.put(id, info);
}
Info info = infos.get(id);
if (isGetter(operation.getSimpleName())) {
info.getter = operation;
} else {
if (!propertyName.equals("dirty")) {
info.setter = operation;
}
}
}
// apply readonly and create descriptions
for (Info info : infos.values()) {
if (info.getter == null) {
continue;
}
if (info.setter == null) {
info.readonly = true;
}
// TODO Pirchner - remove this workaround
if (info.name.equals("id") || info.name.equals("uuid")) {
info.idProperty = true;
}
}
for (JvmFeature member : type.getAllFeatures()) {
if (member instanceof JvmField) {
JvmField field = (JvmField) member;
String id = calcFieldId(field.getDeclaringType(),
field.getSimpleName());
if (infos.containsKey(id)) {
Info info = infos.get(id);
info.setField(field);
info.type = field.getType().getType();
info.primitive = info.type instanceof JvmPrimitiveType
|| info.type.getQualifiedName().equals(
String.class.getName());
// collect all super types and check if collection is part
// of them
Set<String> superTypes = new RawSuperTypes()
.collectNames(info.type);
for (String typeName : superTypes) {
if (typeName.equals(Collection.class.getName())) {
info.many = true;
break;
}
}
if (info.many) {
JvmParameterizedTypeReference typeRef = (JvmParameterizedTypeReference) field
.getType();
if (!typeRef.getArguments().isEmpty()) {
info.parameterizedType = typeRef.getArguments()
.get(0).getType();
}
}
}
}
}
return infos;
}
/**
* Normalizes the name.
*
* @param declaringType
* the declaring type
* @param simpleName
* the simple name
* @return the string
*/
public static String calcId(JvmDeclaredType declaringType, String simpleName) {
String tempName = toPropertyName(simpleName);
if (tempName == null) {
return null;
}
return declaringType.getQualifiedName() + ":" + tempName;
}
/**
* Normalizes the name.
*
* @param declaringType
* the declaring type
* @param simpleName
* the simple name
* @return the string
*/
public static String calcFieldId(JvmDeclaredType declaringType,
String simpleName) {
return declaringType.getQualifiedName() + ":" + simpleName;
}
/**
* The Class Info.
*/
public static class Info implements Comparable<Info> {
/**
* Can by any object that requested the info. For instance a YBeanSlot,
* an Entity, a JvmField,... The root should only be set for the top
* most parent.
*/
private Object root;
/**
* The parent which requested this instance of info.
*/
private Info parent;
/** The id. */
private String id;
/** The name. */
private String name;
/** The readonly. */
private boolean readonly;
/** The primitive. */
private boolean primitive;
/** The getter. */
private JvmOperation getter;
/** The setter. */
private JvmOperation setter;
/** The field. */
private JvmField field;
/** The type. */
private JvmType type;
/** The parameterized type. */
private JvmType parameterizedType;
/** The many. */
private boolean many;
/** The id property. */
private boolean idProperty;
/** The children. */
private List<Info> children = new ArrayList<>();
/**
* Gets the parent which requested this instance of info.
*
* @return the parent which requested this instance of info
*/
public Info getParent() {
return parent;
}
/**
* Gets the children.
*
* @return the children
*/
public List<Info> getChildren() {
return children;
}
/**
* Adds the child info.
*
* @param temp
* the temp
*/
public void addChildInfo(Info temp) {
children.add(temp);
}
/**
* Sets the parent which requested this instance of info.
*
* @param parent
* the new parent which requested this instance of info
*/
public void setParent(Info parent) {
this.parent = parent;
parent.addChildInfo(this);
}
/**
* Gets the top parent.
*
* @return the top parent
*/
public Info getTopParent() {
if (getParent() != null) {
return getParent().getTopParent();
}
return this;
}
/**
* Gets the can by any object that requested the info.
*
* @return the can by any object that requested the info
*/
public Object getRoot() {
if (this.root == null && getParent() != null) {
return getParent().getRoot();
}
return root;
}
/**
* Sets the can by any object that requested the info.
*
* @param root
* the new can by any object that requested the info
*/
public void setRoot(Object root) {
this.root = root;
}
/**
* Gets the id.
*
* @return the id
*/
public String getId() {
return id;
}
/**
* Sets the id.
*
* @param id
* the new id
*/
public void setId(String id) {
this.id = id;
}
/**
* Gets the name.
*
* @return the name
*/
public String getName() {
return name;
}
/**
* Sets the name.
*
* @param name
* the new name
*/
public void setName(String name) {
this.name = name;
}
/**
* Checks if is readonly.
*
* @return true, if is readonly
*/
public boolean isReadonly() {
return readonly;
}
/**
* Sets the readonly.
*
* @param readonly
* the new readonly
*/
public void setReadonly(boolean readonly) {
this.readonly = readonly;
}
/**
* Gets the getter.
*
* @return the getter
*/
public JvmOperation getGetter() {
return getter;
}
/**
* Sets the getter.
*
* @param getter
* the new getter
*/
public void setGetter(JvmOperation getter) {
this.getter = getter;
}
/**
* Gets the setter.
*
* @return the setter
*/
public JvmOperation getSetter() {
return setter;
}
/**
* Sets the setter.
*
* @param setter
* the new setter
*/
public void setSetter(JvmOperation setter) {
this.setter = setter;
}
/**
* Gets the field.
*
* @return the field
*/
public JvmField getField() {
return field;
}
/**
* The jvm type containing the field.
*
* @return the declaring type
*/
public JvmDeclaredType getDeclaringType() {
return field.getDeclaringType();
}
/**
* Sets the field.
*
* @param field
* the new field
*/
public void setField(JvmField field) {
this.field = field;
}
/**
* Checks if is primitive.
*
* @return true, if is primitive
*/
public boolean isPrimitive() {
return primitive;
}
/**
* Sets the primitive.
*
* @param primitive
* the new primitive
*/
public void setPrimitive(boolean primitive) {
this.primitive = primitive;
}
/**
* Gets the type.
*
* @return the type
*/
public JvmType getType() {
return type;
}
/**
* Sets the type.
*
* @param type
* the new type
*/
public void setType(JvmType type) {
this.type = type;
}
/**
* Checks if is many.
*
* @return true, if is many
*/
public boolean isMany() {
return many;
}
/**
* Checks if is id property.
*
* @return true, if is id property
*/
public boolean isIdProperty() {
return idProperty;
}
/**
* Sets the many.
*
* @param many
* the new many
*/
public void setMany(boolean many) {
this.many = many;
}
/**
* Gets the parameterized type.
*
* @return the parameterized type
*/
public JvmType getParameterizedType() {
return parameterizedType;
}
/**
* Sets the parameterized type.
*
* @param parameterizedType
* the new parameterized type
*/
public void setParameterizedType(JvmType parameterizedType) {
this.parameterizedType = parameterizedType;
}
/**
* Returns true, if the info has an annotation matching the given
* annotationType.
*
* @param annotationType
* the annotation type
* @return true, if successful
*/
public boolean hasAnnotation(Class<?> annotationType) {
if (field == null) {
return false;
}
for (JvmAnnotationReference annotation : field.getAnnotations()) {
if (annotation.getAnnotation().getQualifiedName()
.equals(annotationType.getName())) {
return true;
}
}
return false;
}
/**
* Returns the JvmAnnotationType instance or null.
*
* @param annotationType
* the annotation type
* @return true, if successful
*/
public JvmAnnotationType getAnnotation(Class<?> annotationType) {
if (!hasAnnotation(annotationType)) {
return null;
}
for (JvmAnnotationReference annotation : field.getAnnotations()) {
if (annotation.getAnnotation().getQualifiedName()
.equals(annotationType.getName())) {
return annotation.getAnnotation();
}
}
return null;
}
/**
* Returns the dot'ed attribute path for this info and its parents. For
* instance <code>person.address.name</code>.
*
* @return the attribute path
*/
public String getAttributePath() {
return getAttributePath(parent, name);
}
/**
* Gets the attribute path.
*
* @param parent
* the parent
* @param postFix
* the post fix
* @return the attribute path
*/
protected String getAttributePath(Info parent, String postFix) {
if (parent != null) {
String temp = parent.getAttributePath();
return temp + "." + postFix;
} else {
return postFix;
}
}
/*
* (non-Javadoc)
*
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
@Override
public int compareTo(Info other) {
if (name == null || other == null) {
return -1;
}
return name.compareTo(other.getName());
}
}
}