I'm trying to fill a TableView with the data from a csv-file with the datafx extension.
Unfortunately the tableview is empty and I'm not able to find any example anywhere which indicates my mistake.
DataSourceReader dsr1 = new FileSource("Example3.csv");
CSVDataSource ds1 = new CSVDataSource(dsr1);
TableView table1 = new TableView();
table1.setItems(ds1.getData());
table1.getColumns().addAll(ds1.getColumns());
System.out.println("#ds1 " + ds1.getData().size()); //returns zero
The code does not throw an exception, which makes it even more mysterious.
even though the question is to fill the TableView with the DataFX extension here is a solution without DataFX:
Create a class that represents a list item of your tableView e.g.:
public class YourItem {
private String itemID;
private String itemTitle;
public String getItemID() {
return itemID;
}
public void setitemID(String itemID) {
this.itemID = itemID;
}
//getter and setter for the other vars, I am lazy. }
Parse your csv file and return a List<YourItem>
there are several tutorials and examples for that, you can find one here:
http://www.mkyong.com/java/how-to-read-and-parse-csv-file-in-java/ Important is that you create a List of YourItem objects where each row is a YourItem object
Convert your List<YourItem> into an ObservableList<YourItem>
ObservableList<YourItem> obsList = FXCollections.observableArrayList(yourList);
finally set the items to your TableView:
I won't mention that you need to create Columns for your TableView
TableView<YourItem> test = new TableView<YourItem>();
test.setItems(obsList);
Related
I'm using Java 8 and jackson to try and get an int value from a json object. Here is some similar code I used to verify the structure.
HashMap<String, Object> myMap = new HashMap<String, Object>();
myMap
.entrySet()
.stream()
.forEach(x -> System.out.println(x.getKey() + " => " + x.getValue()));
and the result:
myKey1 => {"number":1}
myKey2 => {"number":1}
myKey3 => {"number":2}
What I'm trying to do is use the key, like myKey1 to find the json value i.e. {"number":1} and pull out the actual number, which for that key is 1.
However, I don't all know the values of the key's, just the key I want to match up. So I have to do this dynamically. I know the structure of the values and that is always the same, except the number can be different.
I think because I don't know the keys and their order, plus I'm using entrySet, that is forcing me into using Optional, which is making this more difficult.
Here is my code where I'm actually using the key to pull the json value:
Optional<Object> object = myMap.entrySet().stream()
.filter(e -> e.getKey().equals(myKey))
.map(Map.Entry::getValue)
.findFirst();
However, the stream pulls back
Optional[{"number":1}]
and I can't seem to get the number out so I can return it from a method. I don't actually
have a Java class for the object, so I assume that is why it's returning Optional as I was getting a compile error without it, but I'm not sure.
Any ideas as to the right way to do this?
Why iterating over all the entries of the map and do a linear search by key, to get the value of the entry?
Just get the value directly:
Object value = myMap.get(myKey);
Now, with regard to the number inside value, as you say you don't have a class that represents the values of the map, the most likely thing is that the JSON library you're using is creating a Map for each value. So from now on, let's assume that the values are actually some implementation of Map:
Integer = null;
if (value != null) {
// What's the type of the value? Maybe a Map?
if (value instanceof Map) {
Map<String, Object> valueAsMap = (Map<String, Object>) value;
number = (Integer) valueAsMap.get("number");
}
}
I'm assuming the numbers are Integers, but they can perfectly be Long instances or even Doubles or BigDecimals. Just be sure of the exact type, so the second cast doesn't fail.
EDIT: For completeness, here's the code for when the values are not maps, but of some class that represents a json node. Here I'm using JsonNode from Jackson library, but the approach is very similar for other libs:
Integer = null;
if (value != null) {
if (value instanceof JsonNode) {
JsonNode valueAsNode = (JsonNode) value;
number = (Integer) valueAsNode.get("number").numberValue();
}
}
findFirst() returns an Optional. You need to call .get() or .orElse() or .orElseThrow() after you call findFirst().
You can then cast the Object to JsonNode and retrieve the value. Here is the full code:-
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
HashMap<String, Object> myMap = new HashMap<String, Object>();
myMap.put("myKey1", mapper.readTree("{\"number\":1}"));
myMap.put("myKey2", mapper.readTree("{\"number\":1}"));
myMap.put("myKey3", mapper.readTree("{\"number\":2}"));
System.out.println(getNumberUsingMapKey(myMap, "myKey3"));
}
private static int getNumberUsingMapKey(Map<String, Object> map, String key) throws Exception {
return Optional.of(map.get(key))
.map(o -> ((JsonNode) o).get("number").asInt())
.get(); //or use one of the following depending on your needs
// .orElse(-1);
// .orElseThrow(Exception::new);
}
//or use this method
private static int getNumberUsingMapKeyWithoutOptional(Map<String, Object> map, String key) throws Exception {
Object o = map.get(key);
return ((JsonNode) o).get("number").asInt();
}
Output
2
Unfortunately I didn't describe my problem statement well from the start, but this is the final working code that I was able to piece from the other answers.
This is what the data structure looked like. A key that had a value which was a JSON object that had a key and an int, in other words a nested JSON object.
Key: myKey1 Value:{"number":1}
Key: myKey2 Value:{"number":1}
Key: myKey3 Value:{"number":2}
I'm posting it in case some else runs into this use case. This may not be the best way to do it, but it works.
Object value = myMap.get(keyName);
ObjectMapper mapper = new ObjectMapper();
String jsonString = (String) value;
JsonNode rootNode = mapper.readTree(jsonString);
JsonNode numberNode = rootNode.path("number");
System.out.println("number: " + numberNode.intValue());
and the result:
number: 1
This is with the Docusign Rest api. When I call ToJson() on an EnvelopeDefinition, it returns the correct info, but I would like it to not serialize the base64 array for when I am writing this out to a log file. I tried using the [JsonIgnore] directive, but that stopped the array from being serialized altogether. Do I need to override the Serialize method on this class or just create another method, something like ToJsonForLogging() and not serialize that array?
I have created an extension method that will work for you. You can call this extension method in your code as follows
string json = envelopeDefinition.ToJsonLog(logDocumentBase64:false)
I am copying the DocumentBase64 into a temporary List and then using .ToJson() function to log without the documentBase64 property.
public static class EnvelopeDefinitionExtensions
{
public static string ToJsonLog(this EnvelopeDefinition envDefinition, bool logDocumentBase64 = true)
{
if (logDocumentBase64) return envDefinition.ToJson();
var tempDocumentBase64List = new List<string>();
foreach(var doc in envDefinition.Documents)
{
tempDocumentBase64List.Add(doc.DocumentBase64);
doc.DocumentBase64 = null;
}
string json = envDefinition.ToJson();
int i =0;
foreach(var doc in envDefinition.Documents)
{
doc.DocumentBase64 = tempDocumentBase64List[i];
i++;
}
return json;
}
}
I wonder if this is possible.
I have a huge json file to parse and modify.
But not all fields are interresting to me : I wan't to map only fields I'm interrested in, modify them then save the whole json with all fields I didn't care left unchanged.
Then suppose I have lot of properties and only one I'm interrested in named "MyProp", I tried something like
public class MyMapper extends HashMap {
private String myProp;
public void setMyProp(String myProp) {
this.myProp = myProp;
}
public String getMyProp() {
return myProp;
}
}
But the property "MyProp" is always null (until I remove "extends HashMap").
Instead all goes in the map.
Wouldn't be useful (or is it already possible ?) to be able to mix concrete fields with maps to work with known fields without loosing unknowns ?
And it would be better to did not extend HashMap but instead having a field to hold all unknown fields like this :
public class MyMapper {
private String myProp;
private Map remaining = new HashMap();
public void setMyProp(String myProp) {
this.myProp = myProp;
}
public String getMyProp() {
return myProp;
}
#JsonRemaining
public Map getRemaining() {
return remaining;
}
}
How would you do in this case ?
Seems like #JsonAnySetter and #JsonAnyGetter annotations might help. All irrelecant proerpties get stuffed into one Map and then the map contents get dumped back to json
See how-to guide here
http://vincentdevillers.blogspot.co.il/2013/08/how-to-map-unknown-json-properties-with.html
Can I turn data contract attributes off and on dynamically? Essentially, I'd like two data contracts, one between the 3rd party and my app, and one between my app and my client - without having to manage two DTO classes. For example, consider MyDTO:
[DataContract]
public class MyDTO
{
[DataMember(Name = "Lame/3rdParty/Inbound/Key")]
public string MyCoolOutboundKey { get; set; }
}
I'd like to deserialize the DTO with ServiceStack.Text:
MyDTO dto = "{\"Lame/3rdParty/Inbound/Key\":\"CoolValue\"}".FromJson<MyDTO>();
But, I'd like to serialize it so that this Assertion would be true:
Assert.AreEqual("{\"MyCoolOutboundKey\":\"CoolValue\"}",dto.ToJson());
The actual object in question has over hundred properties, so I'm hoping to avoid having to create a second class just to allow for outbound serialization.
So, there is nothing wrong with your approach, but I think you are underestimating the power of JsonObject, it's kinda like LINQ to JSON.
I used it to get geo data from Google Maps and map it to a nice little DTO:
var jsonObj = jsonFromGoogleMaps.FromJson<JsonObject>();
return (
from x in jsonObject.Get<JsonArrayObjects>("results")
let geo = x.Get("geometry")
let loc = geo.Get("location")
return new Coords
{
Lat = x.Get<decimal>("lat"),
Lng = x.Get<decimal>("lng"),
}
).FirstOrDefault();
OK - it's pretty well established that you cannot change attributes at runtime.
An alternative that would create an end-run around the entire issue, would be to pre-process the incoming json, replacing the keys according to a map, i.e.:
Dictionary<String,String> map = new Dictionary<String,String>();
map.Add("Lame/3rdParty/Inbound/Key","MyCoolOutboundKey");
JsonObject result = new JsonObject();
JsonObject obj = jsonObject.Parse("{\"Lame/3rdParty/Inbound/Key\":\"CoolValue\"}");
foreach (var entry in obj)
{
entry.Key = map[entry.Key];
result[entry.Key] = entry.Value;
}
Assert.AreEqual("{\"MyCoolOutboundKey\":\"CoolValue\"}",result.ToJson());
This way the only data contract I'd require would be the one between my app and my app's clients.
I'm starting out with GXT and am a bit confused on how to use the JsonReader to parse a valid json string with multiple root objects. I have a set of selection boxes to build the sql statement to display records in a grid. I'm getting the values for the selections from the database as well. What I'm attempting to do is a single request to my php database functions to build the json with all the values for the selection boxes in one string. My first thought was the JsonReader.
Here's an example of the json I'm working with:
"categories":[{"id":"1","value":"categoryValue1"},{"id":"2","value":"categoryValue2"}], "frequencies":[{"id":"1","value":"frequencyValue1"},{"id":"2","value":"frequencyValue2"}]
Building off the cityList example in the api, this is what I've got so far.
JsonRootObject interface:
public interface JsonRootObject {
List<SelectionProperties> getCategories();
List<SelectionProperties> getFrequencies();
}
JsonRootObjectAutoBeanFactory:
public interface JsonRootObjectAutoBeanFactory extends AutoBeanFactory {
AutoBean<JsonRootObject> jsonRootObject();
}
I created a SelectionProperties interface as all are single int/string value pairs:
public interface SelectionProperties {
String getId();
String getValue();
}
Now, according to the api:
// To convert from JSON data, extend a JsonReader and override
// createReturnData to return the desired type.
So I created a reader for both categories and frequencies;
CategoryReader:
public class CategoryReader
extends
JsonReader<ListLoadResult<SelectionProperties>, JsonRootObject> {
public CategoriesReader(AutoBeanFactory factory, Class<JsonRootObject> rootBeanType) {
super(factory, rootBeanType);
}
protected ListLoadResult<SelectionProperties> createReturnData(Object loadConfig, JsonRootObject incomingData) {
return new ListLoadResultBean<SelectionProperties>(incomingData.getCategories());
}
}
FrequencyReader:
public class FrequencyReader extends
JsonReader<ListLoadResult<SelectionProperties>, net.apoplectic.testapps.client.JsonRootObject> {
public FrequencyReader(AutoBeanFactory factory, Class<JsonRootObject> rootBeanType) {
super(factory, rootBeanType);
}
protected ListLoadResult<SelectionProperties> createReturnData(Object loadConfig, JsonRootObject incomingData) {
return new ListLoadResultBean<SelectionProperties>(incomingData.getFrequencies());
}
}
This doesn't feel quite right. I'm creating multiple instances of basically the same code and parsing the actual json string twice (at this point. I may have more options for the grid once I dig in). My question is am I missing something or is there a more efficient way to parse the response string? From my onSuccessfulResponse:
JsonRootObjectAutoBeanFactory factory = GWT.create(JsonRootObjectAutoBeanFactory.class);
CategoryReader catReader = new CategoriesReader(factory, JsonRootObject.class);
FrequencyReader freqReader = new FrequenciesReader(factory, JsonRootObject.class);
categories = catReader.read(null, response);
frequencies = freqReader.read(null, response);
List<SelectionProperties> categoriesList = categories.getData();
List<SelectionProperties> frequenciesList = frequencies.getData();
ListBox cateBox = new ListBox(false);
ListBox freqBox = new ListBox(false);
for (SelectionProperties category : categoriesList )
{
cateBox.addItem(category.getValue(), category.getId());
}
for (SelectionProperties frequency : frequenciesList)
{
freqBox.addItem(frequency.getValue(), frequency.getId());
}
The above does work, both the ListBoxes are populated correctly. I just wonder if this is the correct approach. Thanks in advance!