/******************************************************************************* * Copyright (c) 2015, 2016 Pivotal, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Pivotal, Inc. - initial API and implementation *******************************************************************************/ package org.springframework.ide.eclipse.boot.properties.editor.completions; import static org.eclipse.jdt.internal.ui.text.javadoc.JavadocContentAccess2.getHTMLContent; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import org.eclipse.jdt.core.IField; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IMember; import org.springframework.boot.configurationmetadata.Deprecation; import org.springframework.ide.eclipse.boot.core.BootActivator; import org.springframework.ide.eclipse.boot.properties.editor.util.Type; import org.springframework.ide.eclipse.boot.properties.editor.util.TypeUtil; import org.springframework.ide.eclipse.boot.properties.editor.util.TypeUtil.BeanPropertyNameMode; import org.springframework.ide.eclipse.boot.properties.editor.util.TypeUtil.EnumCaseMode; import org.springframework.ide.eclipse.boot.properties.editor.util.TypedProperty; import org.springframework.ide.eclipse.editor.support.util.HtmlSnippet; import com.google.common.collect.ImmutableList; /** * Example used as reference for explaingin the meaning of the instance variables: * * foo.bar[0].children.wavelen */ @SuppressWarnings("restriction") public class JavaTypeNavigationHoverInfo extends AbstractPropertyHoverInfo { /** * Property expression that represents the full path to the point being hovered over. * E.g. foo.bar[0].data.wavelen" */ private final String id; /** * Last sgment of the path as a property name. * This is only set if the naviation is accessing a property name (so, for example, will be null for navigation into * indexed element in a sequence/list) * <p> * Example: "wavelen" */ private final String propName; /** * The type from which we are navigating. * E.g. the type of "foo.bar[0].data" */ private Type parentType; /** * The type at which we arrive. * E.g the type of "foo.bar[0].data.wavelen" */ private Type type; private TypeUtil typeUtil; private Deprecation deprecation; public JavaTypeNavigationHoverInfo(String id, String propName, Type fromType, Type toType, TypeUtil typeUtil) { this.id = id; this.propName = propName; this.parentType = fromType; this.type = toType; this.typeUtil = typeUtil; //Note: If you are considerind caching the result of this method... don't. //The rendered html itself is cached by the superclass, which means this method only gets called once. Map<String, TypedProperty> props = typeUtil.getPropertiesMap(parentType, EnumCaseMode.ALIASED, BeanPropertyNameMode.ALIASED); if (props!=null) { TypedProperty prop = props.get(propName); if (prop!=null) { this.deprecation = prop.getDeprecation(); } } } // @Override // protected String renderAsHtml() { // JavaTypeLinks jtLinks = new JavaTypeLinks(this); // HtmlBuffer html = new HtmlBuffer(); // // html.raw("<b>"); // html.text(id); // html.raw("</b>"); // html.raw("<br>"); // // if (type!=null) { // jtLinks.javaTypeLink(html, typeUtil, type); // } else { // jtLinks.javaTypeLink(html, typeUtil.getJavaProject(), Object.class.toString()); // } // // if (isDeprecated()) { // html.raw("<br><br>"); // html.bold("Deprecated!"); // } // // // String deflt = formatDefaultValue(data.getDefaultValue()); // // if (deflt!=null) { // // html.raw("<br><br>"); // // html.text("Default: "); // // html.raw("<i>"); // // html.text(deflt); // // html.raw("</i>"); // // } // // String description = getDescription(); // if (description!=null) { // html.raw("<br><br>"); // html.raw(description); // } // // return html.toString(); // } @Override protected boolean isDeprecated() { return deprecation!=null; } @Override protected HtmlSnippet getDescription() { try { List<IJavaElement> jes = getAllJavaElements(); if (jes!=null) { for (IJavaElement je : jes) { if (je instanceof IMember) { String jdoc = getHTMLContent((IMember)je, true); if (jdoc!=null) { return HtmlSnippet.raw(jdoc); } } } } } catch (Exception e) { BootActivator.log(e); } return null; } @Override public List<IJavaElement> getJavaElements() { if (propName!=null) { if (TypeUtil.isMap(parentType)) { Type enumType = typeUtil.getKeyType(parentType); if (typeUtil.isEnum(enumType)) { IField f = typeUtil.getEnumConstant(enumType, propName); if (f!=null) { return ImmutableList.of(f); } } } else { IJavaElement je; Type beanType = parentType; je = typeUtil.getSetter(beanType, propName); if (je!=null) { return Collections.singletonList(je); } je = typeUtil.getGetter(beanType, propName); if (je!=null) { return Collections.singletonList(je); } je = typeUtil.getField(beanType, propName); if (je!=null) { return Collections.singletonList(je); } } } return Collections.emptyList(); } private List<IJavaElement> getAllJavaElements() { if (propName!=null) { Type beanType = parentType; if (TypeUtil.isMap(beanType)) { Type keyType = typeUtil.getKeyType(beanType); if (keyType!=null && typeUtil.isEnum(keyType)) { IField field = typeUtil.getEnumConstant(keyType, propName); if (field!=null) { return ImmutableList.of(field); } } } else { ArrayList<IJavaElement> elements = new ArrayList<IJavaElement>(3); maybeAdd(elements, typeUtil.getField(beanType, propName)); maybeAdd(elements, typeUtil.getSetter(beanType, propName)); maybeAdd(elements, typeUtil.getGetter(beanType, propName)); if (!elements.isEmpty()) { return elements; } } } return ImmutableList.of(); } private void maybeAdd(ArrayList<IJavaElement> elements, IJavaElement e) { if (e!=null) { elements.add(e); } } @Override protected Object getDefaultValue() { //Not supported return null; } @Override protected IJavaProject getJavaProject() { return typeUtil.getJavaProject(); } @Override protected String getType() { return typeUtil.niceTypeName(type); } @Override protected String getDeprecationReason() { if (deprecation!=null) { return deprecation.getReason(); } return null; } @Override protected String getId() { return id; } @Override protected String getDeprecationReplacement() { if (deprecation!=null) { return deprecation.getReplacement(); } return null; } }