I have found few similar threads about infinity loop while trying save object as Json, but most of them are about java + jpa, and these solutions don't work for me. I would like to create tree structure of some data. There is class ProjectNode which got
private ArrayList<ProjectNode> children;
field. I'm pretty sure this one course the problem but its the main field in this structure, I can't ignore it. I have tested and I can convert object which has list with node which doesn't have children, but cant if any child got another children in the below code:
public class ProjectNode implements Comparable<ProjectNode>{
private String parent;
private String nodeName;
private String nodeHref;
private boolean hasChild;
private int td;
private ArrayList<ProjectNode> children;
public ProjectNode() {
super();
// TODO Auto-generated constructor stub
}
+ getters and setters
ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writeValueAsString(parser.getProjectFactory().get(12));
parser.getProjectFactory() returns list of ParentNodes (parent=null), I would like to convert 12 elements because there is a case where node has child and this child has child. Cause this error:
Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"]->java.util.ArrayList[31]->ProjectNode["children"])
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:734)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)
at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:119)
at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serialize(IndexedListSerializer.java:79)
at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serialize(IndexedListSerializer.java:18)
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:727)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719)
EDIT:
Parser - parse project/hosts list from cacti:
public List<ProjectNode> getProjectFactory() throws FailingHttpStatusCodeException, MalformedURLException, IOException {
FileWriter fstream = new FileWriter("graphMap.txt");
BufferedWriter out = new BufferedWriter(fstream);
String [] hostInfo = null;
HtmlTableCell cel= (HtmlTableCell) page.getHtmlPage().getByXPath("/html/body/table/tbody/tr[5]/td[1]").get(0);
System.out.println(cel.getChildElementCount());
List<HtmlDivision> divs = cel.getByXPath(".//div");
System.out.println(divs.size());
//checks if list of host has been added to the project
ProjectTree projectTree = new ProjectTree();
Map<Integer,String> suppMap = new HashMap<Integer,String>();
for(HtmlDivision div : divs) {
List<DomNode> td = div.getByXPath(".//table/tbody/tr/td");
if(td.size()>2) {
ProjectNode pn = new ProjectNode(getNameSrc(td).split("#")[0],getNameSrc(td).split("#")[1],td.size());
hostInfo = getNameSrc(td).split("#");
if(pn.getTd()>3) {
if(!suppMap.get(pn.getTd()-1).isEmpty()) {
pn.setParent(suppMap.get(pn.getTd()-1));
}
if(suppMap.get(pn.getTd())!=null){
suppMap.remove(pn.getTd());
}
suppMap.put(pn.getTd(), pn.getNodeName());
projectTree.addNodeToTree(pn);
} else {
projectTree.addNodeToTree(pn);
suppMap.put(pn.getTd(), pn.getNodeName());
//out.write(pn.toString()+"\n");
}
}
}
ArrayList<ProjectNode> pns = projectTree.getNodeList();
Collections.sort(pns, Comparator.comparing(ProjectNode::getTd));
Collections.reverse(pns);
projectTree.setNodeList(pns);
List<ProjectNode> finalList = new ArrayList<ProjectNode>();
for(ProjectNode pn :pns ) {
if(pn.getTd()==3) {
finalList.add(pn);
}else {
projectTree.addToParent(pn);
}
}
Collections.reverse(finalList);
for(ProjectNode pn : finalList) {
Collections.sort(pn.getChildren());
}
out.write(finalList.get(12).getChildren().get(4).getChildren().toString());
out.close();
System.out.println(finalList.size());
return finalList;
}
ProjectTree class
public class ProjectTree {
private ProjectNode rootNode;
private ArrayList<ProjectNode> NodeList;
public ProjectTree() {
super();
this.NodeList = new ArrayList<ProjectNode>();
}
public ProjectTree(ProjectNode rootNode, ArrayList<ProjectNode> nodeList) {
super();
this.rootNode = rootNode;
NodeList = nodeList;
}
public ArrayList<ProjectNode> groupHosts(){
return this.NodeList;
}
public void addToParent(ProjectNode pn) {
for(ProjectNode pnA :this.NodeList) {
if(pnA.getNodeName().equals(pn.getParent())) {
if(pnA.getChildren()!=null && pnA.getChildren().size()!=0) {
pnA.sortChildren();
}
pnA.addChlild(pn);
}
}
}
public ProjectNode getRootNode() {
return rootNode;
}
public void setRootNode(ProjectNode rootNode) {
this.rootNode = rootNode;
}
public ArrayList<ProjectNode> getNodeList() {
return NodeList;
}
public void setNodeList(ArrayList<ProjectNode> nodeList) {
NodeList = nodeList;
}
}
ProjectNode.class
public class ProjectNode implements Comparable<ProjectNode>{
private String parent;
private String nodeName;
private String nodeHref;
private boolean hasChild;
private int td;
private ArrayList<ProjectNode> children;
public ProjectNode() {
super();
// TODO Auto-generated constructor stub
}
public ProjectNode( String nodeName, String nodeHref, int td) {
super();
this.nodeName = nodeName;
this.nodeHref = nodeHref;
this.hasChild =false;
this.td=td;
}
public void addChlild(ProjectNode pn) {
if(children!=null) {
this.children.add(pn);
}else {
this.children = new ArrayList<ProjectNode>();
this.children.add(pn);
}
}
public List<ProjectNode> getChildren() {
return children;
}
public void sortChildren() {
Collections.sort(this.getChildren());;
//Collections.sort(this.getChildren(), Comparator.comparing(ProjectNode::getNodeName));
//System.out.println(this.children.toString());
}
public void setChildren(ArrayList<ProjectNode> children) {
this.children = children;
}
public int getTd() {
return td;
}
public void setTd(int td) {
this.td = td;
}
public boolean isHasChild() {
return hasChild;
}
public void setHasChild(boolean hasChild) {
this.hasChild = hasChild;
}
public String getParent() {
return parent;
}
public void setParent(String parent) {
this.parent = parent;
}
public String getNodeName() {
return nodeName;
}
public void setNodeName(String nodeName) {
this.nodeName = nodeName;
}
public String getNodeHref() {
return nodeHref;
}
public void setNodeHref(String nodeHref) {
this.nodeHref = nodeHref;
}
#Override
public String toString() {
return "ProjectNode [parent=" + parent + ", nodeName=" + nodeName + ", nodeHref=" + nodeHref + ", hasChild="
+ hasChild + ", td=" + td + ", children=" +"]";
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((children == null) ? 0 : children.hashCode());
result = prime * result + (hasChild ? 1231 : 1237);
result = prime * result + ((nodeHref == null) ? 0 : nodeHref.hashCode());
result = prime * result + ((nodeName == null) ? 0 : nodeName.hashCode());
result = prime * result + ((parent == null) ? 0 : parent.hashCode());
result = prime * result + td;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ProjectNode other = (ProjectNode) obj;
if (children == null) {
if (other.children != null)
return false;
} else if (!children.equals(other.children))
return false;
if (hasChild != other.hasChild)
return false;
if (nodeHref == null) {
if (other.nodeHref != null)
return false;
} else if (!nodeHref.equals(other.nodeHref))
return false;
if (nodeName == null) {
if (other.nodeName != null)
return false;
} else if (!nodeName.equals(other.nodeName))
return false;
if (parent == null) {
if (other.parent != null)
return false;
} else if (!parent.equals(other.parent))
return false;
if (td != other.td)
return false;
return true;
}
#Override
public int compareTo(ProjectNode o) {
// TODO Auto-generated method stub
return nodeName.compareTo(o.getNodeName());
}
}
I would use recursive to groupd all nodes in corect place but i had same error (with stackoverflow) so i had to use work around which is addToParent() function.
I have managed it by breaking loop when parent of my node have been found. I made it just for performance because before even if parent has been found loop was checking all elements anyway so i added break, and it works.. Not sure why..
Code below:
public void group() {
int td = this.highestTd;
while (td > 2) {
List<ProjectNode> toRemove = new ArrayList<ProjectNode>();
for (ProjectNode pnA : this.NodeList) {
if(pnA.getTd()==3) {
pnA.setParent("root");
}
if (pnA.getTd() == td) {
for (ProjectNode pnB : this.NodeList) {
System.out.println(pnB.toString());
if (pnA.getParent()!=null && pnA.getParent().equals(pnB.getNodeName())) {
System.out.println("Dodaje "+pnA.getNodeName() + " Do "+pnB.getNodeName());
pnB.addChlild(pnA);
toRemove.add(pnA);
break;
}
}
}
}
td--;
this.NodeList.removeAll(toRemove);
}
}
Related
I'm trying to create a 'skeletal' like system using class Bone and having the "primary" bone's children consist of all other bones that are connected.
public class Main {
public static void main(String[] args) {
Bone body = new Bone("primary", null);
Bone leftArm1 = new Bone("left_arm_1", body);
Bone leftArm2 = new Bone("left_arm_2", leftArm1);
Bone rightArm1 = new Bone("right_arm_1", body);
Bone rightArm2 = new Bone("right_arm_2", rightArm1);
List<Bone> bones = new ArrayList<Bone>();
for(Bone child : body.getChildren()) {
System.out.println(child.getName());
}
}
}
public class Bone {
private Bone parent = null;
private String name = null;
private List<Bone> children = new ArrayList<Bone>();
public Bone(String name, Bone parent) {
this.name = name;
this.parent = parent;
if(parent != null) {
parent.addChild(this);
}
}
public String getName() {
return this.name;
}
public Bone getParent() {
return this.parent;
}
public boolean hasParent() {
if(this.parent != null) {
return true;
} else {
return false;
}
}
public List<Bone> getChildren() {
return this.children;
}
public boolean hasChildren() {
if(this.children.isEmpty()) {
return false;
} else {
return true;
}
}
public void addChild(Bone child) {
this.children.add(child);
}
}
The current program is outputting...
left_arm_1
right_arm_1
when it should be outputting...
left_arm_1
left_arm_2
right_arm_1
right_arm_2
how would I make the program output the correct strings?
I would use recursion
public void printBones(Bone bone) {
if(bone == null) {
return;
}
List<Bone> children = bone.getChildren();
if(children != null && children.size() > 0) {
for(Bone bone : children) {
printBones(bone);
}
}
System.out.println(bone.getName());
}
Because body has only 2 children, the output is only left_arm_1 right_arm_1
If you want to print all children, you need to do it in recursion for all children of the children and so on.
How do I use DOTGenerator to convert a parse tree to DOT/graphviz format in ANTLR4?
I found this related question but the only answer uses TreeViewer to display the tree in a JPanel and that's not what I'm after. This other question is exacly what I need but it didn't get answered. Everything else I stumbled upon relates to DOTTreeGenerator from ANTLR3 and it's not helpful.
I'm using Java with the ANTLR4 plugin for IntelliJ.
I have a small project that has all kind of utility methods w.r.t. ANTLR4 grammar debugging/testing. I haven't found the time to provide it of some proper documentation so that I can put it on Github. But here's a part of it responsible for creating a DOT file from a grammar.
Stick it all in a single file called Main.java (and of course generate the lexer and parser for Expression.g4), and you will see a DOT string being printed to your console:
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.tree.ParseTree;
import java.util.*;
public class Main {
public static void main(String[] args) {
/*
// Expression.g4
grammar Expression;
expression
: '-' expression
| expression ('*' | '/') expression
| expression ('+' | '-') expression
| '(' expression ')'
| NUMBER
| VARIABLE
;
NUMBER
: [0-9]+ ( '.' [0-9]+ )?
;
VARIABLE
: [a-zA-Z] [a-zA-Z0-9]+
;
SPACE
: [ \t\r\n] -> skip
;
*/
String source = "3 + 42 * (PI - 3.14159)";
ExpressionLexer lexer = new ExpressionLexer(CharStreams.fromString(source));
ExpressionParser parser = new ExpressionParser(new CommonTokenStream(lexer));
SimpleTree tree = new SimpleTree.Builder()
.withParser(parser)
.withParseTree(parser.expression())
.withDisplaySymbolicName(false)
.build();
DotOptions options = new DotOptions.Builder()
.withParameters(" labelloc=\"t\";\n label=\"Expression Tree\";\n\n")
.withLexerRuleShape("circle")
.build();
System.out.println(new DotTreeRepresentation().display(tree, options));
}
}
class DotTreeRepresentation {
public String display(SimpleTree tree) {
return display(tree, DotOptions.DEFAULT);
}
public String display(SimpleTree tree, DotOptions options) {
return display(new InOrderTraversal().traverse(tree), options);
}
public String display(List<SimpleTree.Node> nodes, DotOptions options) {
StringBuilder builder = new StringBuilder("graph tree {\n\n");
Map<SimpleTree.Node, String> nodeNameMap = new HashMap<>();
int nodeCount = 0;
if (options.parameters != null) {
builder.append(options.parameters);
}
for (SimpleTree.Node node : nodes) {
nodeCount++;
String nodeName = String.format("node_%s", nodeCount);
nodeNameMap.put(node, nodeName);
builder.append(String.format(" %s [label=\"%s\", shape=%s];\n",
nodeName,
node.getLabel().replace("\"", "\\\""),
node.isTokenNode() ? options.lexerRuleShape : options.parserRuleShape));
}
builder.append("\n");
for (SimpleTree.Node node : nodes) {
String name = nodeNameMap.get(node);
for (SimpleTree.Node child : node.getChildren()) {
String childName = nodeNameMap.get(child);
builder.append(" ").append(name).append(" -- ").append(childName).append("\n");
}
}
return builder.append("}\n").toString();
}
}
class InOrderTraversal {
public List<SimpleTree.Node> traverse(SimpleTree tree) {
if (tree == null)
throw new IllegalArgumentException("tree == null");
List<SimpleTree.Node> nodes = new ArrayList<>();
traverse(tree.root, nodes);
return nodes;
}
private void traverse(SimpleTree.Node node, List<SimpleTree.Node> nodes) {
if (node.hasChildren()) {
traverse(node.getChildren().get(0), nodes);
}
nodes.add(node);
for (int i = 1; i < node.getChildCount(); i++) {
traverse(node.getChild(i), nodes);
}
}
}
class DotOptions {
public static final DotOptions DEFAULT = new DotOptions.Builder().build();
public static final String DEFAULT_PARAMETERS = null;
public static final String DEFAULT_LEXER_RULE_SHAPE = "box";
public static final String DEFAULT_PARSER_RULE_SHAPE = "ellipse";
public static class Builder {
private String parameters = DEFAULT_PARAMETERS;
private String lexerRuleShape = DEFAULT_LEXER_RULE_SHAPE;
private String parserRuleShape = DEFAULT_PARSER_RULE_SHAPE;
public DotOptions.Builder withParameters(String parameters) {
this.parameters = parameters;
return this;
}
public DotOptions.Builder withLexerRuleShape(String lexerRuleShape) {
this.lexerRuleShape = lexerRuleShape;
return this;
}
public DotOptions.Builder withParserRuleShape(String parserRuleShape) {
this.parserRuleShape = parserRuleShape;
return this;
}
public DotOptions build() {
if (lexerRuleShape == null)
throw new IllegalStateException("lexerRuleShape == null");
if (parserRuleShape == null)
throw new IllegalStateException("parserRuleShape == null");
return new DotOptions(parameters, lexerRuleShape, parserRuleShape);
}
}
public final String parameters;
public final String lexerRuleShape;
public final String parserRuleShape;
private DotOptions(String parameters, String lexerRuleShape, String parserRuleShape) {
this.parameters = parameters;
this.lexerRuleShape = lexerRuleShape;
this.parserRuleShape = parserRuleShape;
}
}
class SimpleTree {
public static class Builder {
private Parser parser = null;
private ParseTree parseTree = null;
private Set<Integer> ignoredTokenTypes = new HashSet<>();
private boolean displaySymbolicName = true;
public SimpleTree build() {
if (parser == null) {
throw new IllegalStateException("parser == null");
}
if (parseTree == null) {
throw new IllegalStateException("parseTree == null");
}
return new SimpleTree(parser, parseTree, ignoredTokenTypes, displaySymbolicName);
}
public SimpleTree.Builder withParser(Parser parser) {
this.parser = parser;
return this;
}
public SimpleTree.Builder withParseTree(ParseTree parseTree) {
this.parseTree = parseTree;
return this;
}
public SimpleTree.Builder withIgnoredTokenTypes(Integer... ignoredTokenTypes) {
this.ignoredTokenTypes = new HashSet<>(Arrays.asList(ignoredTokenTypes));
return this;
}
public SimpleTree.Builder withDisplaySymbolicName(boolean displaySymbolicName) {
this.displaySymbolicName = displaySymbolicName;
return this;
}
}
public final SimpleTree.Node root;
private SimpleTree(Parser parser, ParseTree parseTree, Set<Integer> ignoredTokenTypes, boolean displaySymbolicName) {
this.root = new SimpleTree.Node(parser, parseTree, ignoredTokenTypes, displaySymbolicName);
}
public SimpleTree(SimpleTree.Node root) {
if (root == null)
throw new IllegalArgumentException("root == null");
this.root = root;
}
public SimpleTree copy() {
return new SimpleTree(root.copy());
}
public String toLispTree() {
StringBuilder builder = new StringBuilder();
toLispTree(this.root, builder);
return builder.toString().trim();
}
private void toLispTree(SimpleTree.Node node, StringBuilder builder) {
if (node.isLeaf()) {
builder.append(node.getLabel()).append(" ");
}
else {
builder.append("(").append(node.label).append(" ");
for (SimpleTree.Node child : node.children) {
toLispTree(child, builder);
}
builder.append(") ");
}
}
#Override
public String toString() {
return String.format("%s", this.root);
}
public static class Node {
protected String label;
protected int level;
protected boolean isTokenNode;
protected List<SimpleTree.Node> children;
Node(Parser parser, ParseTree parseTree, Set<Integer> ignoredTokenTypes, boolean displaySymbolicName) {
this(parser.getRuleNames()[((RuleContext)parseTree).getRuleIndex()], 0, false);
traverse(parseTree, this, parser, ignoredTokenTypes, displaySymbolicName);
}
public Node(String label, int level, boolean isTokenNode) {
this.label = label;
this.level = level;
this.isTokenNode = isTokenNode;
this.children = new ArrayList<>();
}
public void replaceWith(SimpleTree.Node node) {
this.label = node.label;
this.level = node.level;
this.isTokenNode = node.isTokenNode;
this.children.remove(node);
this.children.addAll(node.children);
}
public SimpleTree.Node copy() {
SimpleTree.Node copy = new SimpleTree.Node(this.label, this.level, this.isTokenNode);
for (SimpleTree.Node child : this.children) {
copy.children.add(child.copy());
}
return copy;
}
public void normalizeLevels(int level) {
this.level = level;
for (SimpleTree.Node child : children) {
child.normalizeLevels(level + 1);
}
}
public boolean hasChildren() {
return !children.isEmpty();
}
public boolean isLeaf() {
return !hasChildren();
}
public int getChildCount() {
return children.size();
}
public SimpleTree.Node getChild(int index) {
return children.get(index);
}
public int getLevel() {
return level;
}
public String getLabel() {
return label;
}
public boolean isTokenNode() {
return isTokenNode;
}
public List<SimpleTree.Node> getChildren() {
return new ArrayList<>(children);
}
private void traverse(ParseTree parseTree, SimpleTree.Node parent, Parser parser, Set<Integer> ignoredTokenTypes, boolean displaySymbolicName) {
List<SimpleTree.ParseTreeParent> todo = new ArrayList<>();
for (int i = 0; i < parseTree.getChildCount(); i++) {
ParseTree child = parseTree.getChild(i);
if (child.getPayload() instanceof CommonToken) {
CommonToken token = (CommonToken) child.getPayload();
if (!ignoredTokenTypes.contains(token.getType())) {
String tempText = displaySymbolicName ?
String.format("%s: '%s'",
parser.getVocabulary().getSymbolicName(token.getType()),
token.getText()
.replace("\r", "\\r")
.replace("\n", "\\n")
.replace("\t", "\\t")
.replace("'", "\\'")) :
String.format("%s",
token.getText()
.replace("\r", "\\r")
.replace("\n", "\\n")
.replace("\t", "\\t"));
if (parent.label == null) {
parent.label = tempText;
}
else {
parent.children.add(new SimpleTree.Node(tempText, parent.level + 1, true));
}
}
}
else {
SimpleTree.Node node = new SimpleTree.Node(parser.getRuleNames()[((RuleContext)child).getRuleIndex()], parent.level + 1, false);
parent.children.add(node);
todo.add(new SimpleTree.ParseTreeParent(child, node));
}
}
for (SimpleTree.ParseTreeParent wrapper : todo) {
traverse(wrapper.parseTree, wrapper.parent, parser, ignoredTokenTypes, displaySymbolicName);
}
}
#Override
public String toString() {
return String.format("{label=%s, level=%s, isTokenNode=%s, children=%s}", label, level, isTokenNode, children);
}
}
private static class ParseTreeParent {
final ParseTree parseTree;
final SimpleTree.Node parent;
private ParseTreeParent(ParseTree parseTree, SimpleTree.Node parent) {
this.parseTree = parseTree;
this.parent = parent;
}
}
}
And if you paste the output in a DOT viewer, you will get this:
You may also want to look at alternatives. DOT graphs aren't the pretties among possible graph representations. Maybe you like an svg graph instead? If so have a look at the ANTLR4 grammar extension for Visual Studio Code, which generates and exports an svg graphic with the click of a mouse button (and you can style that with own CSS code).
I defined classes Graph containing GraphNode as follows, my intention for declaring N is to compare 2 GraphNode objects using generics.
The question is how shall I instantiate the Graph which is recursively bound.
error while declaring as below.
Graph<Integer,Comparable<GraphNode>> graph = new Graph<>();
Bound mismatch: The type Comparable<GraphNode> is not a valid substitute for the bounded parameter <N extends Comparable<GraphNode<T,N>>> of the type Graph<T,N>
public class Graph<T, N extends Comparable<GraphNode<T, N>>> {
private N root;
private Class<N> clazz;
Graph(Class<N> clazz) {
this.clazz = clazz;
}
public N getInstance() {
try {
return clazz.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
return null;
} catch (IllegalAccessException e) {
e.printStackTrace();
return null;
}
}
#SuppressWarnings("unchecked")
public void insert(T d, N n) {
if (root == null && n == null)
root = getInstance();
if (root == null)
root = n;
N node = root;
while (node != null) {
if (node.equals(n)) {
N newNode = getInstance();
((GraphNode<T, N>) newNode).setAdjNode(newNode);
}
}
}
}
public class GraphNode<T, N extends Comparable<GraphNode<T, N>>> implements Comparable<N> {
private T data;
private LinkedHashSet<N> adjNodes = new LinkedHashSet<>();
GraphNode() {
data = null;
}
GraphNode(T d) {
setData(d);
}
public void setAdjNode(N n) {
adjNodes.add(n);
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
#Override
public int hashCode() {
return data.hashCode();
}
#Override
public boolean equals(Object obj) {
if (obj instanceof GraphNode<?, ?>) {
return ((GraphNode<?, ?>) obj).getData() == this.getData();
}
return false;
}
#Override
public String toString() {
return data + "";
}
#Override
public int compareTo(N o) {
return this.compareTo(o);
}
}
This solved my above problem
public class Graph<T extends Comparable<T>> {
private GraphNode<T> root;
public void insert(T d, GraphNode<T> n) {
if (root == null && n == null)
root = new GraphNode<T>(d);
if (root == null)
root = n;
GraphNode<T> node = root;
Queue<GraphNode<T>> queue = new ConcurrentLinkedQueue<>();
queue.add(root);
while (!queue.isEmpty()) {
node = queue.poll();
node.setNodeColor(color.BLACK);
if (node.equals(n)) {
GraphNode<T> newNode = new GraphNode<T>(d);
((GraphNode<T>) newNode).setAdjNode(newNode);
} else {
queue.addAll(node.getUnexploredAdjNodes());
}
}
}
}
public class GraphNode<T extends Comparable<T>> implements Comparable<GraphNode<T>> {
enum color {
WHITE, GREY, BLACK
};
private T data;
private color nodeColor = color.WHITE;
private LinkedHashSet<GraphNode<T>> adjNodes = new LinkedHashSet<>();
GraphNode() {
data = null;
}
GraphNode(T d) {
setData(d);
}
public void setAdjNode(GraphNode<T> n) {
adjNodes.add(n);
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public LinkedHashSet<GraphNode<T>> getAdjNodes() {
return adjNodes;
}
public LinkedHashSet<GraphNode<T>> getUnexploredAdjNodes() {
LinkedHashSet<GraphNode<T>> n = new LinkedHashSet<>();
for (GraphNode<T> node : adjNodes) {
if (node.getNodeColor() == color.WHITE)
n.add(node);
}
return n;
}
public color getNodeColor() {
return nodeColor;
}
public void setNodeColor(color nodeColor) {
this.nodeColor = nodeColor;
}
#Override
public int hashCode() {
return data.hashCode();
}
#Override
public boolean equals(Object obj) {
if (obj instanceof GraphNode<?>) {
return ((GraphNode<?>) obj).getData() == this.getData();
}
return false;
}
#Override
public int compareTo(GraphNode<T> o) {
return data.compareTo(o.data);
}
#Override
public String toString() {
return data + "";
}
}
Graph<Integer> graph = new Graph<>();
I'm quite new to Java so this is probably pretty straight forward question.
I want to sort an ArrayList in the class MediaLib based on the natural order of a specified key.
I can't work out how to use my comparator (compareTo(MediaInterface, key)) which is in the Media class. Whats the best way to go about this?
package assign1;
import java.util.*;
public class Media implements MediaInterface {
private Map<String, Object> fields;
private static int compare;
public Media(String title, String format) {
fields = new TreeMap<String, Object>();
fields.put("title", title);
fields.put("format", format);
}
public Object get(String key) {
return fields.get(key);
}
public void put(String key, Object value) {
fields.put(key, value);
}
public boolean hasKeywords(String[] words, boolean combineWithAND) {
Collection<Object> values = (Collection<Object>) fields.values();
int count = 0;
int size = 0;
for (String s: words) {
for (Object o: values) {
String t = o.toString();
if (t.indexOf(s) >= 0) {
count++;
break;
}
}
size++;
}
if ((count == 0 && !combineWithAND) || (combineWithAND && (count != size))) {
return false;
}
return true;
}
public int compareTo(MediaInterface mi, String key) { //<<<<<<<------calling this!!
if (mi == null)
throw new NullPointerException();
Media m = (Media) mi;
Comparable mValue = (Comparable) m.get(key);
Comparable lValue = (Comparable) fields.get(key);
if ((mValue == null) && (lValue == null)){
return 0;
}
if ((lValue == null)){
return 1;
}
if ((mValue == null)){
return -1;
}
return (lValue).compareTo(mValue);
}
#Override
public int compareTo(MediaInterface mi) {
if (mi == null)
throw new NullPointerException();
Media m = (Media) mi;
Set<String> lSet = fields.keySet();
if (compareTo(m, "title") != 0) {
return compareTo(m, "title");
}
if (compareTo(m, "year") != 0) {
return compareTo(m, "year");
}
for (String s: lSet) {
if (compareTo(m, s) != 0) {
return compareTo(m, s);
}
}
return 0;
}
public boolean equals(Object object) {
if (object == null)
return false;
if (!(object instanceof Media))
return false;
Media m = (Media) object;
if (compareTo(m) != 0) {
return false;
}
return true;
}
}
package assign1;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
public class MediaLib implements Searchable {
private ArrayList<MediaInterface> media;
public MediaLib() {
media = new ArrayList<MediaInterface>();
}
#Override
public void add(MediaInterface mi) {
if (media.isEmpty()) {
media.add(mi);
}
else {
for (MediaInterface m: media) {
if (mi.equals(m)) {
return;
}
}
media.add(mi);
}
}
#Override
public boolean contains(MediaInterface mi) {
for (MediaInterface m: media) {
if (mi.equals(m)) {
return true;
}
}
return false;
}
#Override
public Collection<MediaInterface> findByKeyword(String[] words, boolean combineWithAND) {
Collection<MediaInterface> foundList = new ArrayList<MediaInterface>();
for (MediaInterface mi: media) {
if (mi.hasKeywords(words, combineWithAND)) {
foundList.add(mi);
}
}
return foundList;
}
#Override
public Collection<MediaInterface> findByTitle(String str) {
Collection<MediaInterface> foundList = new ArrayList<MediaInterface>();
for (MediaInterface mi: media) {
if ((mi.get("title")).equals(str)) {
foundList.add(mi);
}
}
return foundList;
}
#Override
public Collection<MediaInterface> getAllWithFormat(String formatName) {
Collection<MediaInterface> foundList = new ArrayList<MediaInterface>();
for (MediaInterface mi: media) {
if ((mi.get("format")).equals(formatName)) {
foundList.add(mi);
}
}
return foundList;
}
public Collection<MediaInterface> getAll() {
Collection<MediaInterface> fullList = new ArrayList<MediaInterface>();
for (MediaInterface mi: media) {
fullList.add(mi);
}
return fullList;
}
#Override
public void removeAllWithKeyword(String[] words, boolean combineWithAND) {
Collection<MediaInterface> foundList = findByKeyword(words, combineWithAND);
for (MediaInterface mi: foundList) {
media.remove(mi);
}
}
#Override
public void removeAllWithFormat(String format) {
Collection<MediaInterface> foundList = getAllWithFormat(format);
for (MediaInterface mi: foundList) {
media.remove(mi);
}
}
#Override
public void sort() {
Collections.sort(media);
}
#Override
public void sort(final String fieldName) {
Collections.sort(media, new Media.compareTo(MediaInterface, fieldName)) //<<<<<--------Trying to call compareTo()
}
}
public void parse(java.io.BufferedReader br) throws java.io.IOException {
while(br.readLine()!= null) {
Media mi = new Media(/n br.readLine(), br.readLine());
while
}
}
}
You already implement the Comparable interface in your MediaInterface class, this is a generic interface, so you then implement Comparable<MediaInterface> which will then require you to implement a method with the signature
public int compareTo(final MediaInterface other)
This is why your call to Collections.sort(media); compiles
In order to sort by a specific field name, you need to provide an instance of a Comparator, the easiest way to do this will be to create an inner class in your Media class which you can then pass into Collections.sort. For example
public class Media implements MediaInterface {
public static final class FieldComparator implements Comparator<Media> {
private final String field;
public FieldComparator(final String field) {
this.field = field;
}
public int compare(final Media a, final Media b) {
// implementation to compare a.field to b.field
}
}
}
You can then rewrite your second sort method as
#Override
public void sort(final String fieldName) {
Collections.sort(media, new Media.FieldComparator(fieldName));
}
I have an array list that contains Quote objects. I want to be able to sort alphabetically by name, by change, and by percent change. How can I sort my arraylist?
package org.stocktwits.model;
import java.io.Serializable;
import java.text.DecimalFormat;
public class Quote implements Serializable {
private static final long serialVersionUID = 1L;
public String symbol;
public String name;
public String change;
public String percentChange;
public String open;
public String daysHigh;
public String daysLow;
public String dividendYield;
public String volume;
public String averageDailyVolume;
public String peRatio;
public String marketCapitalization;
public String yearHigh;
public String yearLow;
public String lastTradePriceOnly;
public DecimalFormat df = new DecimalFormat("#,###,###,###,###,##0.00");
public DecimalFormat vf = new DecimalFormat("#,###,###,###,###,##0");
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getChange() {
return change;
}
public void setChange(String change) {
if(change.equals("null")){
this.change = "N/A";
}
else{
float floatedChange = Float.valueOf(change);
this.change = (df.format(floatedChange));
}
}
public String getPercentChange() {
return percentChange;
}
public void setPercentChange(String percentChange) {
if(percentChange.equals("null"))
percentChange = "N/A";
else
this.percentChange = percentChange;
}
public String getOpen() {
return open;
}
public void setOpen(String open) {
if(open.equals("null"))
this.open = "N/A";
else
this.open = open;
}
public String getDaysHigh() {
return daysHigh;
}
public void setDaysHigh(String daysHigh) {
if(daysHigh.equals("null"))
this.daysHigh = "N/A";
else{
float floatedDaysHigh = Float.valueOf(daysHigh);
this.daysHigh = (df.format(floatedDaysHigh));
}
}
public String getDaysLow() {
return daysLow;
}
public void setDaysLow(String daysLow) {
if(daysLow.equals("null"))
this.daysLow = "N/A";
else{
float floatedDaysLow = Float.valueOf(daysLow);
this.daysLow = (df.format(floatedDaysLow));
}
}
public String getVolume() {
return volume;
}
public void setVolume(String volume) {
if(volume.equals("null")){
this.volume = "N/A";
}
else{
float floatedVolume = Float.valueOf(volume);
this.volume = (vf.format(floatedVolume));
}
}
public String getDividendYield() {
return dividendYield;
}
public void setDividendYield(String dividendYield) {
if(dividendYield.equals("null"))
this.dividendYield = "N/A";
else
this.dividendYield = dividendYield;
}
public String getAverageDailyVolume() {
return averageDailyVolume;
}
public void setAverageDailyVolume(String averageDailyVolume) {
if(averageDailyVolume.equals("null")){
this.averageDailyVolume = "N/A";
}
else{
float floatedAverageDailyVolume = Float.valueOf(averageDailyVolume);
this.averageDailyVolume = (vf.format(floatedAverageDailyVolume));
}
}
public String getPeRatio() {
return peRatio;
}
public void setPeRatio(String peRatio) {
if(peRatio.equals("null"))
this.peRatio = "N/A";
else
this.peRatio = peRatio;
}
public String getMarketCapitalization() {
return marketCapitalization;
}
public void setMarketCapitalization(String marketCapitalization) {
if(marketCapitalization.equals("null"))
this.marketCapitalization = "N/A";
else
this.marketCapitalization = marketCapitalization;
}
public String getYearHigh() {
return yearHigh;
}
public void setYearHigh(String yearHigh) {
if(yearHigh.equals("null"))
this.yearHigh = "N/A";
else
this.yearHigh = yearHigh;
}
public String getYearLow() {
return yearLow;
}
public void setYearLow(String yearLow) {
if(yearLow.equals("null"))
this.yearLow = "N/A";
else
this.yearLow = yearLow;
}
public String getLastTradePriceOnly() {
return lastTradePriceOnly;
}
public void setLastTradePriceOnly(String lastTradePriceOnly) {
if(lastTradePriceOnly.equals("null")){
this.lastTradePriceOnly = "N/A";
}
else{
float floatedLastTradePriceOnly = Float.valueOf(lastTradePriceOnly);
this.lastTradePriceOnly = (df.format(floatedLastTradePriceOnly));
}
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((change == null) ? 0 : change.hashCode());
result = prime * result
+ ((daysHigh == null) ? 0 : daysHigh.hashCode());
result = prime * result + ((daysLow == null) ? 0 : daysLow.hashCode());
result = prime
* result
+ ((lastTradePriceOnly == null) ? 0 : lastTradePriceOnly
.hashCode());
result = prime
* result
+ ((marketCapitalization == null) ? 0 : marketCapitalization
.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((open == null) ? 0 : open.hashCode());
result = prime * result + ((peRatio == null) ? 0 : peRatio.hashCode());
result = prime * result
+ ((percentChange == null) ? 0 : percentChange.hashCode());
result = prime * result + ((symbol == null) ? 0 : symbol.hashCode());
result = prime * result + ((volume == null) ? 0 : volume.hashCode());
result = prime * result
+ ((yearHigh == null) ? 0 : yearHigh.hashCode());
result = prime * result + ((yearLow == null) ? 0 : yearLow.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Quote other = (Quote) obj;
if (change == null) {
if (other.change != null)
return false;
} else if (!change.equals(other.change))
return false;
if (daysHigh == null) {
if (other.daysHigh != null)
return false;
} else if (!daysHigh.equals(other.daysHigh))
return false;
if (daysLow == null) {
if (other.daysLow != null)
return false;
} else if (!daysLow.equals(other.daysLow))
return false;
if (lastTradePriceOnly == null) {
if (other.lastTradePriceOnly != null)
return false;
} else if (!lastTradePriceOnly.equals(other.lastTradePriceOnly))
return false;
if (marketCapitalization == null) {
if (other.marketCapitalization != null)
return false;
} else if (!marketCapitalization.equals(other.marketCapitalization))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (open == null) {
if (other.open != null)
return false;
} else if (!open.equals(other.open))
return false;
if (peRatio == null) {
if (other.peRatio != null)
return false;
} else if (!peRatio.equals(other.peRatio))
return false;
if (percentChange == null) {
if (other.percentChange != null)
return false;
} else if (!percentChange.equals(other.percentChange))
return false;
if (symbol == null) {
if (other.symbol != null)
return false;
} else if (!symbol.equals(other.symbol))
return false;
if (volume == null) {
if (other.volume != null)
return false;
} else if (!volume.equals(other.volume))
return false;
if (yearHigh == null) {
if (other.yearHigh != null)
return false;
} else if (!yearHigh.equals(other.yearHigh))
return false;
if (yearLow == null) {
if (other.yearLow != null)
return false;
} else if (!yearLow.equals(other.yearLow))
return false;
return true;
}
}
If you (almost) always want to use that order you can add the Comparable interface to Quote and implement a compareTo method.
public int compareTo(Quote quote) {
int result = this.getName().compareTo(quote.getName());
if (result == 0) {
result = this.getChange().compareTo(quote.getChange());
}
if (result == 0) {
result = this.getPercentChange().compareTo(quote.getPercentChange());
}
return result;
}
Then use a sorted collection, or sort a list, and the quotes will be sorted.
For ad hoc sorting, a separate, possibly anonymous, Comparator is better.
Everybody is right that you want to use Comparators. Extending on that idea, if you want to be able to sort on multiple criteria, then a class like this will work for you:
public class MultiComparator<T> implements Comparator<T> {
private List<Comparator<T>> comparators;
public MultiComparator(List<Comparator<T>> comparators) {
this.comparators = comparators;
}
public int compare(T o1, T o2) {
for (Comparator<T> comparator : comparators) {
int comparison = comparator.compare(o1, o2);
if (comparison != 0) return comparison;
}
return 0;
}
}
Then you just write really simple comparators for whichever fields you desire and you can combine them into more complex comparators more easily and with more reuse.
Have a look at the ComparatorChain from the Apache Commons Collection. This should do the job. Don't implement logic if is already available and tested.
At the following site I have a tutorial: Sorting Objects By Multiple Attributes"
Create an appropiate Comparator that will compare two items according to your desired criteria. Then use Collections.sort() on your ArrayList.
If at a later time you want to sort by different criteria, call Collections.sort() again with a different Comparator.
Sun has devoted big part of its tutorial to sorting in Java collections:
http://download.oracle.com/javase/tutorial/collections/interfaces/order.html
It discusses both Comparable and Comparator interfaces with examples.
See Collections.sort with an explicit Comparator (or the Collections.sort kind that requires the input to implement Comparable, if you prefer).
There are two things:
Sorting on multiple fields of an object
Multilevel sorting (Here sorting done on first field and then next sorting applied on grouping done on similar items in previous sort)
For #2: I found this below article very much close to what i desire
http://strangeoptics.blogspot.com/2011/09/sorting-objects-by-multiple-attributes.html