I am having a problem where a method from another class is not being recognized as existing by Eclipse, even though all the other methods are. I have no idea why this is happening, and cannot figure it out. I get the error The method getData() is undefined for the type TMXReader.TMXHandler when I try doing this:
package tiled.simple.reader;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import tiled.simple.core.Map;
import tiled.simple.core.MapLayer;
import tiled.simple.core.TileSet;
import davidiserovich.TMXLoader.TMXHandler;
import davidiserovich.TMXLoader.TileMapData;
TMXHandler handler = new TMXHandler();
handler.getData();
Here is the TMXHandler class:
package davidiserovich.TMXLoader;
import java.util.HashMap;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
//import android.sax.StartElementListener;
public class TMXHandler extends DefaultHandler {
/*
* This is an SAX2 XML parser that interprets the input TMX file and creates
* a TileMapData object.
*/
// NOTE: Map Object loading is not yet implemented
// Markers for which tag we're in
private boolean inTileSet, inTile, inLayer, inData, inObjectGroup,
inProperties;
// ID of the current tile that we're adding properties to.
// This is actually an OFFSET from firstGID of the tile in
// the tileset. Beware.
private String currentTileID;
private String currentObjectGroupName;
TileMapData.TMXObject currentObject;
TileMapData.TileSet currentTileSet;
TileMapData.Layer currentLayer;
HashMap<String, HashMap<String, String>> currentTileSetProperties;
HashMap<String, String> currentLayerProperties;
private TileMapData data;
/*
* These fields hold the buffer and data to help decode the long stream of
* gids in the data field
*/
private char buffer[];
private int bufferIndex;
private int currentX;
private int currentY;
public int MAX_INT_DECIMAL_LENGTH = 10;
public TMXHandler() {
super();
buffer = new char[MAX_INT_DECIMAL_LENGTH];
bufferIndex = 0;
currentX = 0;
currentY = 0;
}
public TileMapData getData() {
return data;
}
#Override
public void startDocument() throws SAXException {
data = new TileMapData();
}
#Override
public void endDocument() throws SAXException {
}
#Override
public void startElement(String namespaceURI, String localName,
String qName, Attributes atts) throws SAXException {
if (localName.equals("map")) {
// inMap = true;
// Check that the orientation is orthogonal
if (!(atts.getValue("orientation").equals("orthogonal"))) {
throw new SAXException(
"Unsupported orientation. Parse Terminated.");
}
data.orientation = atts.getValue("orientation");
data.height = Integer.parseInt(atts.getValue("height"));
data.width = Integer.parseInt(atts.getValue("width"));
data.tilewidth = Integer.parseInt(atts.getValue("tilewidth"));
data.tileheight = Integer.parseInt(atts.getValue("tileheight"));
// data.sectionId = atts.getValue("id");
} else if (localName.equals("tileset")) {
inTileSet = true;
currentTileSet = new TileMapData.TileSet();
currentTileSet.firstGID = Integer.parseInt(atts
.getValue("firstgid"));
currentTileSet.tileWidth = Integer.parseInt(atts
.getValue("tilewidth"));
currentTileSet.tileHeight = Integer.parseInt(atts
.getValue("tileheight"));
currentTileSet.name = atts.getValue("name");
currentTileSetProperties = new HashMap<String, HashMap<String, String>>();
} else if (inTileSet && localName.equals("image")) {
currentTileSet.ImageFilename = atts.getValue("source");
currentTileSet.imageWidth = Integer
.parseInt(atts.getValue("width"));
currentTileSet.imageHeight = Integer.parseInt(atts
.getValue("height"));
} else if (inTileSet && localName.equals("tile")) {
inTile = true;
currentTileID = atts.getValue("id");
} else if (inTile && localName.equals("properties")) {
inProperties = true;
currentTileSetProperties.put(currentTileID,
new HashMap<String, String>());
} else if (inLayer && localName.equals("properties")) {
inProperties = true;
} else if (inTile && inProperties && localName.equals("property")) {
(currentTileSetProperties.get(currentTileID)).put(
atts.getValue("name"), atts.getValue("value"));
} else if (inLayer && inProperties && localName.equals("property")) {
currentLayerProperties.put(atts.getValue("name"),
atts.getValue("value"));
} else if (localName.equals("layer")) {
inLayer = true;
currentLayer = new TileMapData.Layer();
currentLayer.name = atts.getValue("name");
currentLayer.width = Integer.parseInt(atts.getValue("width"));
currentLayer.height = Integer.parseInt(atts.getValue("height"));
if (atts.getValue("opacity") != null)
currentLayer.opacity = Double.parseDouble(atts
.getValue("opacity"));
currentLayer.tiles = new long[currentLayer.height][currentLayer.width];
currentLayerProperties = new HashMap<String, String>();
} else if (localName.equals("data")) {
/*
* Data is loaded directly into the int array in characters() We
* just check if the encoding is supported here.
*/
inData = true;
String encoding = atts.getValue("encoding");
if (!encoding.equals("csv")) {
throw new SAXException(
"Unsupported encoding. Parse Terminated.");
}
} else if (localName.equals("objectgroup")) {
inObjectGroup = true;
currentObjectGroupName = atts.getValue("name");
} else if (localName.equals("object")) {
currentObject = new TileMapData.TMXObject();
currentObject.name = atts.getValue("name");
currentObject.type = atts.getValue("type");
currentObject.x = Integer.parseInt(atts.getValue("x"));
currentObject.y = Integer.parseInt(atts.getValue("y"));
currentObject.width = Integer.parseInt(atts.getValue("width"));
currentObject.height = Integer.parseInt(atts.getValue("height"));
if (inObjectGroup) {
currentObject.objectGroup = currentObjectGroupName;
} else {
currentObject.objectGroup = null;
}
}
}
#Override
public void endElement(String namespaceURI, String localName, String qName)
throws SAXException {
if (localName.equals("map")) {
// inMap = false;
} else if (localName.equals("tileset")) {
inTileSet = false;
currentTileSet.properties = currentTileSetProperties;
currentTileSetProperties = null;
data.tilesets.add(currentTileSet);
currentTileSet = null; // Clear it just in case
} else if (localName.equals("tile")) {
inTile = false;
currentTileID = "-1"; // -1 won't be produced when searching for
// properties. Just a safeguard for
// improperly formatted files.
} else if (localName.equals("properties")) {
inProperties = false;
} else if (localName.equals("layer")) {
inLayer = false;
currentLayer.properties = currentLayerProperties;
data.layers.add(currentLayer);
currentLayer = null; // Clear it just in case
} else if (localName.equals("data")) {
inData = false;
// In case we missed the last entry (no non-numeral chars before tag
// end)
if (bufferIndex > 0) {
currentLayer.tiles[currentY][currentX] = Long
.parseLong(new String(buffer, 0, bufferIndex));
}
// Clear buffer
bufferIndex = 0;
currentX = 0;
currentY = 0;
} else if (localName.equals("objectgroup")) {
inObjectGroup = false;
} else if (localName.equals("object")) {
data.objects.add(currentObject);
}
}
#Override
public void characters(char ch[], int start, int length) {
/*
* Java has no unsigned types, so we have to use a long instead of an
* int so we can "simulate" an unsigned int. Disgusting. Anyway, we're
* going to add the numbers from the character stream to a buffer until
* we hit a comma, at which point we empty the buffer and convert it to
* a long, and dump it into the array. These are raw, so the horizontal
* and vertical flip bits may be set - to get the actual GID number,
* we'll use TileMapData's getGIDAt(x, y), which will mask it properly.
*/
if (inData) {
for (int i = 0; i < length; i++) {
if (ch[start + i] <= '9' && ch[start + i] >= '0') {
buffer[bufferIndex] = ch[start + i];
// Log.d("Wrote to index", String.valueOf(bufferIndex));
bufferIndex++;
} else {
// When we hit a comma or any non-number character, empty
// the buffer and enter the relevant
// GID into the data field
// int what = Integer.parseInt(new String(buffer, 0,
// bufferIndex));
// Log.d("Number", new String(buffer, 0, bufferIndex));
String nextNumber = new String(buffer, 0, bufferIndex);
if ((nextNumber != null) && ((nextNumber.trim()) != "")
&& (bufferIndex != 0)) {
// Log.d("Checking", nextNumber + " yes");
currentLayer.tiles[currentY][currentX] = Long
.parseLong(nextNumber);
bufferIndex = 0;
// Move to the next tile
if (currentX < (currentLayer.width - 1)) {
currentX++;
} else if (currentY < (currentLayer.height - 1)) {
currentX = 0;
currentY++;
}
}
}
}
}
}
}
Auto-complete shows all the other methods as usable, but for some reason getData "doesn't exist"...
I'm sure this is apparent for experienced Java programmers, but I have no idea why this is happening... so if anyone could tell me why, I'd be grateful. Thanks!
Change this:
TMXHandler handler = new TMXHandler;
To this:
TMXHandler handler = new TMXHandler();
EDIT
If it's just a typo issue... and if your question is complete... You may have forgot to put it in a class ? :<
import davidiserovich.TMXLoader.TMXHandler;
public class Main {
public static void main(String[] args) {
TMXHandler handler = new TMXHandler();
handler.getData();
}
}
You have to create object. You have forget ()
TMXHandler handler = new TMXHandler();
Are you sure the java code which is referring TMXHandler class have correct TMXHandler.class file in Runtime. This may be caused by old TMXHandler.class which dont have getData() method defined.
maybe try a clean build
TMXHandler handler = new TMXHandler;
The above line is the culprit.
- When we call new on a Class name its always accompanied by () as postfix, which indicates the constructor of the class whose object is now created on the heap.
- And this line gives the opportunity to step in, to initialize the state of the object before the Actual object is assigned to the Object reference variable.
So it should be....
TMXHandler handler = new TMXHandler();
I solved it... turns out that the one project already had a class named TMXHandler, so it was referring to that, and not my other project... A very stupid mistake. :
Related
I am using an apache lucene built in token filter called "PatternCaptureGroupTokenFilter." Basically, I am creating an elasticsearch plugin and needed this token filter for fulfilling a use case.
The text on which I want to use this token filter is "https://www.google.com/". The regex that I am using with the "PatternCaptureGroupTokenFilter" is
"(?\<!\[^\\p{Punct}\])(\\p{Punct}\\p{Alnum}+\\p{Punct})"
The expected tokens in this case are:
/www., .google., .com/
But, I am only getting the "/www."
I did a little research about this issue on StackOverflow itself and found out that it can be solved using the find() and group() methods. But, inside my token filter factory file I didn't saw any scope of doing that as I'm directly importing it inside my file.
The code inside my java file looks like:
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.pattern.PatternCaptureGroupTokenFilter;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.index.IndexSettings;
import org.elasticsearch.index.analysis.AbstractTokenFilterFactory;
import java.util.regex.Pattern;
public class PuAlPuTokenFilterFactory extends AbstractTokenFilterFactory {
public PuAlPuTokenFilterFactory(IndexSettings indexSettings, Environment environment, String name, Settings settings) {
super(indexSettings, name, settings);
}
#Override
public TokenStream create(TokenStream tokenStream) {
return new PatternCaptureGroupTokenFilter(tokenStream, true, Pattern.compile("(?<![^\\p{Punct}])(\\p{Punct}\\p{Alnum}+\\p{Punct})"));
}
}
So, I went to the code inside the PatternCaptureGroupTokenFilter file in the Official Apache lucene project. The code in that file is below:
package org.apache.lucene.analysis.pattern;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.lucene.analysis.TokenFilter;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
import org.apache.lucene.util.CharsRefBuilder;
public final class PatternCaptureGroupTokenFilter extends TokenFilter {
private final CharTermAttribute charTermAttr = addAttribute(CharTermAttribute.class);
private final PositionIncrementAttribute posAttr = addAttribute(PositionIncrementAttribute.class);
private State state;
private final Matcher[] matchers;
private final CharsRefBuilder spare = new CharsRefBuilder();
private final int[] groupCounts;
private final boolean preserveOriginal;
private int[] currentGroup;
private int currentMatcher;
public PatternCaptureGroupTokenFilter(TokenStream input,
boolean preserveOriginal, Pattern...patterns) {
super(input);
this.preserveOriginal = preserveOriginal;
this.matchers = new Matcher[patterns.length];
this.groupCounts = new int[patterns.length];
this.currentGroup = new int[patterns.length];
for (int i = 0; i < patterns.length; i++) {
this.matchers[i] = patterns[i].matcher("");
this.groupCounts[i] = this.matchers[i].groupCount();
this.currentGroup[i] = -1;
}
}
private boolean nextCapture() {
int min_offset = Integer.MAX_VALUE;
currentMatcher = -1;
Matcher matcher;
for (int i = 0; i < matchers.length; i++) {
matcher = matchers[i];
if (currentGroup[i] == -1) {
currentGroup[i] = matcher.find() ? 1 : 0;
}
if (currentGroup[i] != 0) {
while (currentGroup[i] < groupCounts[i] + 1) {
final int start = matcher.start(currentGroup[i]);
final int end = matcher.end(currentGroup[i]);
if (start == end || preserveOriginal && start == 0 &&
spare.length() == end) {
currentGroup[i]++;
continue;
}
if (start < min_offset) {
min_offset = start;
currentMatcher = i;
}
break;
}
if (currentGroup[i] == groupCounts[i] + 1) {
currentGroup[i] = -1;
i--;
}
}
}
return currentMatcher != -1;
}
#Override
public boolean incrementToken() throws IOException {
if (currentMatcher != -1 && nextCapture()) {
assert state != null;
clearAttributes();
restoreState(state);
final int start = matchers[currentMatcher]
.start(currentGroup[currentMatcher]);
final int end = matchers[currentMatcher]
.end(currentGroup[currentMatcher]);
posAttr.setPositionIncrement(0);
charTermAttr.copyBuffer(spare.chars(), start, end - start);
currentGroup[currentMatcher]++;
return true;
}
if (!input.incrementToken()) {
return false;
}
char[] buffer = charTermAttr.buffer();
int length = charTermAttr.length();
spare.copyChars(buffer, 0, length);
state = captureState();
for (int i = 0; i < matchers.length; i++) {
matchers[i].reset(spare.get());
currentGroup[i] = -1;
}
if (preserveOriginal) {
currentMatcher = 0;
} else if (nextCapture()) {
final int start = matchers[currentMatcher]
.start(currentGroup[currentMatcher]);
final int end = matchers[currentMatcher]
.end(currentGroup[currentMatcher]);
// if we start at 0 we can simply set the length and save the copy
if (start == 0) {
charTermAttr.setLength(end);
} else {
charTermAttr.copyBuffer(spare.chars(), start, end - start);
}
currentGroup[currentMatcher]++;
}
return true;
}
#Override
public void reset() throws IOException {
super.reset();
state = null;
currentMatcher = -1;
}
}
I was thinking of directly using the code of the 'PatternCaptureGroupTokenFilter' inside my token filter and use it as required. I tried to add the find() and group() functionality in the code but finding a little difficult to put the code at the required place.
I am trying to save a javafx.scene.shape.Path to a file (at least its elements) however since Path is non-serializable and its PathElement as well it has proven very difficult.
Could someone inform me of a way to either convert the object to a String (preferred), JSON or something else?
Here are all the ways I have tried saving the object:
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import javafx.scene.shape.Path;
import javafx.scene.shape.Polygon;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.Shape;
class Test {
public static void main(String[] args) {
GsonBuilder builder = new GsonBuilder();
Path path;
Gson gson = builder.create();
{
Rectangle rectangle = new Rectangle(100, 100);
Polygon polygon = new Polygon(0, 0, 50, 50, 0, 50);
path = (Path) Shape.subtract(rectangle, polygon);
}
try {
String completePathObject = gson.toJson(path);
System.out.println(completePathObject);
} catch (IllegalArgumentException e) {
e.printStackTrace();
// java.lang.IllegalArgumentException: class com.sun.javafx.util.WeakReferenceQueue$ListEntry declares multiple JSON fields named next
}
try {
String pathObjectElements = gson.toJson(path.getElements());
System.out.println(pathObjectElements);
} catch (IllegalArgumentException e) {
e.printStackTrace();
// java.lang.IllegalArgumentException: class com.sun.javafx.util.WeakReferenceQueue$ListEntry declares multiple JSON fields named next
}
try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("test.set"))) {
objectOutputStream.writeObject(path);
} catch (IOException e) {
e.printStackTrace();
// java.io.NotSerializableException: javafx.scene.shape.Path
}
try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("test.set"))) {
objectOutputStream.writeObject(path.getElements());
} catch (IOException e) {
e.printStackTrace();
// java.io.NotSerializableException: javafx.scene.shape.Path$2
}
}
}
Nodes contain a lot of properties you'd need to convert to a form that can be written to a file.
Since your last attempt indicates you'll be satisfied with writing the path elements to the file, you could convert the PathElements to parts of a SVG path and also implement logic for parsing the elements PathElements from a svg path string.
The following doesn't accept all possible SVG paths and may accept some invalid paths:
public class SVGConverter {
private enum PathElementType {
ARC('a', ArcTo.class, ArcTo::new,
ArcTo::radiusXProperty,
ArcTo::radiusYProperty,
ArcTo::XAxisRotationProperty,
ArcTo::largeArcFlagProperty,
ArcTo::sweepFlagProperty,
ArcTo::xProperty,
ArcTo::yProperty),
CLOSE_PATH('z', ClosePath.class, ClosePath::new),
CUBIC_CURVE('c', CubicCurveTo.class, CubicCurveTo::new,
CubicCurveTo::controlX1Property,
CubicCurveTo::controlY1Property,
CubicCurveTo::controlX2Property,
CubicCurveTo::controlY2Property,
CubicCurveTo::xProperty,
CubicCurveTo::yProperty),
H_LINE_TO('h', HLineTo.class, HLineTo::new,
HLineTo::xProperty),
LINE_TO('l', LineTo.class, LineTo::new,
LineTo::xProperty, LineTo::yProperty),
MOVE_TO('m', MoveTo.class, MoveTo::new,
MoveTo::xProperty, MoveTo::yProperty),
QUAD_CURVE_TO('q', QuadCurveTo.class, QuadCurveTo::new,
QuadCurveTo::controlXProperty, QuadCurveTo::controlYProperty,
QuadCurveTo::xProperty, QuadCurveTo::yProperty),
V_LINE_TO('v', VLineTo.class, VLineTo::new,
VLineTo::yProperty);
private final char letter;
private final String typeName;
private final Supplier<? extends PathElement> factory;
private final Function[] propertyGetters;
<T extends PathElement> PathElementType(char letter, Class<T> type, Supplier<T> factory, Function<T, ? extends Property<?>>... propertyGetters) {
this.letter = letter;
this.typeName = type.getName();
this.factory = factory;
this.propertyGetters = propertyGetters;
}
}
private final Map<String, PathElementType> ELEMENT_TYPES_BY_TYPE;
private final Map<Character, PathElementType> ELEMENT_TYPES_BY_LETTER;
public SVGConverter() {
ELEMENT_TYPES_BY_LETTER = new HashMap<>();
ELEMENT_TYPES_BY_TYPE = new HashMap<>();
for (PathElementType et : PathElementType.values()) {
ELEMENT_TYPES_BY_LETTER.put(et.letter, et);
ELEMENT_TYPES_BY_TYPE.put(et.typeName, et);
}
}
public String pathToSvg(Path path) {
StringBuilder sb = new StringBuilder();
for (PathElement element : path.getElements()) {
PathElementType elementType = ELEMENT_TYPES_BY_TYPE.get(element.getClass().getName());
if (elementType == null) {
throw new IllegalArgumentException("Unknown PathElement type: " + element.getClass().getName());
}
// specify path element type
char c = elementType.letter;
if (element.isAbsolute()) {
c = Character.toUpperCase(c);
}
sb.append(c);
// write property values
for (Function f : elementType.propertyGetters) {
Property property = (Property) f.apply(element);
sb.append((property instanceof BooleanProperty)
// special treatment for booleans to convert true/false to 1/0
? (((BooleanProperty) property).get() ? "1" : "0")
: property.getValue().toString()).append(' ');
}
}
// trim, if necessary
int lastIndex = sb.length() - 1;
if (lastIndex >= 0 && sb.charAt(lastIndex) == ' ') {
sb.deleteCharAt(lastIndex);
}
return sb.toString();
}
private static final String NUMBER_PATTERN_STRING = "[+-]?\\d*\\.\\d*(?:[eE][+-]?\\d+)?";
private static final Pattern NUMBER_PATTERN = Pattern.compile("(?<![\\d.+-])(" + NUMBER_PATTERN_STRING + ')');
private static final Pattern SVG_PATTERN = Pattern.compile("([aAcChHlLvmMqQVzZ])((?:\\s*" + NUMBER_PATTERN_STRING + "(?:[\\s,]+" + NUMBER_PATTERN_STRING + ")*)?)");
// parses doubles from number sequence
private static double[] getNumberMatches(Matcher m, int count) {
double[] result = new double[count];
for (int i = 0; i < count; i++) {
if (!m.find()) {
throw new IllegalArgumentException("missing numbers");
}
result[i] = Double.parseDouble(m.group(1));
}
if (m.find()) {
throw new IllegalArgumentException("too many numbers");
}
return result;
}
public Path svgToPath(String svg) {
Path path = new Path();
Matcher matcher = SVG_PATTERN.matcher(svg);
while (matcher.find()) {
// find out path element type
char c = matcher.group(1).charAt(0);
PathElementType elementType = ELEMENT_TYPES_BY_LETTER.get(Character.toLowerCase(c));
if (elementType == null) {
throw new IllegalArgumentException("Unknown path type " + c);
}
PathElement element = (PathElement) elementType.factory.get();
element.setAbsolute(Character.isUpperCase(c));
// retrieve parameters
if (elementType.propertyGetters.length > 0) {
Matcher numberMatcher = NUMBER_PATTERN.matcher(matcher.group(2));
double[] numbers = getNumberMatches(numberMatcher, elementType.propertyGetters.length);
for (int i = 0; i < elementType.propertyGetters.length; i++) {
Property property = (Property) elementType.propertyGetters[i].apply(element);
property.setValue((property instanceof BooleanProperty)
? (numbers[i] == 1) // convert to boolean (true iff 1.0)
: numbers[i]);
}
}
path.getElements().add(element);
}
return path;
}
}
Note: This does not restore any kind of bindings that may have existed before converting to string of course.
Summary:
My Jsoup parser works perfectly on its own, but fails to gather any values once copy-pasted into one of my Android application's AsyncTask task classes. The 2d array is returned filled with nothing but nulls.
Long version:
I have been working on an application that uses page-scraping via Jsoup to pull and display content from various blogs. I have written a few parsers so far, and all seem to work as expected. Unfortunately, my most recent parser (written for nyc-shows.brooklynvegan.com), has been having issues.
Here is the parser method itself, invoked by a main method with print statements added. Run this yourself. It works (not perfectly, but it works).
import java.io.IOException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
public class Main {
static String TAG_EVENT = "li.ds-entry";
static String TAG_TITLE = ".ds-entry-title";
static String TAG_LOCATION = ".location";
static String TAG_DATE_AND_TIME = ".ds-date";
static String TAG_TICKET_URL = ".ds-buy-tickets";
static String FEED_URL = "http://nyc-shows.brooklynvegan.com/";
public static void main(String[] args) throws IOException {
String values[][] = new String[50][6];
values = getFeedItems();
for (int i=0; i<values.length; i++) {
for (int j=0; j<6; j++) {
System.out.println(values[i][j]);
}
System.out.println("-----------------");
}
}
public static String[][] getFeedItems() throws IOException {
Document doc = null;
String values[][] = new String[50][6];
try{
doc = Jsoup.connect(FEED_URL).timeout(0).get();
Elements events = doc.select(TAG_EVENT);
String delimSpace = "[ ]";
int i = 0;
for (Element event : events) {
//Set event title
Element title = event.select(TAG_TITLE).first();
String titleString = title.text();
if (title != null) {
boolean isFake = checkFake(titleString);
if (!isFake) {
values[i][0] = titleString;
}
else {
continue;
}
}
//Set event date and time i guess
Element dateAndTime = event.select(TAG_DATE_AND_TIME).first();
if (dateAndTime != null) {
String[] dateAndTimeTokens = dateAndTime.text().split(delimSpace);
String date = dateAndTimeTokens[1];
String time = dateAndTimeTokens[3];
values[i][1] = date;
values[i][2] = time;
}
//Set price (tbd)
values[i][3] = "See Ticket";
//Set location
Element location = event.select(TAG_LOCATION).first();
if (location != null) {
values[i][4] = location.text();
}
//Set ticket urls
Element ticketContainer = event.select(TAG_TICKET_URL).first();
if (ticketContainer != null) {
String ticket = ticketContainer.select("a").attr("href");
values[i][5] = ticket;
}
else {
values[i][3] = "Free";
}
i++;
} //End of event loop
} //End of try clause
catch (IOException e) {
e.printStackTrace();
}
return values;
}
public static boolean checkFake(String s) {
boolean isFake = false;
String[] days = {"Today", "Tomorrow", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
for (int i=0; i<days.length; i++) {
if (s.contains(days[i])) {
isFake = true;
return isFake;
}
}
return isFake;
}
}
Now, here is the same exact method transported into an AsyncTask to be run in the background by my application while a loading screen is displayed.
package com.example.nylist;
import java.io.IOException;
import android.app.Activity;
import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.Toast;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
public class BVParser extends AsyncTask<Void, Void, String[][]> {
static String TAG_EVENT = "li.ds-entry";
static String TAG_TITLE = ".ds-entry-title";
static String TAG_LOCATION = ".location";
static String TAG_DATE_AND_TIME = ".ds-date";
static String TAG_TICKET_URL = ".ds-buy-tickets";
static String FEED_URL = "http://nyc-shows.brooklynvegan.com/";
Context context;
Activity activity;
public BVParser(Activity context) {
this.context = context.getApplicationContext();
this.activity = context;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
Toast.makeText(context, "Fetching...", Toast.LENGTH_LONG).show();
}
#Override
protected String[][] doInBackground(Void... param) {
String values[][] = new String[50][6];
try {
values = getFeedItems();
}
catch (IOException e) {
Log.d("ASSERT", "Exception occured during doInBackground", e);
e.printStackTrace();
}
Log.d("ASSERT", ("values successfully returned by doInBackground, first title is: "+values[0][0]));
return values;
}
protected void onPostExecute(String[][] result) {
super.onPostExecute(result);
int eventCount = result.length;
Log.d("ASSERT", ("event count in onPostExecute is: "+eventCount));
ListRow[] listrow_data = new ListRow[eventCount];
ListRow temp;
for (int i=0; i<eventCount; i++) {
if (result[i] != null) {
temp = new ListRow(context, result[i][0], result[i][1], result[i][2],
result[i][3], result[i][4], result[i][5], i);
listrow_data[i] = temp;
}
}
((EventList) activity).setList(listrow_data);
}
public String[][] getFeedItems() throws IOException {
Document doc = null;
String values[][] = new String[50][6];
int i = 0;
try{
Log.d("ASSERT","Made it to try block");
doc = Jsoup.connect(FEED_URL).timeout(0).get();
Elements events = doc.select(TAG_EVENT);
Log.d("ASSERT","printing events, whatever it is: "+events);
String delimSpace = "[ ]";
//******THIS LOOP NEVER BEGINS*****//
for (Element event : events) {
Log.d("ASSERT","Made it to getFeedItems's main for loop");
//Set event title
Element title = event.select(TAG_TITLE).first();
String titleString = title.text();
Log.d("ASSERT","This title is: "+titleString);
boolean isFake = checkFake(titleString);
if (!isFake) {
values[i][0] = titleString;
}
else {
continue;
}
//Set event date and time i guess
Element dateAndTime = event.select(TAG_DATE_AND_TIME).first();
if (dateAndTime != null) {
String[] dateAndTimeTokens = dateAndTime.text().split(delimSpace);
String date = dateAndTimeTokens[1];
String time = dateAndTimeTokens[3];
values[i][1] = date;
values[i][2] = time;
}
//Set price
values[i][3] = "See Ticket";
//Set location
Element location = event.select(TAG_LOCATION).first();
if (location != null) {
values[i][4] = location.text();
}
//Set ticket urls
Element ticketContainer = event.select(TAG_TICKET_URL).first();
if (ticketContainer != null) {
String ticket = ticketContainer.select("a").attr("href");
values[i][5] = ticket;
}
else {
values[i][3] = "Free";
}
i++;
} //End of event loop
} //End of try clause
catch (IOException e) {
Log.d("ASSERT","Exception during getFeedItems");
e.printStackTrace();
}
Log.d("ASSERT","The first title in getFeedItems before returning is: "+values[0][0]);
return values;
}
private static boolean checkFake(String s) {
boolean isFake = false;
String[] days = {"Today", "Tomorrow", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
for (int i=0; i<days.length; i++) {
if (s.contains(days[i])) {
isFake = true;
return isFake;
}
}
return isFake;
}
}
Debugging Attempts:
I added log statements throughout the code in order to debug the problem. If you run this, you will see that the problem seems to occur somewhere within getFeedItems() itself, specifically within the "try" block. Although the log statement at the beginning of the try statement appears, the for loop that runs through events isn't running at all, because the log statement at it's beginning never prints.
Question:
Can someone explain why the loop through events doesn't begin? Is events null, and if so, why? Why is there a discrepancy between the method running on it's own and the method running within my AsyncTask? I have been tearing my hair out. The logic in this parser is almost identical to the logic in the (working) others that I have written, and yet this is returning a 2d array with nothing but nulls. I have trouble even beginning to understand where the logic error might be, and yet I just can't seem to find the typo.
PS:
If comparing this with my other parser would help, let me know and I'll post the source. Thanks in advance.
In the following program I'm inserting
files[i].lastModified() value in allFiles HashMap in RThread class
when I tried to retrive the value of lastModified from allFiles HashMap in the main class the value is coming as null. So instead of lastModified value I placed File object directly in HashMpa then it worked.
Anyone guide me the concept behind this.
import java.io.File;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
public class RCFLister {
ConcurrentHashMap allFiles = new ConcurrentHashMap();
String fileType = null;
/**
* #param args
*/
public static void main(String[] args) {
RCFLister rcFileLister = new RCFLister();
rcFileLister.recentFiles(args);
}
public void recentFiles(String[] args) {
int days = 1;
ThreadGroup rootthreadGr = new ThreadGroup("rootsThreadGroup");
// reading number of days
if (args.length > 0 && args[0] != null) {
days = Integer.valueOf(args[0]);
}
// reading file type
if (args.length > 0 && args[0] != null) {
fileType = args[1];
}
fileType = "png";
// fileextFilter = new FileExtensionFilter(fileType);
File[] roots = File.listRoots();
List threads = new ArrayList();
for (int i = 0; i < roots.length; i++) {
// System.out.println(roots[i].getAbsolutePath());
// rfThread = null;
RThread rfThread = new RThread(roots[i]);
Thread t = new Thread(rfThread);
t.start();
threads.add(t);
}
for (int i = 0; i < threads.size(); i++) {
try {
((Thread) threads.get(i)).join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
ValueComparator vc = new ValueComparator(allFiles);
TreeMap sortedMap = new TreeMap(vc);
sortedMap.putAll(allFiles);
System.out.println(sortedMap.size());
Iterator it = sortedMap.keySet().iterator();
while (it.hasNext()) {
Object key = it.next();
System.out.println(key + " " + sortedMap.get(key));
}
}
private class ValueComparator implements Comparator {
Map allFiles;
public ValueComparator(Map allFiles) {
this.allFiles = allFiles;
}
public int compare(Object o1, Object o2) {
if (((Long) allFiles.get(o1)) >= ((Long) allFiles.get(o2))) {
return -1;
} else {
return 1;
}
}
}
private class RThread implements Runnable {
File rootFolder;
RThread(File root) {
rootFolder = root;
}
public void run() {
getFiles(rootFolder);
}
public void getFiles(File folder) {
File[] files = folder.listFiles();
for (int i = 0; files != null && i < files.length; i++) {
// System.out.println(files[i].getAbsolutePath());
if (files[i].isDirectory()) {
getFiles(files[i]);
} else if (fileType == null
|| (fileType != null && files[i].getName().endsWith(
fileType))) {
String filename = null;
try {
filename = files[i].getCanonicalPath();
} catch (Exception e) {
e.printStackTrace();
}
if(files[i].lastModified()!=0)
allFiles.put(filename, files[i].lastModified());
}
}
}
}
}
compare() method of ValueComparator never returns 0. Return 0 means equality which is missing so even if key is present it is not found.
Also the key is String(filename) and you are comparing by value (long). Need to rethink how you want to store data.
Just to make sure it is only problem, print CocurrentHashMap.
Do use Generic, it looks tedious at beginning but is really not that bad. It will help to compiler code without warning and achieve type safety.
I have a class in Java which is written bellow.I want to know does that has normal size or it is big and huge and should be broken into some pieces:
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.SAXException;
public class AddressTree
{
private AddressNode structureRoot, userRoot;
private String xmlAddress;
public AddressTree(String XMLaddress)
{
this.xmlAddress = XMLaddress;
createEmptyTree();
startParsing();
}
private void startParsing()
{
AddressXMLParser handler = new AddressXMLParser(this);
try
{
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
File xml = new File(xmlAddress);
parser.parse(xml, handler);
ArrayList<AddressNode> rawNodes = createRawNodes(handler.getAddressStructure());
createTreeFromRawNodes(rawNodes, handler.getStartItem());
for (int i = 0; i < handler.getFinalItems().size(); i++)
{
getAddressNode(handler.getFinalItems().get(i), structureRoot).setIsFinal(true);
}
}
catch (StartAddressNodeNotFoundException ex)
{
Logger.getLogger(AddressTree.class.getName()).log(Level.SEVERE, null, ex);
}
catch (ParserConfigurationException ex)
{
}
catch (SAXException ex)
{
}
catch (IOException ex)
{
}
}
private void createEmptyTree()
{
structureRoot = new AddressNode("root", null);
userRoot = new AddressNode("root", null);
}
public void setValue(String nodeName, String value) throws AddressNodeNotFoundException
{
AddressNode node = getAddressNode(nodeName, userRoot);
if (node != null)
{
node.setNodeValue(value);
}
else
{
throw new AddressNodeNotFoundException();
}
}
public ArrayList<String> getCompleteAddress()
{
return null;
}
public boolean isAddressCompleted()
{
AddressNode iterator = userRoot;
while (iterator.getAllChilds().size() != 0)
{
iterator = iterator.getAllChilds().get(0);
}
if (getAddressNode(iterator.getNodeName(), structureRoot).isFinal())
{
return true;
}
else
{
return false;
}
}
public List<String> getSubAddressItems(String addressItem)
{
ArrayList<String> subAddressItems = new ArrayList<String>();
List<AddressNode> childNodes = getAddressNode(addressItem, structureRoot).getAllChilds();
for (int i = 0; i < childNodes.size(); i++)
{
subAddressItems.add(childNodes.get(i).getNodeName());
}
return subAddressItems;
}
private AddressNode getAddressNode(String nodeName, AddressNode root)
{
ArrayList<AddressNode> graphNodes = new ArrayList<AddressNode>();
ArrayList<AddressNode> passedNodes = new ArrayList<AddressNode>();
graphNodes.add(root);
while (graphNodes.size() != 0)
{
AddressNode cureNode = graphNodes.remove(0);
passedNodes.add(cureNode);
if (cureNode.getNodeName().equals(nodeName))
{
return cureNode;
}
else
{
for (int i = 0; i < cureNode.getAllChilds().size(); i++)
{
if (!passedNodes.contains(cureNode.getAllChilds().get(i)))
{
graphNodes.add(cureNode.getAllChilds().get(i));
}
}
}
}
return null;
}
private ArrayList<AddressNode> createRawNodes(TreeMap<String, ArrayList<String>> addressStructure)
{
int itemsSize = addressStructure.size();
ArrayList<AddressNode> tmpNodes = new ArrayList<AddressNode>();
ArrayList<AddressNode> finalNodes = new ArrayList<AddressNode>();
for (int i = 0; i < itemsSize; i++)
{
String curKey = addressStructure.firstKey();
ArrayList<String> curSubItems = addressStructure.remove(curKey);
AddressNode curNode = new AddressNode(curKey);
finalNodes.add(new AddressNode(curKey));
for (int j = 0; j < curSubItems.size(); j++)
{
curNode.addChlid(curSubItems.get(j));
}
tmpNodes.add(curNode);
}
for (int i = 0; i < finalNodes.size(); i++)
{
for (int j = 0; j < tmpNodes.get(i).getAllChilds().size(); j++)
{
AddressNode childNode = null;
boolean existNodeBefore = false;
for (int k = 0; k < finalNodes.size(); k++)
{
if (finalNodes.get(k).getNodeName().equals(tmpNodes.get(i).getAllChilds().get(j).getNodeName()))
{
childNode = finalNodes.get(k);
existNodeBefore = true;
}
}
if (!existNodeBefore)
{
finalNodes.get(i).addChlid(tmpNodes.get(i).getAllChilds().get(j).getNodeName());
}
else
{
finalNodes.get(i).addChildNode(childNode);
}
}
}
return finalNodes;
}
private void createTreeFromRawNodes(ArrayList<AddressNode> rawNodes, String rootName) throws StartAddressNodeNotFoundException
{
if (rootName == null)
{
throw new StartAddressNodeNotFoundException();
}
for (int i = 0; i < rawNodes.size(); i++)
{
if (rawNodes.get(i).getNodeName().equals(rootName))
{
structureRoot.addChildNode(rawNodes.get(i));
rawNodes.get(i).setParent(structureRoot);
}
}
}
public void addAddressItem(String itemName) throws AddressStructureAbusingException
{
AddressNode iterator = userRoot;
while (iterator.getAllChilds().size() > 0)
{
iterator = iterator.getAllChilds().get(0);
}
AddressNode fatherNode = getAddressNode(iterator.getNodeName(), structureRoot);
for (int i = 0; i < fatherNode.getAllChilds().size(); i++)
{
if (fatherNode.getAllChilds().get(i).getNodeName().equals(itemName))
{
iterator.addChlid(itemName);
return;
}
}
throw new AddressStructureAbusingException();
}
public void removeLastAddressItem() throws AddressNodeNotFoundException
{
if (userRoot.getAllChilds().size() > 0)
{
AddressNode iterator = userRoot;
while (iterator.getAllChilds().get(0).getAllChilds().size() > 0)
{
iterator = iterator.getAllChilds().get(0);
}
iterator.clearChilds();
}
else
{
throw new AddressNodeNotFoundException();
}
}
}
if it has to be broken how?
Your class has 230 lines - that's by no means excessive. However, size alone is only a very vague indicator of whether a class should be broken up.
A more general indicator is cohesion - basically, most of a class's methods should be using most of its fields. But that also isn't a problem in your class - it looks OK.
it has several responsibilites as I can see:
XML parsing (the representation)
XML manipulation (AddressNode)
hold parsing's output (the model)
at least I separate these two responsabilities in at least two separated classes.
NB
not concerned by the question there are also several empty catch blocks, see here why they are a bad idea
I've certainly seen bigger classes than that.
If you're finding it hard to read, I suggest strongly recommend putting some comments in there.
As long as your class revolves around a specific purpose, it should be as big as it needs to be to perform that purpose.
You may want to adapt
if (foo) {
bar();
} else {
fum();
}
instead. This allows the code to be shorter in length, allowing you to see more at once on the screen.
Also. Never have empty catch blocks. Consider "throw new RuntimeException("unexpected", e)" in them.