| /** |
| * |
| * 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: |
| * Christophe Loetz (Loetz GmbH&Co.KG) - initial implementation |
| */ |
| |
| package org.eclipse.osbp.autowirehelper; |
| |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.emf.ecore.resource.ResourceSet; |
| import org.eclipse.emf.ecore.util.EcoreUtil; |
| import org.eclipse.osbp.autowirehelper.AutowireHelper.LocalResourceAccess; |
| import org.eclipse.osbp.runtime.common.annotations.Filter; |
| import org.eclipse.osbp.runtime.common.annotations.Range; |
| import org.eclipse.osbp.runtime.common.annotations.UniqueEntry; |
| import org.eclipse.xtext.common.types.JvmAnnotationReference; |
| 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.TypesPackage; |
| import org.eclipse.xtext.common.types.util.RawSuperTypes; |
| import org.eclipse.xtext.resource.IReferenceDescription; |
| import org.eclipse.xtext.ui.editor.findrefs.IReferenceFinder; |
| import org.eclipse.xtext.util.IAcceptor; |
| import org.eclipse.xtext.xbase.lib.StringExtensions; |
| |
| import com.google.inject.Inject; |
| |
| /** |
| * Helper class to collect all properties for a given JvmType. |
| */ |
| @SuppressWarnings("restriction") |
| public class JvmTypeProperties { |
| |
| @Inject |
| private IReferenceFinder referenceFinder; |
| |
| /** |
| * Normalizes the method name. |
| * |
| * @param simpleName |
| * @return |
| */ |
| 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; |
| } |
| |
| public static boolean isGetter(String simpleName) { |
| if (simpleName == null) { |
| return false; |
| } |
| return simpleName.startsWith("get") || simpleName.startsWith("is"); |
| } |
| |
| public static boolean isSetter(String simpleName) { |
| return simpleName != null && simpleName.startsWith("set"); |
| } |
| |
| /** |
| * Calculates the operation infos for the given type. |
| * |
| * @param type |
| * @return |
| */ |
| public static Map<String, Info> getOperationInfos(JvmDeclaredType type) { |
| return getOperationInfos(type, null); |
| } |
| |
| /** |
| * Calculates the operation infos for the given info. |
| * |
| * @param info |
| * @return |
| */ |
| public static Map<String, Info> getOperationInfos(Info info) { |
| |
| JvmType type = null; |
| if (info.isMany()) { |
| type = info.getParameterizedType(); |
| } else { |
| type = info.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(info); |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Calculates the operation infos for the given type. |
| * |
| * @param type |
| * @param filterName |
| * - is used to filter only methods property names matching the |
| * filter name. |
| * @return |
| */ |
| 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; |
| } |
| } |
| |
| 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 |
| * @param simpleName |
| * @return |
| */ |
| 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 |
| * @param simpleName |
| * @return |
| */ |
| public static String calcFieldId(JvmDeclaredType declaringType, |
| String simpleName) { |
| return declaringType.getQualifiedName() + ":" + simpleName; |
| } |
| |
| /** |
| * Finds all sub types of the given dtoType. |
| */ |
| public Set<URI> findSubTypes(JvmType dtoType, ResourceSet rs) { |
| Set<URI> result = new HashSet<>(); |
| Set<URI> jvmTypeURIs = new HashSet<>(); |
| jvmTypeURIs.add(EcoreUtil.getURI(dtoType)); |
| IAcceptor<IReferenceDescription> acceptor = e -> { |
| if (e.getEReference() == TypesPackage.Literals.JVM_PARAMETERIZED_TYPE_REFERENCE__TYPE) { |
| if (e.getSourceEObjectUri().fragment() |
| .endsWith("/@superTypes.0")) { |
| URI uri = e.getSourceEObjectUri(); |
| result.add(URI.createURI(uri.toString().replace( |
| "/@superTypes.0", ""))); |
| } |
| } |
| }; |
| referenceFinder.findAllReferences(jvmTypeURIs, new LocalResourceAccess( |
| rs), acceptor, null); |
| return result; |
| } |
| |
| 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; |
| private String id; |
| private String name; |
| private boolean readonly; |
| private boolean primitive; |
| private JvmOperation getter; |
| private JvmOperation setter; |
| private JvmField field; |
| private JvmType type; |
| private JvmType parameterizedType; |
| private boolean many; |
| |
| public Info getParent() { |
| return parent; |
| } |
| |
| public void setParent(Info parent) { |
| this.parent = parent; |
| } |
| |
| public Info getTopParent() { |
| if (getParent() != null) { |
| return getParent().getTopParent(); |
| } |
| return this; |
| } |
| |
| public Object getRoot() { |
| if (this.root == null && getParent() != null) { |
| return getParent().getRoot(); |
| } |
| return root; |
| } |
| |
| public void setRoot(Object root) { |
| this.root = root; |
| } |
| |
| public String getId() { |
| return id; |
| } |
| |
| public void setId(String id) { |
| this.id = id; |
| } |
| |
| public String getName() { |
| return name; |
| } |
| |
| public void setName(String name) { |
| this.name = name; |
| } |
| |
| public boolean isReadonly() { |
| return readonly; |
| } |
| |
| public void setReadonly(boolean readonly) { |
| this.readonly = readonly; |
| } |
| |
| public JvmOperation getGetter() { |
| return getter; |
| } |
| |
| public void setGetter(JvmOperation getter) { |
| this.getter = getter; |
| } |
| |
| public JvmOperation getSetter() { |
| return setter; |
| } |
| |
| public void setSetter(JvmOperation setter) { |
| this.setter = setter; |
| } |
| |
| public JvmField getField() { |
| return field; |
| } |
| |
| public void setField(JvmField field) { |
| this.field = field; |
| } |
| |
| public boolean isPrimitive() { |
| return primitive; |
| } |
| |
| public void setPrimitive(boolean primitive) { |
| this.primitive = primitive; |
| } |
| |
| public JvmType getType() { |
| return type; |
| } |
| |
| public void setType(JvmType type) { |
| this.type = type; |
| } |
| |
| public boolean isMany() { |
| return many; |
| } |
| |
| public void setMany(boolean many) { |
| this.many = many; |
| } |
| |
| public JvmType getParameterizedType() { |
| return parameterizedType; |
| } |
| |
| public void setParameterizedType(JvmType parameterizedType) { |
| this.parameterizedType = parameterizedType; |
| } |
| |
| /** |
| * Returns true, if the info has an annotation matching the given |
| * annotationType. |
| * |
| * @param annotationType |
| * @return |
| */ |
| 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 dot'ed attribute path for this info and its parents. For |
| * instance <code>person.address.name</code>. |
| * |
| * @return |
| */ |
| public String getAttributePath() { |
| return getAttributePath(parent, name); |
| } |
| |
| protected String getAttributePath(Info parent, String postFix) { |
| if (parent != null) { |
| String temp = parent.getAttributePath(); |
| return temp + "." + postFix; |
| } else { |
| return postFix; |
| } |
| } |
| |
| public boolean isRange() { |
| return hasAnnotation(Range.class); |
| } |
| |
| public boolean isFilter() { |
| return hasAnnotation(Filter.class); |
| } |
| |
| public boolean isUniqueEntry() { |
| return hasAnnotation(UniqueEntry.class); |
| } |
| |
| @Override |
| public int compareTo(Info other) { |
| if (name == null || other == null) { |
| return -1; |
| } |
| return name.compareTo(other.getName()); |
| } |
| |
| } |
| } |