Default primitive values from primitive Class<?> object.

D

Daniel Pitts

I have some generic reflection based code which "clears" a JavaBean
based on the PropertyDescriptors. Initially, I set everything to "null"
which worked until I put a boolean (not Boolean) in one of my beans.

I special cased boolean, and that is fine, but I know that sometime
someone is going to ask for an "int" or a "long", etc...

I have the Class<?> from the propertyDescriptor and was wondering if
there was any easy way to map from that Class<?> to an appropriate
"default" wrapper? If there isn't a built-in way, I can always use a
Map<Class<?>, Object>, and just initialize it with new Integer(0), new
Double(0), etc...
Not quite the best approach in my opinion.
 
Z

zerg

Daniel said:
I have the Class<?> from the propertyDescriptor and was wondering if
there was any easy way to map from that Class<?> to an appropriate
"default" wrapper? If there isn't a built-in way, I can always use a
Map<Class<?>, Object>, and just initialize it with new Integer(0), new
Double(0), etc...
Not quite the best approach in my opinion.

No; brute force is probably the best approach, given how few primitive
types there are. Just special-case each one the way you already have
boolean.
 
D

Daniel Pitts

zerg said:
No; brute force is probably the best approach, given how few primitive
types there are. Just special-case each one the way you already have
boolean.
That's what I thought :-(
Here's what I did:
private static final Map<Class<?>, Object> defaultValues;
static {
final Map<Class<?>, Object> values = new HashMap<Class<?>, Object>();
defaultValues = Collections.unmodifiableMap(values);
values.put(Boolean.TYPE, false);
values.put(Integer.TYPE, 0);
values.put(Short.TYPE, (short) 0);
values.put(Long.TYPE, 0L);
values.put(Float.TYPE, 0f);
values.put(Double.TYPE, 0d);
values.put(Character.TYPE, (char)0);
values.put(Byte.TYPE, (byte)0);
}

// elsewhere
setProperty(property, bean, defaultValues.get(property.getPropertyType()));


where setProperty actually invokes the property's write method on the
given bean with the given value.

This works for all cases, since map.get(*) will return null if there
isn't a specific value. This lets me add "custom" default values later
on if I need to.
 
M

Mark Space

Daniel said:
This works for all cases, since map.get(*) will return null if there
isn't a specific value.

Clever. I missed that reading the code. Might want to mention it in a
comment somewhere....
 
O

Owen Jacobson

I have some generic reflection based code which "clears" a JavaBean
based on the PropertyDescriptors.  Initially, I set everything to "null"
which worked until I put a boolean (not Boolean) in one of my beans.

I special cased boolean, and that is fine, but I know that sometime
someone is going to ask for an "int" or a "long", etc...

I have the Class<?> from the propertyDescriptor and was wondering if
there was any easy way to map from that Class<?> to an appropriate
"default" wrapper?  If there isn't a built-in way, I can always use a
Map<Class<?>, Object>, and just initialize it with new Integer(0), new
Double(0), etc...
Not quite the best approach in my opinion.

On the contrary. This actually lets you plug in "default" values for
any type you want. However, rather than hardcoding the map, I'd
provide a convenience tool that constructs a map containing only
defaults for primitive-wrapper and primitive types and accept a
default map as a parameter to the 'resetter' method (or class); if the
consumer wants to use the defaults, they can, or they can provide any
map they want. The result is flexible in potentially-useful ways.

-o
 
D

Daniel Pitts

Lew said:
Mark said:
Clever. I missed that reading the code. Might want to mention it in
a comment somewhere....

<http://java.sun.com/javase/6/docs/api/java/util/Map.html#get(java.lang.Object)>

Map#get()
Returns the value to which the specified key is mapped, or null if
this map contains no mapping for the key.

I started thinking twistedly - how could one retrieve just the normal
default values, letting Java decide what they are, without a Map, even
for automatic variables?

<sscce>
package testit;

/** Show strange use of anonymous class to get default value. */
public class OverGet
{
/** Show strange use of anonymous class to get default value. */
public void foo()
{
int huhQ =
new Object()
{
int huh;
public int getHuh()
{
return huh;
}
}.getHuh();
System.out.println( huhQ );
}

/** Entry point.
* @param args <code>String []</code> command line arguments.
*/
public static void main( String [] args )
{
new OverGet().foo();
}

}
</sscce>
Well, I'm in a codebase that is doing heavy reflection, so I can do this
(untested, and probably won't end up in production):
private static final defs = new Object() {
byte by; boolean bo; char c; int i; float f; double d; short s;
}
for (Field field: defs.getClass().getDeclaredFields()) {
defaultValues.put(field.getType(), field.get(defs));
}
 
D

Daniel Pitts

Owen said:
On the contrary. This actually lets you plug in "default" values for
any type you want. However, rather than hardcoding the map, I'd
provide a convenience tool that constructs a map containing only
defaults for primitive-wrapper and primitive types and accept a
default map as a parameter to the 'resetter' method (or class); if the
consumer wants to use the defaults, they can, or they can provide any
map they want. The result is flexible in potentially-useful ways.

-o
That approach may be useful in the future, but this is a specific enough
(and large enough) codebase that I'm trying to avoid YAGNI features.
 
L

Lew

Lew said:
I started thinking twistedly - how could one retrieve just the normal
default values, letting Java decide what they are, without a Map, even
for automatic variables?

<sscce>
package testit;

/** Show strange use of anonymous class to get default value.   */
public class OverGet
{
 /** Show strange use of anonymous class to get default value.  */
 public void foo()
 {
   int huhQ =
     new Object()
     {
       int huh;
       public int getHuh()
       {
         return huh;
       }
     }.getHuh();
   System.out.println( huhQ );
 }

 /** Entry point.
  * @param args <code>String []</code> command line arguments.
  */
 public static void main( String [] args )
 {
  new OverGet().foo();
 }

}
</sscce>

Daniel said:
Well, I'm in a codebase that is doing heavy reflection, so I can do this
(untested, and probably won't end up in production):
private static final defs = new Object() {
    byte by; boolean bo; char c; int i; float f; double d; short s;}

for (Field field: defs.getClass().getDeclaredFields()) {
    defaultValues.put(field.getType(), field.get(defs));

}

Huh.

Shows that even wacky ideas can have their place. I didn't even see
it as that useful until I saw your example.

In your code, you could make defs a temporary variable inside an
initializer block.

I came up with a poetic variant of the idiom specific to 'double':

double duh = new Object(){double duh;}.duh;
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,902
Latest member
Elena68X5

Latest Threads

Top