How can i return the URL using fetchCurrentURL in Vaadin - java

If im using fetchCurrentURL in Vaadin like that:
UI.getCurrent().getPage().fetchCurrentURL(url -> Notification.show(url.getPath()));
to get a Notification at the website with the current URL of the page as String, how then i can get this value back, i want something like:
String s = UI.getCurrent().getPage().fetchCurrentURL(url -> Notification.show(url.getPath()));
???

I don't know, if this is the right way in vaadin app, but as a workaround you can somewhat abuse mutable objects to achieve it.
class MutableObject {
private String value;
//getter,setter
}
Instantiate it outside the lambda and set the value inside the function:
MutableObject mutableObject = new MutableObject();
UI.getCurrent().getPage().fetchCurrentURL(url -> mutableObject.setValue(url.getPath()));
System.out.println(mutableObject.getValue());

Related

Return dynamic or union type from lambda in Java

I'm returning to Java after having been away for a very, very long time, and I'm trying to do in Java the sort of thing that I've often done in Javascript or Typescript. But I can't figure it out.
I'm trying to create a mapping between two different systems to easily map types and copy values from one system to the other. The systems are Neo4j and Excel, although my question doesn't really have anything to do with either of those. Basically the idea is that users can export data from Neo4j to an Excel sheet, edit values there, and then import it again. (I know! It's a terrible idea! But they really want it and we can blame them if they mess up.)
Still, at the very least I'd like them to not change the types of data in neo4j properties, so I'm building a fairly strict mapping:
public enum Neo4jExcelDataTypeMapping {
STRING("String", cell -> cell.getStringCellValue()),
INTEGER("Integer", cell -> cell.getNumericCellValue()),
FLOAT("Float", cell -> cell.getNumericCellValue()),
BOOLEAN("Boolean", cell -> cell.getBooleanCellValue()),
STRING_ARRAY("String[]",
cell -> Neo4jExcelDataTypeMapping.deserializeArrayToString(cell.getStringCellValue()),
value -> serializeArray((Object[]) value)
),
DATE("Date",
cell -> LocalDate.parse(cell.getStringCellValue()),
value -> ((LocalDate)value).format(DateTimeFormatter.ISO_LOCAL_DATE)),
);
interface ExcelCellReader {
Object readValue(Cell cell);
}
interface ExcelCellWriter {
Object writeValue(Object value);
}
public final String className;
public final ExcelCellReader excelCellReader;
public final ExcelCellWriter excelCellWriter;
private Neo4jExcelDataTypeMapping(String className, ExcelCellReader excelCellReader) {
this.className = className;
this.excelCellReader = excelCellReader;
this.excelCellWriter = value -> value;
}
private Neo4jExcelDataTypeMapping(String className, ExcelCellReader excelCellReader, ExcelCellWriter excelCellWriter) {
this.className = className;
this.excelCellReader = excelCellReader;
this.excelCellWriter = excelCellWriter;
}
public static Neo4jExcelDataTypeMapping fromNeo4jType(String type) {
for (Neo4jExcelDataTypeMapping instance : Neo4jExcelDataTypeMapping.values()) {
if (instance.className.equals(type)) {
return instance;
}
}
return null;
}
}
(I'm leaving out the serialization/deserialization of arrays in a readable manner, because that's a whole separate issue.)
This code seems fine. The IDE doesn't complain about it at least. But then I try to use it in a unit test:
#Test
public void testStringMapping() {
String testString = "Test String";
VirtualNode node = new VirtualNode(1);
node.setProperty("test", testString);
Cell cell = row.createCell(0);
String neo4jType = node.getProperty("test").getClass().getSimpleName();
Neo4jExcelDataTypeMapping mapping = Neo4jExcelDataTypeMapping.fromNeo4jType(neo4jType);
cell.setCellValue(mapping.excelCellWriter.writeValue(node.getProperty("test")));
}
Here, the problem is that cell.setCellValue() expects a specific type. It's heavily overloaded, so it can accept String, Integer, Float, various Dates, and more. But not Object. Now all the objects I'm returning from my lambda will be one of those types, but the lambda itself says it's returning an Object, and Java doesn't like that.
In TypeScript, I might have it return String|Integer|Float|Date, but you can't do that in Java. Is it possible to do this with generics somehow?
I don't want to explicitly cast in cell.setCellValue((String)mapping.excelCellWriter.writeValue(node.getProperty("test"))); because this is just going to be a single line that should work for all data types. I wrote the enum exactly to handle this, but it can't seem to handle this one final cast. I suspect some generic type magic could do it, but I never really mastered that aspect of Java.
(Also: I'm not a fan of the excelWriter.writeValue(). Is there a way to make excelWriter() both a property of the enum and the function that's called? Or is that too JavaScript of me?)

Using Jsoup Elements.select() with Optional.ifPresent

Forgive me for the beginner question. I'm trying to build a web scraper . I made a helper class Selectors to store CSS selectors of different type and the class has a getter method that returns a optional field value:
public Optional<String> getName() {
return Optional.ofNullable(this.name);
}
In my main Scraper class I have a method to extract the name from the HTML using the Selectors object like this:
public String extractName(Element building) {
if (this.selectors.getName().isPresent()) {
String cssSelector = this.selectors.getName().get();
Elements buildingNameElement = building.select(cssSelector);
return buildingNameElement.text();
}
return "N/A";
}
As much as I've read this isn't a very nice way to use the Optional class. But I'm struggling to come up with a better solution. My first thought was to use the ifPresent method but it does not work in this manner:
public String extractName(Element building) {
this.selectors.getName().ifPresent(() -> {
String cssSelector = this.selectors.getName().get();
Elements buildingNameElement = building.select(cssSelector);
return buildingNameElement.text();
});
return "N/A";
}
I'd like that the Elements.select() would execute only if there's a name field present in the Selectors object. Could anyone help me make the code a bit more functional?
Thanks!
public String extractName(Element building) {
return this.selectors
.getName()
.map(cssSelector -> {
Elements buildingNameElement = building.select(cssSelector);
return buildingNameElement.text();
})
.orElse("N/A");
}
This is what Optional.map is for. When you do return inside a lambda, you are only returning from the lambda, not from the outer method. So the above uses the text of the building name element if getName returned a name/selector. And returns N/A if not.
If you’re fine with a more condensed syntax and fewer named variables, you may go with the following:
return this.selectors
.getName()
.map(cssSelector -> building.select(cssSelector).text())
.orElse("N/A");
Disclaimer: I haven’t got JSoup on my computer, so I haven’t tested. Please forgive if there’s a typo, and report back.

getting the values of array from javascript to java as list

var catids = new Array();
I have a catids array where i store the checked checkbox values like the below one.
cat = $("input[name=catChkBox]:checked").map(function () {
return $(this).data('name');
}).get().join(",");
the cat variable forms something like this 1,2,3..
I want to send this "cat" to a java method and print those values.
I pass the values to java through a dwr call like this
DataHandler.getTasks( categories, {callback:function(data){
}, errorHandler:function(){
},async:false
});
I have configured dwr for pojo. should I configure anything for parameters?
I tried the below code but I didn't get anything.
public List<Facade> getTasks(String myIds){
String[] ids = catids .split(",");
System.out.println("-------size of cat id------------" + myIds.length);
for (int i=0; i<myIds.length;i++)
System.out.println(myIds[i]);
//finally it will return a pojo which i l be receiving it in data of dwr call.
-------size of cat id------------ is 1
myIds[i] prints nothing
I need it as an integer back.
What mistake am I doing ?
I will do it in this way.
JavaScript creates json object like this {"categoryIds": [1,2,3,4,5]}
Java converter convert json to java POJO object using for example Gson or Jackson library.
After convert you can work with java POJO object which have list of categories.
If you use this solution your code will be more clear and you will be able to share more objects between JavaScript and Java using the same clear solution.
Example (pseudo code)
CategorList class
public class CategoryList {
private ArrayList<Category> categoryList;
// getters and setters
}
Converter
public class CategoryListConverter {
public CategoryList convert(String json) {
Gson g = new Gson();
CategoryList cl = g.fromJson(json, CategoryList.class);
return cl;
}
}
I tried the code it workd fine
getTasks("1,2,3");
check what the value of categoriesIds is sent to getTask
Send this as a form parameter from webpage. Then get this from HttpServletRequest request object in java.
request.getParameter('categoryId');

How do bind indexed property to jface viewer

I want to bind an indexed property to JFace ComboViewer.
Lets say that I have a DataModel class like this:
class DataModel {
private String[] props = {"A","B","C"};
private PropertyChangeSupport pcs = new PropertyChangeSupport(this);
public String getProperties( int idx ){
return props[idx];
}
public void setProperties( int idx, String value ){
String oldVal = props[idx];
props[idx] = value;
pcs.fireIndexedPropertyChange( "properties", idx, oldVal, value );
}
// code to add/remove PropertyChangeListener
// ...
}
The data binding code for simple property would look like this:
DataModel dataModel = ...
ComboViewer propertyChoice = ...
DataBindingContext ctx = new DataBindingContext();
IObservableValue target = ViewerProperties.singleSelection().observe( propertyChoice );
IObservableValue model = BeanProperties.value( DataModel.class, "properties" ).observe(dataModel);
ctx.bindValue( target, model );
but with an indexed property I have to inform the ctx at which index is the value that I want to bind. I have tried
IObservableValue model = BeanProperties.value( DataModel.class, "properties[0]" ).observe(dataModel);
but it doesn't work.
Is it possible to bind indexed property instead of simple property? How?
Unfortunately this seems to be unsupported. I was looking for exactly the same functionality. There is no documentation in BeanProperties that says it is supported.
When looking into the implementation of BeanProperties.value, you find that it delegates to BeanPropertyHelper for reading and writing a property. The method Object readProperty(Object source, PropertyDescriptor propertyDescriptor) does not know about the subclass IndexedPropertyDescriptor. When it is invoked for an indexed property, readProperty tries to use a read method that reads the entire array. I think this method is optional for indexed properties. For indexed properties it should use the IndexedPropertyDescriptor.getIndexedReadMethod().
Depending on your use case you may be able to workaround the problem by using BeanProperties.list. However you cannot use this in combination with indexed properties. I tried this by adding a method that returns the entire array but still keeping the method that does a "fireIndexedPropertyChange". Unfortunately this gives a ClassCastException: Eclipse's BeanListProperty seems to suppose that the value in the change event is an array or list. However for an indexed property it is a single element of the array.
Or perhaps you can use an observable map instead?

Determining a String based on the value of another String?

Not all that sure how I would describe this question, so I'll jump right into the example code.
I have a Constants.java
package com.t3hh4xx0r.poc;
public class Constants {
//RootzWiki Device Forum Constants
public static final String RWFORUM = "http://rootzwiki.com/forum/";
public static final String TORO = "362-cdma-galaxy-nexus-developer-forum";
public static String DEVICE;
}
In trying to determine the device type, I use this method.
public void getDevice() {
Constants.DEVICE = android.os.Build.DEVICE.toUpperCase();
String thread = Constants.(Constants.DEVICE);
}
Thats not correct though, but thats how I would think it would have worked.
Im setting the Constants.DEVICE to TORO in my case on the Galaxy Nexus. I want to then set the thread String to Constants.TORO.
I dont think I'm explaining this well, but you shoudl be able to understand what I'm trying to do fromt he example code. I want
Constants.(VALUE OF WHAT CONSTANTS.DEVICE IS) set for the String thread.
Another way to put it,
I want to get Constants.(//value of android.os.Build.DEVICE.toUpperCase())
I apologies for the poorly worded question, i dont know of any better way to explain what Im trying to achieve.
Im trying to determine the thread based on the device type. I could go in and do an
if (Constants.DEVICE.equals("TORO"){
String thread = Constants.TORO;
}
But I plan on adding a lot more device options in the future and would like to make it as easy as adding a string to the Constants.java rather than having to add another if clause.
I would suggest using an enum instead of just strings - then you can use:
String name = android.os.Build.DEVICE.toUpperCase();
// DeviceType is the new enum
DeviceType type = Enum.valueOf(DeviceType.class, name);
You can put the value of the string in a field for the enum, and expose it via a property:
public enum DeviceType {
RWFORUM("http://rootzwiki.com/forum/"),
TORO("362-cdma-galaxy-nexus-developer-forum");
private final String forumUrl;
private DeviceType(String forumUrl) {
this.forumUrl = forumUrl;
}
public String getForumUrl() {
return forumUrl;
}
}
(I'm guessing at the meaning of the string value - not a great guess, but hopefully it gives the right idea so you can make your actual code more meaningful.)
EDIT: Or to use a map:
Map<String, String> deviceToForumMap = new HashMap<String, String>();
deviceToForumMap.put("RWFORUM", "http://rootzwiki.com/forum/");
deviceToForumMap.put("TORO", "362-cdma-galaxy-nexus-developer-forum");
...
String forum = deviceToForumMap.get(android.os.Build.DEVICE.toUpperCase());
You can use reflection:
Constants.DEVICE = android.os.Build.DEVICE.toUpperCase();
String thread = (String) Constants.class.getField(Constants.DEVICE).get(null);
Not sure I've understood the question properly, but I feel that it's a right place to use a Map. The outcome will be something like this:
HashMap<String, String> map;
map.put(TORO, DEVICE);
Constants.DEVICE = android.os.Build.DEVICE.toUpperCase();
String thread = map.get(Constants.DEVICE);
Sorry for a possible misunderstanding or your question, but I hope you've got the idea.
P.S. You can find more info about Maps in the Java documentation: Map, HashMap.

Categories