So, I have code that's generating ID's for a number of elements using an AtomicInteger that's set by default at Integer.MAX_VALUE and is decremented from there with each view that gets assigned an ID. So the first view with a generated ID would be Integer.MAX_VALUE - 1, the second would be Integer.MAX_VALUE - 2, etc. The problem I'm afraid of is a collision with IDs generated by Android in R.java.
So my question is how can I detect if an ID is already in use and skip it when I'm generating the IDs. I'm only generating at most 30 IDs so this isn't a huge priority nut I'ld like to make this as bug free as possible.
The following code will tell you if the identifier is an id or not.
static final String PACKAGE_ID = "com.your.package.here:id/"
...
...
int id = <your random id here>
String name = getResources().getResourceName(id);
if (name == null || !name.startsWith(PACKAGE_ID)) {
// id is not an id used by a layout element.
}
I modified Jens answer from above since, as stated in comments, name will never be null and exception is thrown instead.
private boolean isResourceIdInPackage(String packageName, int resId){
if(packageName == null || resId == 0){
return false;
}
Resources res = null;
if(packageName.equals(getPackageName())){
res = getResources();
}else{
try{
res = getPackageManager().getResourcesForApplication(packageName);
}catch(PackageManager.NameNotFoundException e){
Log.w(TAG, packageName + "does not contain " + resId + " ... " + e.getMessage());
}
}
if(res == null){
return false;
}
return isResourceIdInResources(res, resId);
}
private boolean isResourceIdInResources(Resources res, int resId){
try{
getResources().getResourceName(resId);
//Didn't catch so id is in res
return true;
}catch (Resources.NotFoundException e){
return false;
}
}
You can use Java Reflection API to access whatever elements are present in an object of R.id Class.
The code is like this:
Class<R.id> c = R.id.class;
R.id object = new R.id();
Field[] fields = c.getDeclaredFields();
// Iterate through whatever fields R.id has
for (Field field : fields)
{
field.setAccessible(true);
// I am just printing field name and value, you can place your checks here
System.out.println("Value of " + field.getName() + " : " + field.get(object));
}
You can use View.generateViewId() which requires min API 17.
From sdk
Generate a value suitable for use in setId(int). This value will not collide with ID values generated at build time by aapt for R.id.
Just an idea ... you could use the findViewById (int id) to check if the id is already in use.
Related
I am trying to obtain a field's value via reflection. The problem is I don't know the field's type and have to decide it while getting the value.
This code results with this exception:
Can not set java.lang.String field com....fieldName to java.lang.String
Field field = object.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
Class<?> targetType = field.getType();
Object objectValue = targetType.newInstance();
Object value = field.get(objectValue);
I tried to cast, but I get compilation errors:
field.get((targetType)objectValue)
or
targetType objectValue = targetType.newInstance();
How can I do this?
Like answered before, you should use:
Object value = field.get(objectInstance);
Another way, which is sometimes prefered, is calling the getter dynamically. example code:
public static Object runGetter(Field field, BaseValidationObject o)
{
// MZ: Find the correct method
for (Method method : o.getMethods())
{
if ((method.getName().startsWith("get")) && (method.getName().length() == (field.getName().length() + 3)))
{
if (method.getName().toLowerCase().endsWith(field.getName().toLowerCase()))
{
// MZ: Method found, run it
try
{
return method.invoke(o);
}
catch (IllegalAccessException e)
{
Logger.fatal("Could not determine method: " + method.getName());
}
catch (InvocationTargetException e)
{
Logger.fatal("Could not determine method: " + method.getName());
}
}
}
}
return null;
}
Also be aware that when your class inherits from another class, you need to recursively determine the Field. for instance, to fetch all Fields of a given class;
for (Class<?> c = someClass; c != null; c = c.getSuperclass())
{
Field[] fields = c.getDeclaredFields();
for (Field classField : fields)
{
result.add(classField);
}
}
You should pass the object to get method of the field, so
Field field = object.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
Object value = field.get(object);
I use the reflections in the toString() implementation of my preference class to see the class members and values (simple and quick debugging).
The simplified code I'm using:
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
Class<?> thisClass = null;
try {
thisClass = Class.forName(this.getClass().getName());
Field[] aClassFields = thisClass.getDeclaredFields();
sb.append(this.getClass().getSimpleName() + " [ ");
for(Field f : aClassFields){
String fName = f.getName();
sb.append("(" + f.getType() + ") " + fName + " = " + f.get(this) + ", ");
}
sb.append("]");
} catch (Exception e) {
e.printStackTrace();
}
return sb.toString();
}
I hope that it will help someone, because I also have searched.
Although it's not really clear to me what you're trying to achieve, I spotted an obvious error in your code:
Field.get() expects the object which contains the field as argument, not some (possible) value of that field. So you should have field.get(object).
Since you appear to be looking for the field value, you can obtain that as:
Object objectValue = field.get(object);
No need to instantiate the field type and create some empty/default value; or maybe there's something I missed.
Integer typeValue = 0;
try {
Class<Types> types = Types.class;
java.lang.reflect.Field field = types.getDeclaredField("Type");
field.setAccessible(true);
Object value = field.get(types);
typeValue = (Integer) value;
} catch (Exception e) {
e.printStackTrace();
}
`
//Here is the example I used for get the field name also the field value
//Hope This will help to someone
TestModel model = new TestModel ("MyDate", "MyTime", "OUT");
//Get All the fields of the class
Field[] fields = model.getClass().getDeclaredFields();
//If the field is private make the field to accessible true
fields[0].setAccessible(true);
//Get the field name
System.out.println(fields[0].getName());
//Get the field value
System.out.println(fields[0].get(model));
`
I post my solution in Kotlin, but it can work with java objects as well.
I create a function extension so any object can use this function.
fun Any.iterateOverComponents() {
val fields = this.javaClass.declaredFields
fields.forEachIndexed { i, field ->
fields[i].isAccessible = true
// get value of the fields
val value = fields[i].get(this)
// print result
Log.w("Msg", "Value of Field "
+ fields[i].name
+ " is " + value)
}}
Take a look at this webpage: https://www.geeksforgeeks.org/field-get-method-in-java-with-examples/
Was able to access private fields in a class using following method
Beneficiary ben = new Beneficiary();//class with multiple fields
ben.setName("Ashok");//is set by a setter
//then to get that value following was the code which worked for me
Field[] fields = ben.getClass().getDeclaredFields();
for(Field field: fields) {
field.setAccessible(true);//to access private fields
System.out.println(field.get(ben));//to get value
//assign value for the same field.set(ben, "Y");//to set value
}
You are calling get with the wrong argument.
It should be:
Object value = field.get(object);
I have written an application that retrieves Active Directory groups and flattens them, i.e. includes recursively members of subgroup to the top parent group.
It works fine for small groups, but with larger groups I am facing a problem.
If number of members does not exceed 1500, they are listed in the member attribute. If there are more - then this attribute is empty and attribute with name member;range:0-1499 appears, containing first 1500 members.
My problem that I don't know how to get the rest of member set over 1500.
We have groups with 8-12 thousand members. Do I need to run another query?
On the Microsoft site I have seen C# code snippet on the similar matter, but couldn't make much sense of it, as they were showing how to specify a range, but not how to plug it into query. If someone knows how to do it in Java, I'd appreciate a tip.
This will obviously give you the next ones:
String[] returnedAtts = { "member;range=1500-2999" };
You need to fetch the users chunk by chunk (1500 chunks) Just make a counter and update you search and retrieve the next ones until you have all of them.
With your help I have a full working code
// Initialize
LdapContext ldapContext = null;
NamingEnumeration<SearchResult> results = null;
NamingEnumeration<?> members = null;
try {
// Initialize properties
Properties properties = new Properties();
properties.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
properties.put(Context.PROVIDER_URL, "ldap://" + ldapUrl);
properties.put(Context.SECURITY_PRINCIPAL, adminLoginADOnPremise);
properties.put(Context.SECURITY_CREDENTIALS, adminPasswordADOnPremise);
// Initialize ldap context
ldapContext = new InitialLdapContext(properties, null);
int range = 0;
boolean finish = false;
while (finish != true) {
// Set search controls
SearchControls searchCtls = new SearchControls();
searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
searchCtls.setReturningAttributes(generateRangeArray(range));
// Get results
results = ldapContext.search(ldapBaseDn, String.format("(samAccountName=%s)", groupName), searchCtls);
if (results.hasMoreElements() == true) {
SearchResult result = results.next();
try {
members = result.getAttributes().get(generateRangeString(range)).getAll();
while (members.hasMore()) {
String distinguishedName = (String) members.next();
logger.debug(distinguishedName);
}
range++;
} catch (Exception e) {
// Fails means there is no more result
finish = true;
}
}
}
} catch (NamingException e) {
logger.error(e.getMessage());
throw new Exception(e.getMessage());
} finally {
if (ldapContext != null) {
ldapContext.close();
}
if (results != null) {
results.close();
}
}
Two functions missing from the working code example by #Nicolas, I guess they would be something like:
public static String[] generateRangeArray(int i) {
String range = "member;range=" + i * 1500 + "-" + ((i + 1) * 1500 - 1);
String[] returnedAtts = { range };
return returnedAtts;
}
public static String generateRangeString(int i) {
String range = "member;range=" + i * 1500 + "-" + ((i + 1) * 1500 - 1);
return range;
}
The code does not handle the case if the AD group is not so large that the member attribute actually needs to be "chunked", that is if the "member" attribute exists instead.
I am working with Jackcess to read and categorize an access database. It's simply meant to open the database, loop through each line, and print out individual row data to the console which meet certain conditions. It works fine, except for when I try to read numeric values. My code is below. (This code is built into a Swing GUI and gets executed when a jbutton is pressed.)
if (inv == null) { // Check to see if inventory file has been set. If not, then set it to the default reference path.
inv = rPath;
}
if (inventoryFile.exists()) { // Check to see if the reference path exists.
List<String> testTypes = jList1.getSelectedValuesList();
List<String> evalTypes = jList3.getSelectedValuesList();
List<String> grainTypes = jList2.getSelectedValuesList();
StringBuilder sb = new StringBuilder();
for (int i=0; i<=evalTypes.size()-1; i++) {
if (i<evalTypes.size()-1) {
sb.append(evalTypes.get(i)).append(" ");
}
else {
sb.append(evalTypes.get(i));
}
}
String evalType = sb.toString();
try (Database db = DatabaseBuilder.open(new File(inv));) {
Table sampleList = db.getTable("NTEP SAMPLES LIST");
Cursor cursor = CursorBuilder.createCursor(sampleList);
for (int i=0; i<=testTypes.size()-1; i++) {
if ("Sample Volume".equals(testTypes.get(i))) {
if (grainTypes.size() == 1 && "HRW".equals(grainTypes.get(0))) {
switch (evalType) {
case "GMM":
for (Row row : sampleList){
if (null != row.getString("CURRENTGAC")) {}
if ("HRW".equals(row.get("GRAIN")) && row.getDouble("CURRENTGAC")>=12.00) {
System.out.print(row.get("GRAIN") + "\t");
System.out.println(row.get("CURRENTGAC"));
}
}
break;
case "NIRT":
// some conditional code
break;
case "TW":
// some more code
break;
}
}
else {
JOptionPane.showMessageDialog(null, "Only HRW samples can be used for the selected test(s).", "Error", JOptionPane.ERROR_MESSAGE);
}
break;
}
}
}
catch (IOException ex) {
Logger.getLogger(SampleFilterGUI.class.getName()).log(Level.SEVERE, null, ex);
}
When the code is run I get the following error:
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Double
The following condition looks to be what is throwing the error.
row.getDouble("CURRENTGAC")>=12.00
It appears that when the data is read from the database, the program is reading everything as a string, even though some fields are numeric. I was attempting to cast this field as a double, but java doesn't seem to like that. I have tried using the Double.parseDouble() and Double.valueOf() commands to try converting the value (as mentioned here) but without success.
My question is, how can I convert these fields to numeric values? Is trying to type cast the way to go, or is there a different method I'm not aware of? You will also notice in the code that I created a cursor, but am not using it. The original plan was to use it for navigating through the database, but I found some example code from the jackcess webpage and decided to use that instead. Not sure if that was the right move or not, but it seemed like a simpler solution. Any help is much appreciated. Thanks.
EDIT:
To ensure the program was reading a string value from my database, I input the following code
row.get("CURRENTGAC").getClass().getName()
The output was java.lang.String, so this confirms that it is a string. As was suggested, I changed the following code
case "GMM":
for (Row row : sampleList){
if (null != row.get("CURRENTGAC"))
//System.out.println(row.get("CURRENTGAC").getClass().getName());
System.out.println(String.format("|%s|", row.getString("CURRENTGAC")));
/*if ("HRW".equals(row.get("GRAIN")) && row.getDouble("CURRENTGAC")>=12.00 && row.getDouble("CURRENTGAC")<=14.00) {
System.out.print(row.get("GRAIN") + "\t");
System.out.println(row.get("CURRENTGAC"));
}*/
}
break;
The ouput to the console from these changes is below
|9.85|
|11.76|
|9.57|
|12.98|
|10.43|
|13.08|
|10.53|
|11.46|
...
This output, although looks numeric, is still of the string type. So when I tried to run it with my conditional statement (which is commented out in the updated sample code) I still get the same java.lang.ClassCastException error that I was getting before.
Jackcess does not return all values as strings. It will retrieve the fields (columns) of a table as the appropriate Java type for that Access field type. For example, with a test table named "Table1" ...
ID DoubleField TextField
-- ----------- ---------
1 1.23 4.56
... the following Java code ...
Table t = db.getTable("Table1");
for (Row r : t) {
Object o;
Double d;
String fieldName;
fieldName = "DoubleField";
o = r.get(fieldName);
System.out.println(String.format(
"%s comes back as: %s",
fieldName,
o.getClass().getName()));
System.out.println(String.format(
"Value: %f",
o));
System.out.println();
fieldName = "TextField";
o = r.get(fieldName);
System.out.println(String.format(
"%s comes back as: %s",
fieldName,
o.getClass().getName()));
System.out.println(String.format(
"Value: %s",
o));
try {
d = r.getDouble(fieldName);
} catch (Exception x) {
System.out.println(String.format(
"r.getDouble(\"%s\") failed - %s: %s",
fieldName,
x.getClass().getName(),
x.getMessage()));
}
try {
d = Double.parseDouble(r.getString(fieldName));
System.out.println(String.format(
"Double.parseDouble(r.getString(\"%s\")) succeeded. Value: %f",
fieldName,
d));
} catch (Exception x) {
System.out.println(String.format(
"Double.parseDouble(r.getString(\"%s\")) failed: %s",
fieldName,
x.getClass().getName()));
}
System.out.println();
}
... produces:
DoubleField comes back as: java.lang.Double
Value: 1.230000
TextField comes back as: java.lang.String
Value: 4.56
r.getDouble("TextField") failed - java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Double
Double.parseDouble(r.getString("TextField")) succeeded. Value: 4.560000
If you are unable to get Double.parseDouble() to parse the string values from your database then either
they contain "funny characters" that are not apparent from the samples you posted, or
you're doing it wrong.
Additional information re: your sample file
Jackcess is returning CURRENTGAC as String because it is a Text field in the table:
The following Java code ...
Table t = db.getTable("NTEP SAMPLES LIST");
int countNotNull = 0;
int countAtLeast12 = 0;
for (Row r : t) {
String s = r.getString("CURRENTGAC");
if (s != null) {
countNotNull++;
Double d = Double.parseDouble(s);
if (d >= 12.00) {
countAtLeast12++;
}
}
}
System.out.println(String.format(
"Scan complete. Found %d non-null CURRENTGAC values, %d of which were >= 12.00.",
countNotNull,
countAtLeast12));
... produces ...
Scan complete. Found 100 non-null CURRENTGAC values, 62 of which were >= 12.00.
I'm using Tapestry5 and Hibernate. I'm trying to build a criteria query that uses dynamic restrictions generated from the URL. My URL context is designed like a key/value pair.
Example
www.mywebsite.com/make/ford/model/focus/year/2009
I decode the parameters as followed
private Map<String, String> queryParameters;
private List<Vehicle> vehicles;
void onActivate(EventContext context) {
//Count is 6 - make/ford/model/focus/year/2009
int count = context.getCount();
if (count > 0) {
int i;
for (i = 0; (i + 1) < count; i += 2) {
String name = context.get(String.class, i);
String value = context.get(String.class, i + 1);
example "make"
System.out.println("name " + name);
example "ford"
System.out.println("value " + value);
this.queryParameters.put(name, value);
}
}
this.vehicles = this.session.createCriteria(Vehicle.class)
...add dynamic restrictions.
}
I was hoping someone could help me to figure out how to dynamically add the list of restrictions to my query. I'm sure this has been done, so if anybody knows of a post, that would be helpful too. Thanks
Exactly as the other answer said, but here more spelt out. I think the crux of your question is really 'show me how to add a restriction'. That is my interpretation anyhow.
You need to decode each restriction into its own field.
You need to know the Java entity property name for each field.
Then build a Map of these 2 things, the key is the known static Java entity property name and the value is the URL decoded data (possibly with type conversion).
private Map<String, Object> queryParameters;
private List<Vehicle> vehicles;
void onActivate(EventContext context) {
//Count is 6 - make/ford/model/focus/year/2009
int count = context.getCount();
queryParameters = new HashMap<String,Object>();
if (count > 0) {
int i;
for (i = 0; (i + 1) < count; i += 2) {
String name = context.get(String.class, i);
String value = context.get(String.class, i + 1);
Object sqlValue = value;
if("foobar".equals(name)) {
// sometime you don't want a String type for SQL compasition
// so convert it
sqlValue = UtilityClass.doTypeConversionForFoobar(value);
} else if("search".equals(name) ||
"model".equals(name) ||
"year".equals(name)) {
// no-op this is valid 'name'
} else if("make".equals(name)) {
// this is a suggestion depends on your project conf
name = "vehicleMake.name";
} else {
continue; // ignore values we did not expect
}
// FIXME: You should validate all 'name' values
// to be valid and/or convert to Java property names here
System.out.println("name " + name);
System.out.println("value " + value);
this.queryParameters.put(name, sqlValue);
}
}
Criteria crit = this.session.createCriteria(Vehicle.class)
for(Map.Entry<String,Object> e : this.queryParameters.entrySet()) {
String n = e.getKey();
Object v = e.getValue();
// Sometimes you don't want a direct compare 'Restructions.eq()'
if("search".equals(n))
crit.add(Restrictions.like(n, "%" + v + "%"));
else // Most of the time you do
crit.add(Restrictions.eq(n, v));
}
this.vehicles = crit.list(); // run query
}
See also https://docs.jboss.org/hibernate/orm/3.5/reference/en/html/querycriteria.html
With the above there should be no risk of SQL injection, since the "name" and "n" part should be 100% validated against a known good list. The "value" and "v" is correctly escaped, just like using SQL position placeholder '?'.
E&OE
I would assume you would just loop over the parameters Map and add a Restriction for each pair.
Be aware that this will open you up to sql injection attacks if you are not careful. the easiest way to protect against this would be to check the keys against the known Vehicle properties before adding to the Criteria.
Another option would be to create an example query by building an object from the name/value pairs:
Vehicle vehicle = new Vehicle();
int count = context.getCount();
int i;
for (i = 0; (i + 1) < count; i += 2) {
String name = context.get(String.class, i);
String value = context.get(String.class, i + 1);
// This will call the setter for the name, passing the value
// So if name is 'make' and value is 'ford', it will call vehicle.setMake('ford')
BeantUtils.setProperty(vehicle, name, value);
}
// This is using a Hibernate example query:
vehicles = session.createCriteria(Vehicle.class).add(Example.create(vehicle)).list();
See BeanUtils.setProperty and Example Queries for more info.
That assumes you are allowing only one value per property and that the query parameters map to the property names correctly. There may also be conversion issues to think about but I think setProperty handles the common ones.
If they are query paramaters you should treat them as query parameters instead of path parameters. Your URL should look something like:
www.mywebsite.com/vehicles?make=ford&model=focus&year=2009
and your code should look something like this:
public class Vehicles {
#ActivationRequestParameter
private String make;
#ActivationRequestParameter
private String model;
#ActivationRequestParameter
private String year;
#Inject
private Session session;
#OnEvent(EventConstants.ACTIVATE)
void activate() {
Criteria criteria = session.createCriteria(Vehicle.class);
if (make != null) criteria.add(Restrictions.eq("make", make));
if (model != null) criteria.add(Restrictions.eq("model", model));
if (year != null) criteria.add(Restrictions.eq("year", year));
vehicles = criteria.list();
}
}
Assuming you are using the Grid component to display the vehicles I'd highly recommend using the HibernateGridDataSource instead of making the query in the "activate" event handler.
public class Vehicles {
#ActivationRequestParameter
private String make;
#ActivationRequestParameter
private String model;
#ActivationRequestParameter
private String year;
#Inject
private Session session;
#OnEvent(EventConstants.ACTIVATE)
void activate() {
}
public GridDataSource getVehicles() {
return new HibernateGridDataSource(session, Vehicles.class) {
#Override
protected void applyAdditionalConstraints(Criteria criteria) {
if (make != null) criteria.add(Restrictions.eq("make", make));
if (model != null) criteria.add(Restrictions.eq("model", model));
if (year != null) criteria.add(Restrictions.eq("year", year));
}
};
}
}
How can I obtain the value of a boolean field in an SQLite database on Android?
I usually use getString(), getInt(), etc. to get the values of my fields, but there does not seem to be a getBoolean() method.
It is:
boolean value = cursor.getInt(boolean_column_index) > 0;
There is no bool data type in SQLite. Use an int that you fix to 0 or 1 to achieve that effect. See the datatypes reference on SQLite 3.0.
boolean value = (cursor.getInt(boolean_column_index) == 1);
Most of the answers here can result in NumberFormatExceptions or "operator is undefined for the types null, int" if the column you stored the int in was allowed to also hold null.
The decent way to do this would be to use
Boolean.parseBoolean(cursor.getString(booleanColumnIndex));`
though you are now limited to storing the strings "true" and "false" rather than 0 or 1.
An implementation found at Ormlite Cursor also checks for Null which none of the other answers do.
public boolean getBoolean(int columnIndex) {
if (cursor.isNull(columnIndex) || cursor.getShort(columnIndex) == 0) {
return false;
} else {
return true;
}
}
You can also use
boolean value =cursor.getString(boolean_column_index).equals("True");
boolean datatype is not available in Cursor.
you will get the result in an int, so you need to convert that int value to a boolean.
You can either use
boolean b = cursor.getInt(boolean_column_index) > 0;
or
boolean b = (cursor.getInt(boolean_column_index) != 0);
Another option
boolean value = (cursor.getString(column_index)).equals("1");
boolean b = (cursor.getInt(cursor.getColumnIndex("item")) != 0);
Well, that's very simple:
public boolean getBooleanState(SQLiteDatabase db){
boolean result = false;
try{
String QUERY = "SELECT " + BOOLEAN_DATA + " FROM " + TABLE_NAME + " WHERE " + ID + " = 1";
Cursor cursor = db.rawQuery(QUERY, null);
if (cursor.moveToFirst()){
if(cursor.getString(0).equalsIgnoreCase("1")){
result = true;
}
}
c.close();
}catch(Exception ee){
Log.e(TAG, "err getBooleanState: " + TABLE_NAME );
}
return result;
}
For an optional (nullable) Boolean stored as INTEGER, you can create a Kotlin extension:
fun Cursor.getBoolean(columnIndex: Int): Boolean? {
return if (isNull(columnIndex))
null
else
getInt(columnIndex) != 0
}
and use it like this:
val value: Boolean? = cursor.getBoolean(boolean_column_index)
thats what I used:
val work = Work()
work.id = cursor.getInt(0)
work.date = cursor.getString(1)
work.work_value = cursor.getFloat(2)
work.place = cursor.getString(3)
work.wind = cursor.getFloat(4)
work.isCompetition = cursor.getInt(5) > 0
return work
I face the same thing in kotlin.
There was the value "true/false" in the database
and I access it with this code:
cursor.getString(4).toBoolean()
//first as a string then converting them to boolean