| /* |
| * |
| * 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()); |
| } |
| } |
| } |