Java beans binding: adapters? - java

Here's a really simple class:
static public class Bean1
{
final private String name;
final private Bean1 parent;
private int favoriteNumber;
public String getName() { return this.name; }
public Bean getParent() { return this.parent; }
public int getFavoriteNumber() { return this.favoriteNumber; }
public void setFavoriteNumber(int i) { this.favoriteNumber = i; }
}
What I would like to do is to bind some UI components to a BeanAdapter<Bean1> (see com.jgoodies.binding.beans.BeanAdapter) so that if the BeanAdapter points to Bean1 bean1, then I can display
bean1.name (blank if null)
bean1.parent.name (blank if null or if bean1.parent is null)
bean1.favoriteNumber
The fields name and favoriteNumber are easy, but I'm confused about how to display the parent name. It looks like BeanAdapter only lets me bind to properties which exist directly in Bean1. But this is poor modularity and it forces me to add getter/setter functions every time I want to bind to a new aspect of the bean.
What I would like to do is write a helper class which knows how to access a bean, and am confused how to get it to work properly with Bean1 and BeanAdapter.
I'm sorry if this question is not more clear, I don't know the vocabulary and am a little hazy on the concepts of binding.

The problem here is that binding works in both ways: from model to ui, and from ui to model.
In your case, how would you deal with someone entering information for the first time in a textfield that's binded to parent.name? Would you create a parent on the fly? Would you give an error?
If you know what to do in that situation (e.g. create a parent with that name), you could use a com.jgoodies.binding.value.AbstractConverter to convert a Bean1 to a String:
public class ParentNameConverter extends AbstractConverter {
/**
* Converts a value from the subject to the type or format used
* by this converter.
*
* #param subjectValue the subject's value
* #return the converted value in the type or format used by this converter
*/
public Object convertFromSubject(Object subjectValue) { ... }
/**
* Sets a new value on the subject, after converting to appropriate type
* or format
*
* #param newValue the ui component's value
*/
public void setValue(Object newValue) { ... }
}
You can use this converter the same way you use a normal ValueModel:
Bindings.bind(uifield,"value",
new ParentNameConverter(beanAdapter.getValueModel("parent")));

Related

Order YAML file entries according to its java equivalent class (SnakeYaml)

I am using SnakeYaml to both load/dump data in Java. For this I have created a custom class with fields, say that the class looks something like this:
public class Person {
private String name;
private String lastName;
private String address;
public Person() {
// Do nothing
}
// Getters and setters initialized for all the fields
}
Now, what I would like is that when I write a Person object to a file with SnakeYaml I would want to have the fields in the order they are defined in the class.
e.g.
name: Patrick
lastName: Star
Age : 42
The problem is that for more advanced examples, this ordering is not achieved. Currently I am writing/dumping to a yaml file like the following:
Constructor struct = new Constructor(YamlIteratorModel.class);
Yaml yaml = new Yaml(struct);
try {
String path = "Some/File/Path/yamlfile.yaml";
FileWriter writer = new FileWriter(path);
yaml.dump(iteratorModel, writer);
} catch (IOExcepton e) {
// Do something
}
What I have also tried is creating a Representer class which extends Representer and calls the Yaml constructor in a similar manner. This one is taken from another post, and it doesn't do the job for me as it only sorts the Properties in an order I am not entirely sure of (can't find the link right now but will update if I find it again)..
public class ConfigurationModelRepresenter extends Representer {
/**
* Create object without specified dumper object
*/
public ConfigurationModelRepresenter() {
super();
}
/**
* Create object with dumper options
*
* #param options
*/
public ConfigurationModelRepresenter(DumperOptions options) {
super(options);
}
/** {#inheritDoc} */
#Override
protected Set<Property> getProperties(Class< ? extends Object> type) {
Set<Property> propertySet;
if (typeDefinitions.containsKey(type)) {
propertySet = typeDefinitions.get(type).getProperties();
} else {
propertySet = getPropertyUtils().getProperties(type);
}
List<Property> propsList = new ArrayList<>(propertySet);
Collections.sort(propsList, new BeanPropertyComparator());
return new LinkedHashSet<>(propsList);
}
class BeanPropertyComparator implements Comparator<Property> {
#Override
public int compare(Property p1, Property p2) {
// p1.getType().get
if (p1.getType().getCanonicalName().contains("util") && !p2.getType().getCanonicalName().contains("util")) {
return 1;
} else if (p2.getName().endsWith("Name") || p2.getName().equalsIgnoreCase("name")) {
return 1;
} else {
return -1;
}
}
}
}
SUMMARY: How do I maintain the ordering when dumping an object to a YAML file (using SnakeYaml) e.g. the order the fields appear defined in the custom class?
See this question, which discusses that you cannot get the line number of a declared field via reflection.
Together with the fact that reflection gives you a classes' fields in no particular order, it is obvious that it is not possible to observe the order of declared fields in a class at runtime, and it follows that you cannot order the keys in your YAML output according to their position/order in the source, because you cannot know that order.
The remedy is to transport the knowledge of the order to the runtime. Some possible ways to do this might be:
Annotate each field with a weight that defines the position of the resulting YAML key (ugly because you need annotations on the fields).
Autogenerate code by parsing the class' definition discovering the order from there, and write it to some autogenerated source file whose code is then used to order the properties in your Representer (this solution, while avoiding bloat in the original class, is very complex and elaborate).
Hard-code the field order in the Representer. That's basically the previous solution but without autogenerating. Error-prone because the Representer must be adjusted each time the class is changed.
I recommend against using any of those solutions. The YAML spec specifically says that key order must not convey content information, and if the order is important to you, you are already violating the YAML spec and should switch to a format that better serves your needs.

What to do with a class where one particular variable is sometimes not used

Beginner question here. I'm writing a Java program that queries a public API on the internet to retrieve details of discussions on a forum. The data comes back as JSON and I'm parsing that into Java objects to be used in my program.
A discussion normally contains five attributes, i.e. the five public variables. However, in response to a limited number of specific search types, the number of comments is not returned.
Is there a 'best' (in terms of object oriented programming) way to deal with this sort of scenario? My first attempt is below, where I have simply written two constructors, one that assigns a value to numberOfComments, and one that does not.
This doesn't seem like a great solution - what happens if another class creates a DiscussionDetails object, uses the constructor that does not populate numberOfComments, but then later tries to use the numberOfComments field?
I thought that maybe it should be split into two classes, where DiscussionDetails has no numberOfComments field, and DiscussionDetailsSpecialised is a subclass with an additional numberOfComments field. This feels a bit like overkill to me, for the sake of one single field.
Or maybe there's a convention that such a variable is initialised with a particular value like 'false' or '-1' or something?
Are there other, better approaches that an experienced programmer would use for this kind of situation?
I know the example is trivial, but I'm using it to try to illustrate my question as simply as possible.
/**
* Wrapper for a set of JSON data returned from an API
*/
public class DiscussionDetails
{
public String discussionID;
public String discussionName;
public String discussionURL;
public String submittedDate;
public String numberOfComments;
/**
* Constructor that populates all fields
*/
public DiscussionDetails(String discussionID, String discussionName, String discussionURL, String submittedDate, String numberOfComments)
{
this.discussionID = discussionID;
this.discussionName = discussionName;
this.discussionURL = discussionURL;
this.submittedDate = submittedDate;
this.numberOfComments = numberOfComments;
}
/**
* Constructor method to use when the number of comments is unknown, which happens in certain specific cases
*/
public DiscussionDetails(String discussionID, String discussionName, String discussionURL, String submittedDate)
{
this.discussionID = discussionID;
this.discussionName = discussionName;
this.discussionURL = discussionURL;
this.submittedDate = submittedDate;
}
}
This has been traditionally solved with "special" values (values that obviously make no sense, eg: -1 for a count) or null (which in a sense is the most special value).
The "best" way to deal with this is, IMHO, java.util.Optional: clients have to check if a value is present when they wish to use it and Optional makes this explicit, avoiding the common source of bugs of a client forgetting to check.
One way to solve this is with a builder. Your example is good, but a builder can help make it more obvious what's going on.
/**
* Wrapper for a set of JSON data returned from an API
*/
public class DiscussionDetails
{
public String discussionID;
public String discussionName;
public String discussionURL;
public String submittedDate;
public String numberOfComments;
public static class Builder{
private DiscussionDetails dd = new DiscussionDetails();
public discussionID(String discussionID) {
dd.discussionID = discussionID;
return this;
}
public discussionName(String discussionName) {
dd.discussionName= discussionName;
return this;
}
public discussionURL(String discussionURL) {
dd.discussionURL= discussionURL;
return this;
}
public submittedDate(String submittedDate) {
dd.submittedDate= submittedDate;
return this;
}
public numberOfComments(String numberOfComments) {
dd.numberOfComments= numberOfComments;
return this;
}
public DiscussionDetails build() {
return dd;
}
}
}
This can make your instantiation a little cleaner, especially with optional fields or a lot of fields.
You would use this like:
DiscussionDetails details =
new DiscussionDetails.Builder()
.discussionID("1")
.discussionName("Name")
.build();
In this particular case, I've set 2 of the fields. The other fields would be null, or the default value. With some extra code, this gives you a lot of flexibility and arguably makes the code easier to read.
If you need to enforce certain fields being set, you can add more methods in the Builder class itself, or throw an error from the build method.
The "special" value for handling a case when there is no value for a given property is a null value (nil in some languages). However, you should document this in your code so that the client of the code knows that the numberOfComments can be null - forgetting about it and trying to use the value ends with one of the most common exceptions - NullPointerException.
call this in your constructor
public class DiscussionDetails {
public String discussionID;
public String discussionName;
public String discussionURL;
public String submittedDate;
public String numberOfComments;
/**
* Constructor that populates all fields
*/
public DiscussionDetails(String discussionID, String discussionName, String discussionURL,
String submittedDate, String numberOfComments) {
this(discussionID, discussionName, discussionURL, submittedDate);
this.numberOfComments = numberOfComments;
}
/**
* Constructor method to use when the number of comments is unknown, which happens in certain
* specific cases
*/
public DiscussionDetails(String discussionID, String discussionName, String discussionURL,
String submittedDate) {
this.discussionID = discussionID;
this.discussionName = discussionName;
this.discussionURL = discussionURL;
this.submittedDate = submittedDate;
}
}

Data transfer in Android

I'm currently working on a project that has multiple stages to set up a certain thing. In stage one, the user provides a Title, Description, and a required int value. I need to do two things with this data:
Take the title, and set it as the ActionBar title. This is not hard by any means. I've simply set the variable that the Title value was stored in as an extra on the intent, and retrieved it in the new activity, and set it using the .setTitle(); method on the ActionBar.
Here's the one I need help with...
I need to get that integer value transferred over so I can use it as the number returned by the SectionsPagerAdapter, so when it calls getCount(); it returns the value.
I can get the value inside of the same Class as the Title value, but cannot seem to get it in the SectionsPagerAdapter.
Any help is appreciated!
Alternately you can extend SectionsPagerAdapter and include a setter for that value or use a convenience constructor.
Something like this:
public class CustomPagerAdapter extends PagerAdapter {
private int mPageCount;
/**
*
* #param pageCount
*/
public CustomPagerAdapter(int pageCount) {
this.mPageCount = pageCount;
}
#Override
public int getCount() {
return mPageCount;
}
}
I do not know clearly your problem, but before you change page or when you have value, you can use this class:
Class SavedDave extends Application(){
private static String data;
//Contructor
....
public void SetData(String value){
this.data = value;
}
public String getData(){
return data;
}
}
By this class, you can set and get your value every where when application running, is it solve your problem?
Suppose your method in activity is named getTitle();
From adapter call it like context.getTitle();
where context would be one you pass to the constructor of adapter
private final Context context;
public DataPagerAdapter( Context context )
{
this.context = context;
}
Use Shared Preferences. This is the recommended way to do it in Android.
#SharedPref
public interface ExamplePrefs {
// The name will have default value of "Anonymous"
#DefaultString("Anonymous")
String name();
// The field age will have default value 42
#DefaultInt(42)
int age();
// The field address will have default value of "MyAddress"
#DefaultString("MyAddress")
String name();
// The field lastUpdated will have default value 0
long lastUpdated();
}
For your use case just create a class SectionsPagerPref as follows :
#SharedPref
public interface SectionsPagerPref {
#DefaultInt(0)
int getCount();
}

Can't be resolved to a type

I have a service interface that reads thus
package services;
import domain.Items;
public interface IItemsService extends IService {
public final String NAME = "IItemsService";
/** Places items into the database */
public void storeItem(Items items);
/** Retrieves items from the database
*
* #param category
* #param amount
* #param color
* #param type
* #return
* #throws ClassNotFoundException
*/
public Items getItems (String category, float amount, String color, String type) throws ItemNotFoundException, ClassNotFoundException;
}
And a factory that looks like this...
package services;
public class Factory {
public Factory(){}
#SuppressWarnings("unchecked")
public IService getService(String name) throws ServiceLoadException {
try {
Class c = Class.forName(getImplName(serviceName));
return (IService)c.newInstance();
} catch (Exception e) {
throw new ServiceLoadException(serviceName + "not loaded");
}
}
private String getImplName (String name) throws Exception {
java.util.Properties props = new java.util.Properties();
java.io.FileInputStream fis = new java.io.FileInputStream("properties.txt");
props.load(fis);
fis.close();
return props.getProperty(serviceName);
}
}
This should be really simple - but I keep getting two errors - IService cannot be resolved to a type (on both the factory and the service) and also an serviceName cannot be resolved into a variable error in the factory. I know I am missing something simple...
Regarding the type error: if IService is not in the package services, then IItemService will not have access to it and you will need to import some.package.name.IService.
The second answer is simple: in the getService and getImplName methods, the parameter is named name. In the method bodies, you're referring to it as serviceName. You should probably change name to serviceName in each of them.
If, on the other hand, you're trying to access an instance variable, note that in Java you have to declare all instance variables before you can access (read from/write to) them. You would need to modify the class as such:
public class Factory {
private String serviceName;
public Factory () {}
// other code
}
Well the second error is simple: there isn't a variable called serviceName. If you think there is, point to its declaration. I suspect you meant to use the parameter - in which case just change the parameter name to match the name you're trying to use:
public IService getService(String serviceName) throws ServiceLoadException
...
private String getImplName (String serviceName) throws Exception
This was a pretty simple error - you should think about what bit of your diagnosis let you down in working it out for yourself. (You should also indent your code more sensibly, btw.)
As for IService being missing - we have no idea where IService is meant to be declared, which makes it very hard to help you on this front...

Change property name with Flexjson

I use FlexJson for serialization, the only problem is that it generates the field names lower case while I need them to start with upper case:
class Person
{
String name;
public String getName() { return name;}
}
When serialized the field is serialized as name, while I need it to be Name.
How can I specify the output field name? Is there some attribute I can put to specify the required serialization name?
You can achieve this by using a Custom Transformer. As per Flexjson page transformer is:
Responsible for deciding how to translate the passed in object to
JSON, making the appropriate calls on the JSONContext object to output
the JSON, and/or passing the object along the transformation process.
Flexjson has provided an abstract class AbstractTransformer for this purpose; Extend and override transform(Object object) to handle the transformation by yourself.
Pasted below is the code of FieldNameTransformer which I wrote for specifying the field name s manually:
public class FieldNameTransformer extends AbstractTransformer {
private String transformedFieldName;
public FieldNameTransformer(String transformedFieldName) {
this.transformedFieldName = transformedFieldName;
}
public void transform(Object object) {
boolean setContext = false;
TypeContext typeContext = getContext().peekTypeContext();
//Write comma before starting to write field name if this
//isn't first property that is being transformed
if (!typeContext.isFirst())
getContext().writeComma();
typeContext.setFirst(false);
getContext().writeName(getTransformedFieldName());
getContext().writeQuoted(object.toString());
if (setContext) {
getContext().writeCloseObject();
}
}
/***
* TRUE tells the JSONContext that this class will be handling
* the writing of our property name by itself.
*/
#Override
public Boolean isInline() {
return Boolean.TRUE;
}
public String getTransformedFieldName() {
return this.transformedFieldName;
}
}
Following is how to use this custom transformer:
JSONSerializer serializer = new JSONSerializer().transform(new FieldNameTransformer("Name"), "name");
where original field's name is 'name' but in json ouput it will be replaced with Name.
Sample out:
{"Name":"Abdul Kareem"}

Categories