001/* 002 * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. Oracle designates this 008 * particular file as subject to the "Classpath" exception as provided 009 * by Oracle in the LICENSE file that accompanied this code. 010 * 011 * This code is distributed in the hope that it will be useful, but WITHOUT 012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 014 * version 2 for more details (a copy is included in the LICENSE file that 015 * accompanied this code). 016 * 017 * You should have received a copy of the GNU General Public License version 018 * 2 along with this work; if not, write to the Free Software Foundation, 019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 020 * 021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 022 * or visit www.oracle.com if you need additional information or have any 023 * questions. 024 */ 025 026package org.jdrupes.mdoclet.internal.doclets.toolkit; 027 028import java.util.regex.Pattern; 029import javax.lang.model.element.ExecutableElement; 030import javax.lang.model.type.TypeKind; 031import javax.lang.model.type.TypeMirror; 032import javax.lang.model.util.Types; 033 034/** 035 * This class provides basic JavaFX property related utility methods. 036 * Refer to the JavaFX conventions in the VisibleMemberTable comments. 037 */ 038public class PropertyUtils { 039 040 final TypeMirror jbObservableType; 041 042 final Pattern fxMethodPatterns; 043 044 final boolean javafx; 045 046 final Types typeUtils; 047 048 PropertyUtils(BaseConfiguration configuration) { 049 BaseOptions options = configuration.getOptions(); 050 javafx = options.javafx(); 051 052 typeUtils = configuration.docEnv.getTypeUtils(); 053 054 // Disable strict check for JDK's without FX. 055 TypeMirror jboType = options.disableJavaFxStrictChecks() 056 ? null 057 : configuration.utils.getSymbol("javafx.beans.Observable"); 058 059 jbObservableType = jboType != null 060 ? configuration.docEnv.getTypeUtils().erasure(jboType) 061 : null; 062 063 fxMethodPatterns = javafx 064 ? Pattern.compile("[sg]et\\p{Upper}.*||is\\p{Upper}.*") 065 : null; 066 } 067 068 /** 069 * Returns a base name for a property method. Supposing we 070 * have {@code BooleanProperty acmeProperty()}, then "acme" 071 * will be returned. 072 * @param propertyMethod 073 * @return the base name of a property method. 074 */ 075 public String getBaseName(ExecutableElement propertyMethod) { 076 String name = propertyMethod.getSimpleName().toString(); 077 String baseName = name.substring(0, name.indexOf("Property")); 078 return baseName; 079 } 080 081 /** 082 * Returns a property getter's name. Supposing we have a property 083 * method {@code DoubleProperty acmeProperty()}, then "getAcme" 084 * will be returned. 085 * @param propertyMethod 086 * @return the property getter's name. 087 */ 088 public String getGetName(ExecutableElement propertyMethod) { 089 String baseName = getBaseName(propertyMethod); 090 String fnUppercased = "" + 091 Character.toUpperCase(baseName.charAt(0)) + baseName.substring(1); 092 return "get" + fnUppercased; 093 } 094 095 /** 096 * Returns an "is" method's name for a property method. Supposing 097 * we have a property method {@code BooleanProperty acmeProperty()}, 098 * then "isAcme" will be returned. 099 * @param propertyMethod 100 * @return the property is getter's name. 101 */ 102 public String getIsName(ExecutableElement propertyMethod) { 103 String baseName = getBaseName(propertyMethod); 104 String fnUppercased = "" + 105 Character.toUpperCase(baseName.charAt(0)) + baseName.substring(1); 106 return "is" + fnUppercased; 107 } 108 109 /** 110 * Returns true if a property method could have an "is" method, meaning 111 * {@code isAcme} could exist for a property method. 112 * @param propertyMethod 113 * @return true if the property could have an "is" method, false otherwise. 114 */ 115 public boolean hasIsMethod(ExecutableElement propertyMethod) { 116 String propertyTypeName = propertyMethod.getReturnType().toString(); 117 return "boolean".equals(propertyTypeName) || 118 propertyTypeName.endsWith("BooleanProperty"); 119 } 120 121 /** 122 * Returns a property setter's name. Supposing we have a property 123 * method {@code DoubleProperty acmeProperty()}, then "setAcme" 124 * will be returned. 125 * @param propertyMethod 126 * @return the property setter's method name. 127 */ 128 public String getSetName(ExecutableElement propertyMethod) { 129 String baseName = getBaseName(propertyMethod); 130 String fnUppercased = "" + 131 Character.toUpperCase(baseName.charAt(0)) + baseName.substring(1); 132 return "set" + fnUppercased; 133 } 134 135 /** 136 * Returns true if the given setter method is a valid property setter 137 * method. 138 * @param setterMethod 139 * @return true if setter method, false otherwise. 140 */ 141 public boolean isValidSetterMethod(ExecutableElement setterMethod) { 142 return setterMethod.getReturnType().getKind() == TypeKind.VOID; 143 } 144 145 /** 146 * Returns true if the method is a property method. 147 * @param propertyMethod 148 * @return true if the method is a property method, false otherwise. 149 */ 150 public boolean isPropertyMethod(ExecutableElement propertyMethod) { 151 if (!javafx || 152 !propertyMethod.getParameters().isEmpty() || 153 !propertyMethod.getTypeParameters().isEmpty()) { 154 return false; 155 } 156 String methodName = propertyMethod.getSimpleName().toString(); 157 if (!methodName.endsWith("Property") || 158 fxMethodPatterns.matcher(methodName).matches()) { 159 return false; 160 } 161 162 TypeMirror returnType = propertyMethod.getReturnType(); 163 if (jbObservableType == null) { 164 // JavaFX references missing, make a lazy backward compatible check. 165 return returnType.getKind() != TypeKind.VOID; 166 } else { 167 // Apply strict checks since JavaFX references are available 168 returnType = typeUtils.erasure(propertyMethod.getReturnType()); 169 return typeUtils.isAssignable(returnType, jbObservableType); 170 } 171 } 172}