![JAR search and dependency download from the Maven repository](/logo.png)
com.viaoa.util.OAPropertyPath Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of oa-core Show documentation
Show all versions of oa-core Show documentation
Object Automation library
The newest version!
/* Copyright 1999 Vince Via [email protected]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package com.viaoa.util;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import com.viaoa.annotation.OACalculatedProperty;
import com.viaoa.annotation.OAClass;
import com.viaoa.annotation.OAOne;
import com.viaoa.annotation.OAProperty;
import com.viaoa.hub.CustomHubFilter;
import com.viaoa.hub.Hub;
import com.viaoa.hub.HubMerger;
import com.viaoa.object.OACalcInfo;
import com.viaoa.object.OALinkInfo;
import com.viaoa.object.OAObject;
import com.viaoa.object.OAObjectInfo;
import com.viaoa.object.OAObjectInfoDelegate;
import com.viaoa.object.OAPropertyInfo;
/**
* Utility used to parse a propertyPath, get methods, class information, and to be able to get the value by invoking on an object. A
* PropertyPath String is separated by "." for each linkPropery, and each linkProperty can have a filter in the format ":filterName(a,b,n)"
* Supports casting in property path, ex: from Emp, "dept.(manager)employee.name" ex: from OALeftJoin "(Location)A.name" Supports filters:
* ex: "dept.employees:newHires(7).orders.orderItems:overDue(30)" Recursive: created 20120809
*
* @param type of object that the property path is based on.
* @see HubMerger which uses propertyPaths to create a Hub of all lastNode objects, and keeps it updated.
* @see OAPropertyPathDelegate
*/
public class OAPropertyPath {
private Class fromClass;
private String propertyPath;
private Method[] methods = new Method[0];
private boolean bLastMethodHasHubParam; // true if method requires a Hub param
/**
* property class. if casting is used, then this will have the casted class. note: if the method returns a Hub, then this will be the
* hub.objectClass
*/
private Class[] classes = new Class[0];
// flag that is used when data is needed to find the real classes, since generics are being used.
private boolean bNeedsDataToVerify;
private String[] properties = new String[0]; // convert properties, without casting
private String[] castNames = new String[0];
private String[] filterNames = new String[0];
private String[] filterParams = new String[0];
private Object[][] filterParamValues = new Object[0][];
private Class[] filterClasses = new Class[0];
private Constructor[] filterConstructors = new Constructor[0];
/** NOTE: this also includes endLinkInfo */
private OALinkInfo[] linkInfos = new OALinkInfo[0];
private OALinkInfo[] recursiveLinkInfos = new OALinkInfo[0]; // for each linkInfos[]
private OAPropertyPath revPropertyPath;
// the ending propery in the property path will be one of these
private OAPropertyInfo endPropertyInfo;
private OACalcInfo endCalcInfo;
private OALinkInfo endLinkInfo; // note: will also be in linkInfos
public OAPropertyPath(String propertyPath) {
this.propertyPath = propertyPath;
}
public OAPropertyPath(Class fromClass, String propertyPath) {
this(fromClass, propertyPath, false);
}
public OAPropertyPath(Class fromClass, String propertyPath, boolean bIgnoreError) {
this.propertyPath = propertyPath;
this.fromClass = fromClass;
try {
setup(fromClass, bIgnoreError);
} catch (Exception e) {
try {
// setup(fromClass); // for debugging only
} catch (Exception e2) {
// TODO: handle exception
}
if (!bIgnoreError) {
throw new IllegalArgumentException("cant setup, fromClass=" + fromClass + ", propertyPath=" + propertyPath, e);
}
}
}
public String getPropertyPath() {
return this.propertyPath;
}
public OAPropertyPath getReversePropertyPath() {
return getReversePropertyPath(false);
}
public OAPropertyPath getReversePropertyPath(final boolean bAllowPrivateLinks) {
if (revPropertyPath != null) {
return revPropertyPath;
}
if (linkInfos == null || linkInfos.length == 0) {
return null;
}
Class c = null;
String pp = "";
for (int i = 0; i < linkInfos.length; i++) {
OALinkInfo li = linkInfos[i];
OALinkInfo liRev = OAObjectInfoDelegate.getReverseLinkInfo(li);
if (!bAllowPrivateLinks && liRev.getPrivateMethod()) {
return null;
}
if (pp.length() > 0) {
pp = "." + pp;
}
pp = liRev.getName() + pp;
}
c = linkInfos[linkInfos.length - 1].getToClass();
revPropertyPath = new OAPropertyPath(c, pp, bAllowPrivateLinks);
return revPropertyPath;
}
public String getPropertyPathLinksOnly() {
if (linkInfos == null || linkInfos.length == 0) {
return null;
}
String s = "";
for (int i = 0; i < linkInfos.length; i++) {
OALinkInfo li = linkInfos[i];
// 20190307 added cast name
String s2 = "";
if (castNames != null && i < castNames.length) {
if (OAString.isNotEmpty(castNames[i])) {
s2 = "(" + castNames[i] + ")";
}
}
s = OAString.concat(s, s2 + li.getName(), ".");
// 20190307 added filter name
if (filterNames != null && i < filterNames.length) {
if (OAString.isNotEmpty(filterNames[i])) {
s += ":" + filterNames[i];
if (filterParams != null && i < filterParams.length && OAString.isNotEmpty(filterParams[i])) {
s += "(" + filterParams[i] + ")";
}
}
}
}
return s;
}
public OAPropertyInfo getEndPropertyInfo() {
return endPropertyInfo;
}
public OACalcInfo getEndCalcInfo() {
return endCalcInfo;
}
public OALinkInfo getEndLinkInfo() {
return endLinkInfo;
}
public OAProperty getOAPropertyAnnotation() {
if (methods == null || methods.length == 0) {
return null;
}
return methods[methods.length - 1].getAnnotation(OAProperty.class);
}
public OACalculatedProperty getOACalculatedPropertyAnnotation() {
if (methods == null || methods.length == 0) {
return null;
}
return methods[methods.length - 1].getAnnotation(OACalculatedProperty.class);
}
public OAOne getOAOneAnnotation() {
if (methods == null || methods.length == 0) {
return null;
}
return methods[methods.length - 1].getAnnotation(OAOne.class);
}
public String[] getProperties() {
return properties;
}
public String[] getCastNames() {
return castNames;
}
// ex: Employees:recentBirthday() => "recentBirthday()"
public String[] getFilterNames() {
return filterNames;
}
// params used for filter, ex: "(a,b)", "()"
public String[] getFilterParams() {
return filterParams;
}
public Object[][] getFilterParamValues() {
return filterParamValues;
}
public Method[] getMethods() {
return methods;
}
public Class[] getClasses() {
return classes;
}
public Constructor[] getFilterConstructors() {
return filterConstructors;
}
public OALinkInfo[] getLinkInfos() {
return linkInfos;
}
public boolean hasLinks() {
return linkInfos != null && linkInfos.length > 0;
}
public OALinkInfo[] getRecursiveLinkInfos() {
return recursiveLinkInfos;
}
public Object getValue(F fromObject) {
return getValue(null, fromObject);
}
public String getValueAsString(F fromObject) {
return getValueAsString(null, fromObject);
}
public Object getLastLinkValue(F fromObject) {
return getValue(null, fromObject, true);
}
public String getLastPropertyName() {
String[] ss = getProperties();
if (ss == null || ss.length == 0) {
return null;
}
return ss[ss.length - 1];
}
public String getFirstPropertyName() {
String[] ss = getProperties();
if (ss == null || ss.length == 0) {
return null;
}
return ss[0];
}
/**
* Returns the value of the propertyPath from a base object. Notes: if any of the property's is null, then null is returned. If any of
* the non-last properties is a Hub, then the AO will be used.
*/
public Object getValue(Hub hub, F fromObject) {
return getValue(hub, fromObject, false);
}
public Object getValue(Hub hub, F fromObject, boolean bLinksOnly) {
if (fromObject == null) {
return null;
}
if (this.fromClass == null) {
setup((Class) fromObject.getClass());
}
if (methods == null || methods.length == 0) {
return fromObject; // ex: could be pp="."
}
Object result = fromObject;
for (int i = 0; i < methods.length; i++) {
if (bLinksOnly && (linkInfos == null || i >= linkInfos.length)) {
break;
}
if (bLastMethodHasHubParam && i + 1 == methods.length) {
try {
result = methods[i].invoke(result, hub);
} catch (Exception e) {
throw new RuntimeException("error invoking method=" + methods[i], e);
}
} else {
try {
result = methods[i].invoke(result);
} catch (Exception e) {
throw new RuntimeException("error invoking method=" + methods[i], e);
}
}
if (result == null) {
break;
}
if (i + 1 < methods.length && result instanceof Hub) {
result = ((Hub) result).getAO();
if (result == null) {
break;
}
}
}
return result;
}
/**
* This will call getValue, and then call OAConv.toString using getFormat.
*/
public String getValueAsString(Hub hub, F fromObject) {
Object obj = getValue(hub, fromObject);
String s = OAConv.toString(obj, getFormat());
return s;
}
public String getValueAsString(Hub hub, F fromObject, String format) {
Object obj = getValue(hub, fromObject);
String s = OAConv.toString(obj, format);
return s;
}
public Class getFromClass() {
return fromClass;
}
public void setup(Hub hub) {
if (hub == null) {
return;
}
setup(hub, hub.getObjectClass(), false);
}
public void setup(Class clazz) {
setup(clazz, false);
}
public void setup(Class clazz, boolean bIgnorePrivateLink) {
String s = setup(null, clazz, bIgnorePrivateLink);
if (s != null) {
throw new RuntimeException(s);
}
}
public boolean hasPrivateLink() {
if (linkInfos == null) {
return false;
}
for (OALinkInfo li : linkInfos) {
if (li.getPrivateMethod()) {
return true;
}
}
return false;
}
public boolean getDoesLastMethodHasHubParam() {
return bLastMethodHasHubParam;
}
public boolean getNeedsDataToVerify() {
return bNeedsDataToVerify;
}
public String setup(final Hub hub, Class clazz, final boolean bIgnorePrivateLink) {
return setup(hub, clazz, null, bIgnorePrivateLink);
}
/**
* @param substituteClass class to use if a link property is of type OAObject.class
* @param bIgnorePrivateLink if true, then a link that does not have a get method will not throw an exception. Used by HubGroupBy
*/
public String setup(final Hub hub, Class clazz, final Class substituteClass, final boolean bIgnorePrivateLink) {
bNeedsDataToVerify = false;
if (clazz == null) {
bNeedsDataToVerify = true;
return "Hub.objectClass not set";
}
this.fromClass = clazz;
String propertyPath = this.propertyPath;
if (propertyPath == null) {
propertyPath = "";
} else {
propertyPath = propertyPath.trim();
}
// 20140118 if leading with "[ClassName].", then it is the fromClass
int pos = propertyPath.indexOf("[");
if (pos >= 0) {
int pos2 = propertyPath.indexOf("].");
if (pos2 > 0) {
String fromClassName = propertyPath.substring(pos + 1, pos2);
propertyPath = propertyPath.substring(pos2 + 2);
if (fromClassName.indexOf('.') >= 0) {
Class c;
try {
c = Class.forName(fromClassName);
} catch (Exception e) {
throw new RuntimeException("error getting class=" + fromClassName, e);
}
this.fromClass = c;
} else {
String packageName = fromClass.getName();
pos = packageName.lastIndexOf('.');
if (pos > 0) {
packageName = packageName.substring(0, pos + 1);
} else {
packageName = "";
}
Class c;
try {
c = Class.forName(packageName + fromClassName);
} catch (Exception e) {
throw new RuntimeException("error getting class=" + packageName + fromClassName, e);
}
this.fromClass = c;
}
}
}
clazz = this.fromClass;
String propertyPathClean = propertyPath;
// a String that uses quotes "" could have special chars ',:()' inside of "" it
//qqq todo: this wont protect against \" - need to create a tokenizer
for (int i = 0;; i++) {
int p = propertyPathClean.indexOf('\"');
if (p < 0) {
break;
}
int p2 = propertyPathClean.indexOf('\"', p + 1);
if (p2 < 0) {
break;
}
int x = (p2 - p) - 1;
String s = OAString.getRandomString(x, x, false, true, false);
propertyPathClean = propertyPath.substring(0, p) + "\"" + s + "\"" + propertyPath.substring(p2 + 1);
}
Class classLast = clazz;
int posDot, prevPosDot;
posDot = prevPosDot = 0;
if (OAString.isEmpty(propertyPathClean)) {
posDot = -1;
}
int cnter = 0;
for (; posDot >= 0; prevPosDot = posDot + 1) {
cnter++;
if (cnter > 20) {
throw new RuntimeException("cant parse propertyPath=" + propertyPath + ", class=" + clazz);
}
if (prevPosDot >= propertyPathClean.length()) {
break;
}
posDot = propertyPathClean.indexOf('.', prevPosDot);
if (posDot == 0) {
continue;
}
int posCast = propertyPathClean.indexOf('(', prevPosDot);
int posFilter = propertyPathClean.indexOf(':', prevPosDot);
if (posCast >= 0) {
if (posFilter > 0 && posCast > posFilter) {
posCast = -1;
} else if (posDot >= 0) {
if (posCast > posDot) {
posCast = -1;
} else {
// cast could have package name, with '.' in it
posDot = propertyPathClean.indexOf(')', posCast + 1);
posDot = propertyPathClean.indexOf('.', posDot);
}
}
}
if (posDot >= 0 && posFilter > posDot) {
posFilter = -1;
}
String propertyName;
String propertyNameClean;
if (posDot >= 0) {
propertyName = propertyPath.substring(prevPosDot, posDot);
propertyNameClean = propertyPathClean.substring(prevPosDot, posDot);
} else {
propertyName = propertyPath.substring(prevPosDot);
propertyNameClean = propertyPathClean.substring(prevPosDot);
}
String castName = null;
if (posCast >= 0) {
int p = propertyNameClean.indexOf('(');
if (p >= 0) {
int p2 = propertyNameClean.indexOf(')', p);
if (p2 > 0) {
castName = propertyName.substring(p + 1, p2).trim();
propertyName = propertyName.substring(p2 + 1).trim();
propertyNameClean = propertyNameClean.substring(p2 + 1).trim();
}
}
}
this.castNames = (String[]) OAArray.add(String.class, this.castNames, castName);
String filterName = null;
String filterNameClean = null;
String filterParam = null;
String filterParamClean = null;
Constructor filterConstructor = null;
if (posFilter >= 0) {
posFilter = propertyNameClean.indexOf(':');
filterName = propertyName.substring(posFilter + 1).trim();
filterNameClean = propertyNameClean.substring(posFilter + 1).trim();
propertyName = propertyNameClean = propertyName.substring(0, posFilter).trim();
int p = filterNameClean.indexOf('(');
if (p >= 0) {
filterParam = filterName.substring(p).trim();
filterParamClean = filterNameClean.substring(p).trim();
filterName = filterNameClean = filterName.substring(0, p).trim();
}
}
this.filterNames = (String[]) OAArray.add(String.class, this.filterNames, filterName);
this.filterParams = (String[]) OAArray.add(String.class, this.filterParams, filterParam); // ex: "(a,b)", "()"
// figure out params
int paramCount = 0;
if (filterParam != null) {
if (filterParam.charAt(0) == '(') {
filterParam = filterParam.substring(1);
filterParamClean = filterParamClean.substring(1);
if (filterParam.charAt(filterParam.length() - 1) == ')') {
filterParam = filterParam.substring(0, filterParam.length() - 1);
filterParamClean = filterParamClean.substring(0, filterParamClean.length() - 1);
}
}
paramCount = OAString.dcount(filterParamClean, ",");
}
if (OAObject.class.equals(clazz) && substituteClass != null) {
clazz = substituteClass;
}
OAObjectInfo oi = OAObjectInfoDelegate.getOAObjectInfo(clazz);
final OALinkInfo li = OAObjectInfoDelegate.getLinkInfo(oi, propertyName);
if (li != null) {
endLinkInfo = li;
endPropertyInfo = null;
endCalcInfo = null;
linkInfos = (OALinkInfo[]) OAArray.add(OALinkInfo.class, linkInfos, li);
} else {
endPropertyInfo = OAObjectInfoDelegate.getPropertyInfo(oi, propertyName);
endCalcInfo = endPropertyInfo != null ? null : OAObjectInfoDelegate.getOACalcInfo(oi, propertyName);
endLinkInfo = null;
}
boolean bUsingToString;
String mname;
if (propertyName.length() == 0) {
propertyName = mname = "toString";
bUsingToString = true;
} else {
mname = "get" + propertyName;
bUsingToString = false;
}
this.properties = (String[]) OAArray.add(String.class, this.properties, propertyName);
// 20240131
Method method = OAObjectInfoDelegate.getMethod(oi, mname, 0);
//was: Method method = OAReflect.getMethod(clazz, mname, 0);
bLastMethodHasHubParam = false;
if (method == null) {
if (posDot < 0) {
// 20131029 see if it is for hubCalc, which is a static method that has a Hub param
// must be the last property
method = OAReflect.getMethod(clazz, mname, 1);
if (method != null && Modifier.isStatic(method.getModifiers())) {
if (Hub.class.equals(method.getParameterTypes()[0])) {
bLastMethodHasHubParam = true;
} else {
method = null;
}
} else {
method = null;
}
}
if (method == null) {
mname = "is" + propertyName;
method = OAReflect.getMethod(clazz, mname, 0);
if (method == null) {
if (bIgnorePrivateLink && li != null && li.getPrivateMethod()) {
// wait to show error
} else {
return "OAReflect.setup() cant find method. class=" + (clazz == null ? "null" : clazz.getName()) + " prop="
+ propertyName + " path=" + propertyPath;
}
}
}
}
this.methods = (Method[]) OAArray.add(Method.class, this.methods, method);
if (bUsingToString) {
// keep same clazz
} else if (method == null) {
clazz = li.getToClass();
} else {
clazz = method.getReturnType();
}
if (clazz != null && clazz.equals(Hub.class) && castName == null) {
// try to find the ObjectClass for Hub
Class c = OAObjectInfoDelegate.getHubPropertyClass(classLast, propertyName);
if (c != null) {
clazz = c;
}
} else {
if (castName != null) {
String cn;
if (castName.indexOf('.') >= 0) {
cn = castName;
} else {
if (clazz != null) {
String s = clazz.getName();
int p = s.lastIndexOf('.');
if (p >= 0) {
s = s.substring(0, p + 1);
} else {
s = "";
}
cn = s + castName;
} else {
cn = castName;
}
}
try {
clazz = Class.forName(cn);
} catch (Exception e) {
throw new RuntimeException("error getting castName class=" + cn, e);
}
} else if (cnter == 1 && clazz.equals(OAObject.class) && hub != null) { // 20150712
// see if there is an object to check with
for (Object o : hub) {
if (o instanceof OAObject) {
Object x = ((OAObject) o).getProperty(propertyName);
if (x != null) {
clazz = x.getClass();
break;
}
}
}
}
}
// 20150715
if (clazz.equals(OAObject.class) && hub != null) {
// see if it can be found using data from hub
Class c = findLastClass(hub);
if (c == null || c.equals(OAObject.class)) {
bNeedsDataToVerify = true;
} else {
clazz = c;
}
}
this.classes = (Class[]) OAArray.add(Class.class, this.classes, clazz);
classLast = clazz;
// finish with Filter info
Class filterClass = null;
if (filterName != null) {
String filterClassName;
if (filterName.indexOf('.') >= 0) {
filterClassName = filterName;
} else {
String s = clazz.getName();
int p = s.lastIndexOf('.');
filterClassName = s.substring(p + 1) + filterName + "Filter";
// check annotations for correct upper/lower case
OAClass oac = (OAClass) clazz.getAnnotation(OAClass.class);
if (oac != null) {
Class[] cs = oac.filterClasses();
for (Class c : cs) {
if (!CustomHubFilter.class.isAssignableFrom(c)) {
continue;
}
int px = c.getName().toUpperCase().indexOf("." + filterClassName.toUpperCase());
if (px >= 0) {
if ((px + filterClassName.length() + 1) == c.getName().length()) {
filterClass = c;
filterClassName = c.getName();
break;
}
}
}
}
if (filterClass == null) {
if (p >= 0) {
s = s.substring(0, p + 1) + "filter.";
} else {
s = "";
}
filterClassName = s + filterName;
}
}
if (filterClass == null) {
try {
filterClass = Class.forName(filterClassName);
// note: filterClass does not have to exist, as some tools will allow
// creating custom ones. ex: OAFinder has a method that is called to create the filter
} catch (Exception e) {
}
}
if (filterClass != null && !CustomHubFilter.class.isAssignableFrom(filterClass)) {
return "Filter must implement interface CustomHubFilter";
}
}
this.filterClasses = (Class[]) OAArray.add(Class.class, this.filterClasses, filterClass);
Object[] filterParamValue = null;
if (filterClass != null && paramCount > 0) {
for (Constructor con : filterClass.getConstructors()) {
Class[] cs = con.getParameterTypes();
if (cs.length != paramCount + 2) {
continue;
}
if (!cs[0].equals(Hub.class)) {
continue;
}
filterConstructor = con;
filterParamValue = new Object[paramCount];
int p = 0;
int prev = 0;
for (int i = 0; p >= 0; i++, prev = p + 1) {
p = filterParamClean.indexOf(',', prev);
String s;
if (p < 0) {
s = filterParam.substring(prev).trim();
} else {
s = filterParam.substring(prev, p).trim();
}
// remove double quotes
int x = s.length();
if (x > 0 && s.charAt(0) == '\"' && s.charAt(x - 1) == '\"') {
if (x < 3) {
s = "";
} else {
s = s.substring(1, x - 2);
}
}
if (s.equals("?")) {
// needs to be an inputValue
filterParamValue[i] = "?";
} else {
filterParamValue[i] = OAConv.convert(cs[i + 2], s);
}
}
break;
}
} else {
if (filterClass != null) {
try {
filterConstructor = filterClass.getConstructor(new Class[] { Hub.class, Hub.class });
} catch (Exception e) {
throw new RuntimeException("error getting filter constructor", e);
}
}
}
if (filterClass != null && filterConstructor == null) {
//throw new RuntimeException("Could not find constructor for Filter, name="+filterName);
}
this.filterConstructors = (Constructor[]) OAArray.add(Constructor.class, this.filterConstructors, filterConstructor);
if (this.filterParamValues == null) {
this.filterParamValues = new Object[1][];
} else {
Object[][] objs = new Object[filterParamValues.length + 1][];
System.arraycopy(filterParamValues, 0, objs, 0, filterParamValues.length);
filterParamValues = objs;
}
filterParamValues[filterParamValues.length - 1] = filterParamValue;
}
// 20140118 update recursiveMethods
if (linkInfos != null) {
recursiveLinkInfos = new OALinkInfo[linkInfos.length];
int j = 0;
for (OALinkInfo li : linkInfos) {
j++;
if (li == null || !li.getRecursive()) {
continue;
}
OAObjectInfo oi = OAObjectInfoDelegate.getOAObjectInfo(li.getToClass());
OALinkInfo lix;
if (li.getType() == OALinkInfo.MANY) {
lix = OAObjectInfoDelegate.getRecursiveLinkInfo(oi, OALinkInfo.MANY);
} else {
lix = OAObjectInfoDelegate.getRecursiveLinkInfo(oi, OALinkInfo.ONE);
}
recursiveLinkInfos[j - 1] = lix;
}
}
return null;
}
// 20150715 find the class by looking at the data
private Class findLastClass(final Object obj) {
return _findLastClass(obj, 0);
}
private Class _findLastClass(final Object obj, final int pos) {
if (this.properties == null || pos >= this.properties.length) {
return null;
}
Class clazz;
if (obj instanceof Hub) {
clazz = _findLastClass((Hub) obj, pos);
} else if (obj instanceof Object) {
clazz = _findLastClass((Hub) obj, pos);
} else {
clazz = null;
}
return clazz;
}
private Class _findLastClass(final Hub hubRoot, final int pos) {
if (hubRoot == null) {
return null;
}
if (this.properties == null || pos >= this.properties.length) {
// this is last prop
return hubRoot.getObjectClass();
}
Class clazz = null;
for (Object obj : hubRoot) {
if (!(obj instanceof OAObject)) {
break;
}
clazz = _findLastClass(obj, pos + 1);
if (clazz != null) {
break;
}
}
return clazz;
}
private Class _findLastClass(final OAObject obj, final int pos) {
if (obj == null) {
return null;
}
if (this.properties == null || pos >= this.properties.length) {
// this is last prop
return obj.getClass();
}
Class clazz = null;
Object objValue = ((OAObject) obj).getProperty(this.properties[pos]);
if (objValue != null) {
clazz = _findLastClass(objValue, pos + 1);
}
return clazz;
}
private boolean bFormat;
private String format;
public String getFormat() {
if (format != null || bFormat) {
return format;
}
bFormat = true;
Class[] cs = getClasses();
if (cs == null || cs.length == 0) {
return null;
}
Class c = cs[cs.length - 1];
OAProperty op = getOAPropertyAnnotation();
if (op != null) {
format = op.format();
if (!OAString.isEmpty(format)) {
return format;
}
int deci = op.decimalPlaces();
if (OAReflect.isFloat(c)) {
if (op.isCurrency()) {
format = OAConv.getCurrencyFormat();
format = getDecimalFormat(format, deci);
} else {
format = getDecimalFormat(deci);
}
return format;
}
if (OAReflect.isInteger(c)) {
if (op.isCurrency()) {
String fx = OAConv.getCurrencyFormat();
if (deci < 0) {
deci = 0;
}
format = getDecimalFormat(fx, deci);
} else {
format = OAConv.getIntegerFormat();
format = getDecimalFormat(format, deci);
}
return format;
}
}
OACalculatedProperty cp = getOACalculatedPropertyAnnotation();
if (cp != null) {
format = cp.outputFormat();
if (!OAString.isEmpty(format)) {
return format;
}
if (OAReflect.isFloat(c)) {
if (cp.isCurrency()) {
format = OAConv.getCurrencyFormat();
format = getDecimalFormat(format, cp.decimalPlaces());
} else {
format = getDecimalFormat(cp.decimalPlaces());
}
return format;
}
if (OAReflect.isInteger(c)) {
if (cp.isCurrency()) {
String format = OAConv.getCurrencyFormat();
int x = cp.decimalPlaces();
if (x < 0) {
x = 0;
}
format = getDecimalFormat(format, x);
} else {
format = OAConv.getIntegerFormat();
format = getDecimalFormat(format, cp.decimalPlaces());
}
return format;
}
}
if (OAReflect.isFloat(c)) {
format = OAConv.getDecimalFormat();
} else {
format = OAConverter.getFormat(c);
}
return format;
}
private String getDecimalFormat(int deci) {
String format = OAConv.getDecimalFormat();
return getDecimalFormat(format, deci);
}
private String getDecimalFormat(String format, int deci) {
if (format == null) {
format = "";
}
if (deci < 0) {
return format;
}
// DecimalFormat = #,##0.00
int pos = format.indexOf('.');
if (pos < 0) {
if (deci != 0) {
format += ".";
for (int i = 0; i < deci; i++) {
format += "0";
}
}
} else {
int current = (format.length() - pos) - 1;
int diff = deci - current;
if (diff < 0) {
format = format.substring(0, pos + deci + 1);
} else if (diff > 0) {
for (int i = 0; i < diff; i++) {
format += "0";
}
}
}
return format;
}
private boolean bHasHubProperty;
private boolean bHasHubPropertyCheck;
public boolean getHasHubProperty() {
if (bHasHubPropertyCheck) {
return bHasHubProperty;
}
if (linkInfos != null) {
for (OALinkInfo li : linkInfos) {
if (li.getType() == li.TYPE_MANY) {
bHasHubProperty = true;
break;
}
}
}
bHasHubPropertyCheck = true;
return bHasHubProperty;
}
/**
* Used when fromObject is already in the propertyPath.
*
* @param fromObject object to start with
* @param startPos number of properties to skip in the PP, that aligns with fromObject's position in the PP.
*/
public Object getValue(final OAObject fromObject, final int startPos) {
if (fromObject == null) {
return null;
}
Object result = fromObject;
for (int i = startPos; i < methods.length; i++) {
try {
result = methods[i].invoke(result);
} catch (Exception e) {
throw new RuntimeException("error invoking method=" + methods[i], e);
}
if (result == null) {
break;
}
if (i + 1 < methods.length && result instanceof Hub) {
result = ((Hub) result).getAO();
if (result == null) {
break;
}
}
}
return result;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy