weka.core.PropertyPath Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of weka-stable Show documentation
Show all versions of weka-stable Show documentation
The Waikato Environment for Knowledge Analysis (WEKA), a machine
learning workbench. This is the stable version. Apart from bugfixes, this version
does not receive any other updates.
/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
/*
* PropertyPath.java
* Copyright (C) 2006-2012 University of Waikato, Hamilton, New Zealand
*/
package weka.core;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.StringTokenizer;
import java.util.Vector;
/**
* A helper class for accessing properties in nested objects, e.g., accessing
* the "getRidge" method of a LinearRegression classifier part of
* MultipleClassifierCombiner, e.g., Vote. For doing so, one needs to
* supply the object to work on and a property path. The property path is a
* dot delimited path of property names ("getFoo()" and "setFoo(int)" have
* "foo" as property name), indices of arrays are 0-based. E.g.:
*
* getPropertyDescriptor(vote, "classifiers[1].ridge")
will return
* the second classifier (which should be our LinearRegression) of the given
* Vote meta-classifier and there the property descriptor of the "ridge"
* property. getValue(...)
will return the actual value of the
* ridge parameter and setValue(...)
will set it.
*
* @author fracpete (fracpete at waikato dot ac dot nz)
* @version $Revision: 8034 $
*/
public class PropertyPath
implements RevisionHandler {
/**
* Represents a single element of a property path
*
* @author fracpete (fracpete at waikato dot ac dot nz)
* @version $Revision: 8034 $
*/
public static class PathElement
implements Cloneable, RevisionHandler {
/** the property */
protected String m_Name;
/** the index of the array (-1 for none) */
protected int m_Index;
/**
* initializes the path element with the given property
*
* @param property the property to initialize with
*/
public PathElement(String property) {
super();
if (property.indexOf("[") > -1) {
m_Name = property.replaceAll("\\[.*$", "");
m_Index = Integer.parseInt(
property.replaceAll(".*\\[", "").replaceAll("\\].*", ""));
}
else {
m_Name = property;
m_Index = -1;
}
}
/**
* returns a clone of the current object
*
* @return the clone of the current state
*/
public Object clone() {
return new PathElement(this.toString());
}
/**
* returns the name of the property
*
* @return the name of the property
*/
public String getName() {
return m_Name;
}
/**
* returns whether the property is an index-based one
*
* @return true if the property has an index
*/
public boolean hasIndex() {
return (getIndex() > -1);
}
/**
* returns the index of the property, -1 if the property is not an
* index-based one
*
* @return the index of the property
*/
public int getIndex() {
return m_Index;
}
/**
* returns the element once again as string
*
* @return the property as string
*/
public String toString() {
String result;
result = getName();
if (hasIndex())
result += "[" + getIndex() + "]";
return result;
}
/**
* Returns the revision string.
*
* @return the revision
*/
public String getRevision() {
return RevisionUtils.extract("$Revision: 8034 $");
}
}
/**
* Contains a (property) path structure
*
* @author fracpete (fracpete at waikato dot ac dot nz)
* @version $Revision: 8034 $
*/
public static class Path
implements RevisionHandler {
/** the structure */
protected Vector m_Elements;
/**
* default constructor, only used internally
*/
protected Path() {
super();
m_Elements = new Vector();
}
/**
* uses the given dot-path
*
* @param path path in dot-notation
*/
public Path(String path) {
this();
m_Elements = breakUp(path);
}
/**
* uses the vector with PathElement objects to initialize with
*
* @param elements the PathElements to use
*/
public Path(Vector elements) {
this();
for (int i = 0; i < elements.size(); i++)
m_Elements.add((PathElement) elements.get(i).clone());
}
/**
* uses the given array as elements for the path
*
* @param elements the path elements to use
*/
public Path(String[] elements) {
this();
for (int i = 0; i < elements.length; i++)
m_Elements.add(new PathElement(elements[i]));
}
/**
* breaks up the given path and returns it as vector
*
* @param path the path to break up
* @return the single elements of the path
*/
protected Vector breakUp(String path) {
Vector result;
StringTokenizer tok;
result = new Vector();
tok = new StringTokenizer(path, ".");
while (tok.hasMoreTokens())
result.add(new PathElement(tok.nextToken()));
return result;
}
/**
* returns the element at the given index
*
* @param index the index of the element to return
* @return the specified element
*/
public PathElement get(int index) {
return (PathElement) m_Elements.get(index);
}
/**
* returns the number of path elements of this structure
*
* @return the number of path elements
*/
public int size() {
return m_Elements.size();
}
/**
* returns a path object based on the given path string
*
* @param path path to work on
* @return the path structure
*/
public static Path parsePath(String path) {
return new Path(path);
}
/**
* returns a subpath of the current structure, starting with the specified
* element index up to the end
*
* @param startIndex the first element of the subpath
* @return the new subpath
*/
public Path subpath(int startIndex) {
return subpath(startIndex, size());
}
/**
* returns a subpath of the current structure, starting with the specified
* element index up. The endIndex specifies the element that is not part
* of the new subpath. In other words, the new path contains the elements
* from "startIndex" up to "(endIndex-1)".
*
* @param startIndex the first element of the subpath
* @param endIndex the element that is after the last added element
* @return the new subpath
*/
public Path subpath(int startIndex, int endIndex) {
Vector list;
int i;
list = new Vector();
for (i = startIndex; i < endIndex; i++)
list.add(get(i));
return new Path(list);
}
/**
* returns the structure again as a dot-path
*
* @return the path structure as dot-path
*/
public String toString() {
String result;
int i;
result = "";
for (i = 0; i < m_Elements.size(); i++) {
if (i > 0)
result += ".";
result += m_Elements.get(i);
}
return result;
}
/**
* Returns the revision string.
*
* @return the revision
*/
public String getRevision() {
return RevisionUtils.extract("$Revision: 8034 $");
}
}
/**
* A helper class that stores Object and PropertyDescriptor together.
*
* @author fracpete (fracpete at waikato dot ac dot nz)
* @version $Revision: 8034 $
*/
protected static class PropertyContainer
implements RevisionHandler {
/** the descriptor */
protected PropertyDescriptor m_Descriptor;
/** the associated object */
protected Object m_Object;
/**
* initializes the container
*
* @param desc the property descriptor
* @param obj the associated object
*/
public PropertyContainer(PropertyDescriptor desc, Object obj) {
super();
m_Descriptor = desc;
m_Object = obj;
}
/**
* returns the stored descriptor
*
* @return the stored descriptor
*/
public PropertyDescriptor getDescriptor() {
return m_Descriptor;
}
/**
* returns the stored object
*
* @return the stored object
*/
public Object getObject() {
return m_Object;
}
/**
* Returns the revision string.
*
* @return the revision
*/
public String getRevision() {
return RevisionUtils.extract("$Revision: 8034 $");
}
}
/**
* returns the property and object associated with the given path, null if
* a problem occurred.
*
* @param src the object to start from
* @param path the path to follow
* @return not null, if the property could be found
*/
public static PropertyContainer find(Object src, Path path) {
PropertyContainer result;
PropertyDescriptor desc;
Object newSrc;
PathElement part;
Method method;
Object methodResult;
// get descriptor
part = path.get(0);
try {
desc = new PropertyDescriptor(part.getName(), src.getClass());
}
catch (Exception e) {
desc = null;
e.printStackTrace();
}
// problem occurred? -> stop
if (desc == null)
return null;
// end of path reached?
if (path.size() == 1) {
result = new PropertyContainer(desc, src);
}
// recurse further
else {
try {
method = desc.getReadMethod();
methodResult = method.invoke(src, (Object[]) null);
if (part.hasIndex())
newSrc = Array.get(methodResult, part.getIndex());
else
newSrc = methodResult;
result = find(newSrc, path.subpath(1));
}
catch (Exception e) {
result = null;
e.printStackTrace();
}
}
return result;
}
/**
* returns the property associated with the given path, null if a problem
* occurred.
*
* @param src the object to start from
* @param path the path to follow
* @return not null, if the property could be found
*/
public static PropertyDescriptor getPropertyDescriptor(Object src, Path path) {
PropertyContainer cont;
cont = find(src, path);
if (cont == null)
return null;
else
return cont.getDescriptor();
}
/**
* returns the property associated with the given path
*
* @param src the object to start from
* @param path the path to follow
* @return not null, if the property could be found
*/
public static PropertyDescriptor getPropertyDescriptor(Object src, String path) {
return getPropertyDescriptor(src, new Path(path));
}
/**
* returns the value specified by the given path from the object
*
* @param src the object to work on
* @param path the retrieval path
* @return the value, null if an error occurred
*/
public static Object getValue(Object src, Path path) {
Object result;
PropertyContainer cont;
Method method;
Object methodResult;
PathElement part;
result = null;
cont = find(src, path);
// problem?
if (cont == null)
return null;
// retrieve the value
try {
part = path.get(path.size() - 1);
method = cont.getDescriptor().getReadMethod();
methodResult = method.invoke(cont.getObject(), (Object[]) null);
if (part.hasIndex())
result = Array.get(methodResult, part.getIndex());
else
result = methodResult;
}
catch (Exception e) {
result = null;
e.printStackTrace();
}
return result;
}
/**
* returns the value specified by the given path from the object
*
* @param src the object to work on
* @param path the retrieval path
* @return the value, null if an error occurred
*/
public static Object getValue(Object src, String path) {
return getValue(src, new Path(path));
}
/**
* set the given value specified by the given path in the object
*
* @param src the object to work on
* @param path the retrieval path
* @param value the value to set
* @return true if the value could be set
*/
public static boolean setValue(Object src, Path path, Object value) {
boolean result;
PropertyContainer cont;
Method methodRead;
Method methodWrite;
Object methodResult;
PathElement part;
result = false;
cont = find(src, path);
// problem?
if (cont == null)
return result;
// set the value
try {
part = path.get(path.size() - 1);
methodRead = cont.getDescriptor().getReadMethod();
methodWrite = cont.getDescriptor().getWriteMethod();
if (part.hasIndex()) {
methodResult = methodRead.invoke(cont.getObject(), (Object[]) null);
Array.set(methodResult, part.getIndex(), value);
methodWrite.invoke(cont.getObject(), new Object[]{methodResult});
}
else {
methodWrite.invoke(cont.getObject(), new Object[]{value});
}
result = true;
}
catch (Exception e) {
result = false;
e.printStackTrace();
}
return result;
}
/**
* set the given value specified by the given path in the object
*
* @param src the object to work on
* @param path the retrieval path
* @param value the value to set
*/
public static void setValue(Object src, String path, Object value) {
setValue(src, new Path(path), value);
}
/**
* Returns the revision string.
*
* @return the revision
*/
public String getRevision() {
return RevisionUtils.extract("$Revision: 8034 $");
}
/**
* for testing only
*
* @param args the commandline options - ignored
* @throws Exception if something goes wrong
*/
public static void main(String[] args) throws Exception {
// Path
Path path = new Path("hello.world[2].nothing");
System.out.println("Path: " + path);
System.out.println(" -size: " + path.size());
System.out.println(" -elements:");
for (int i = 0; i < path.size(); i++)
System.out.println(
" " + i + ". " + path.get(i).getName()
+ " -> " + path.get(i).getIndex());
/*
// retrieving ridge with path
weka.classifiers.meta.Vote vote = new weka.classifiers.meta.Vote();
vote.setClassifiers(
new weka.classifiers.Classifier[]{
new weka.classifiers.trees.J48(),
new weka.classifiers.functions.LinearRegression()});
path = new Path("classifiers[1].ridge");
System.out.println("path: " + path + " -> " + getValue(vote, path));
// setting ridge with path and retrieving it again
setValue(vote, path.toString(), new Double(0.1));
System.out.println("path: " + path + " -> " + getValue(vote, path));
*/
}
}