Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / December 2007

Tip: Looking for answers? Try searching our database.

enums, using methods as initializers

Thread view: 
Mikhail Teterin - 14 Nov 2007 19:54 GMT
Hello!

I would like to be able to initialize fields of an enum with /methods/ (of
another Class).

Here is the (non-working) example:

import java.util.*;
import java.sql.*;

public enum Field {
 FIELD1 (ResultSet.getString),
 FIELD2 (ResultSet.getDouble),
 ...
 FIELDN (ResultSet.getTimestamp);

 private java.lang.reflect.Method extract;
}

the idea is to be able to get all fields from a given ResultSet by going
through the list of Fields and extracting the column from the ResultSet.

Something like:

public void print(ResultSet rs)
{
 for (Field f : Field.values())
  System.out.println(f + ":\t" + rs.f.extract(f));
}

Does the above stand a chance of being turned into a real Java code?

Thanks for ideas!

-mi
Daniel Pitts - 14 Nov 2007 20:02 GMT
> Hello!
>
[quoted text clipped - 31 lines]
>
>  -mi
Yes, kind of.  You won't be able to pass in a method, but you can create
a delegate method easily.
I have an example here actually:
<http://virtualinfinity.net/wordpress/program-design/2007/10/22/using-enums-as-a-
flyweight-pattern/
>

enums are full classes, so you can add methods to them, and even add an
abstract method to the base enum type (Field in your case) and override
those methods in the subtypes (FIELD1 FIELD2, etc...) .

Signature

Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>

Mikhail Teterin - 14 Nov 2007 20:23 GMT
> Yes, kind of.  You won't be able to pass in a method, but you can create
> a delegate method easily.

:(

> I have an example here actually:
> <http://virtualinfinity.net/wordpress/program-design/2007/10/22/using-enums-as-a-
flyweight-pattern/
>

In your example, each case of the enum spells-out its methods in full.
It is workable, of course, but I wanted to have list the cases as a kind
of a /table/ -- preferably one case per line.

I'm pretty certain, I can do this with my own /data/:

FIELD1 ("string"),
FIELD2 ("double"),
...
FIELDN ("Timestamp);

private String type;

and then use the type to tell me, which of method of the foreign class to
call:

if (type == "string")
 return rs.getString(......)
if (type == "double")
 return rs.getDouble(......)
.... a case for each type ....

But it would all have been much easier, if I could pass the
/methods/ the same way I can pass function-pointers in C or C++.

Thanks!

-mi
Daniel Pitts - 14 Nov 2007 20:59 GMT
>> Yes, kind of.  You won't be able to pass in a method, but you can create
>> a delegate method easily.
[quoted text clipped - 32 lines]
>
>  -mi
You can use reflection in this case, but thats not necessarily a good
idea. Reflection can add unnecessary complexity.

I gather from your previous posts that you are used to programming in
C/C++, and finding more concise manors to express a particular effect of
code.   Just remember, more lines doesn't mean more complex. In fact,
/sometimes/ it means less complex :-)

Like I said, you *can* use reflection for this, but I advise against it:
<http://virtualinfinity.net/wordpress/program-design/2007/01/11/the-dangers-of-re
flection-or-put-down-that-mirror/
>

What you're trying to do sounds a lot like something that I did a while
ago. It also sounds like you would be better off using Hibernate or some
other ORM solution.  Trust me, the ramp-up time is well-worth the
maintenance costs down the road.

Signature

Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>

Mikhail Teterin - 15 Nov 2007 02:58 GMT
> You can use reflection in this case, but thats not necessarily a good
> idea. Reflection can add unnecessary complexity.

Maybe, one can just treat all data-fields of a class as a Collection or some
such?

class Meow {
 String foo;
 double bar;
}

....

for (Field field : Meow.fields()) {
 if (field.getType() == String)
 .....

?

> I gather from your previous posts that you are used to programming in
> C/C++, and finding more concise manors to express a particular effect of
> code. Just remember, more lines doesn't mean more complex. In fact,
> sometimes it means less complex :-)

The idea here is that the concise declarative part can be maintained by
someone else as "data", while I maintain the code...

The shorter the program, the fewer screenfuls it takes, the fewer bugs :)

Thanks!

-mi
Daniel Pitts - 15 Nov 2007 16:35 GMT
> The idea here is that the concise declarative part can be maintained by
> someone else as "data", while I maintain the code...
>
> The shorter the program, the fewer screenfuls it takes, the fewer bugs :)
Not necessarily.  Less verbosity *can* lead to fewer bugs, but it can
also be too terse to understand.  In any case, I think that this
situation *is* ripe for a better solution...  I've suggested it before.
 Hibernate! Google for it.  Use it.  You no longer have to deal with
low-level JDBC stuff, it'll help manage your schema for you if you
choose, and the CRUD operations are super easy.

> Thanks!

No problem.  If you choose *not* to use Hibernate, a response of why
would be appreciated.

Daniel.

Signature

Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>

Lew - 16 Nov 2007 06:11 GMT
>  Hibernate! Google for it.  Use it.  You no longer have to deal with
> low-level JDBC stuff, it'll help manage your schema for you if you
> choose, and the CRUD operations are super easy.

> ...  If you choose *not* to use Hibernate, a response of why
> would be appreciated.

I'm learning Hibernate, and the JPA annotations generally.  It's a bit tricky
learning to configure the DataSource, but I'm slogging through it.

I've written whole entire data-access layers, the most recent replete with
generic <Entity> typing and all kinds of nifty transaction boundaries and
exception logging - whew.  I am really hoping the Hibernatic approach will
make life easier.  It may seem easy to do database, but to do it right, with
rigor and reliability takes a lot.

Having labored through the "by-hand" approach, I really get where the
annotations are coming from.

The devil is in the deployment.

Signature

Lew

mekane - 15 Nov 2007 19:36 GMT
> Hello!
>
[quoted text clipped - 31 lines]
>
>  -mi

I assume you've looked at:
http://java.sun.com/j2se/1.5.0/docs/guide/language/enums.html

I had a case where I needed to do something similar to this, and I tried
overriding a method on each element of the enum. I didn't like defining
big methods inside the constructor, so I actually went with the method
described in the article that uses a switch.

So you would have one method defined in the enum like:

  public String extract( Resultset arg ){
    switch ( this )
    {
      case FIELD1:
        return arg.getString();
      case FIELD2:
        return arg.getDouble();
      ...
      case FIELDN:
        return resultSet.getTimestamp();
    }
  }

then you could iterate over the values of the enum and do f.extract(rs)

-marty
Daniel Pitts - 15 Nov 2007 21:17 GMT
>> Hello!
>>
[quoted text clipped - 59 lines]
>
> -marty
That is very specifically a Bad Idea!
f.extract should NOT have a switch statement, but instead should be
polymorphic.

Signature

Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>

mekane - 15 Nov 2007 21:29 GMT
> That is very specifically a Bad Idea!
> f.extract should NOT have a switch statement, but instead should be
> polymorphic.

What difference does it make? Anything other than I might forget to add
another case?
Is this more than just an implementation detail?
Daniel Pitts - 15 Nov 2007 21:35 GMT
>> That is very specifically a Bad Idea!
>> f.extract should NOT have a switch statement, but instead should be
[quoted text clipped - 3 lines]
> another case?
> Is this more than just an implementation detail?
Yes, it is far more than an implementation detail, it is a design principal.

Switch statements should be avoided. I know this is going to sound
snobby, but polymorphic behavior is far superior for this situation.
Not only is it likely to have better performance, it is easier to
refactor into a more useful idiom.  Say someone wants to add a custom
field extractor, its easy to change these enums into a regular class,
and have the extract be a method in an interface.  That way, the client
can say "extract this field with this approach."

Signature

Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>

mekane - 15 Nov 2007 21:47 GMT
>>> That is very specifically a Bad Idea!
>>> f.extract should NOT have a switch statement, but instead should be
[quoted text clipped - 13 lines]
> the extract be a method in an interface.  That way, the client can say
> "extract this field with this approach."

I see. That makes sense, and I would agree that polymorphism is much
more elegant. But isn't the point of an enum to say "here are all the
possible values of this type, that's it". So a better design decision
here would be to use something other than enums in the first place.
Especially if you can't say for sure that the fields will never change.

To me, an  enum and a switch work nicely together, especially when the
alternative is to write different versions of a big, complicated method
in the definition of an enum.

I'm not trying to argue, I'm just expressing an opinion.

Would you never use a switch?
Daniel Pitts - 15 Nov 2007 22:14 GMT
>>>> That is very specifically a Bad Idea!
>>>> f.extract should NOT have a switch statement, but instead should be
[quoted text clipped - 27 lines]
>
> Would you never use a switch?
I very much try to avoid switch (or if/elseif/elesif,etc..) as much as
feasible.

Switch is a remnant of procedural programming languages.  Often times it
was used to create polymorphic behavior based on a "type" token.  Well,
now you have a "type" that can do that polymorphic behavior for you.

I'm not saying there are NEVER times when you can use switch statements,
I'm just saying that by the time I need one switch statement, I probably
need two, and at that point its time to use polymorphism and create an
abstract method for each of my switch statements.  As a mater of fact, I
would *love* a tool that could take an switch(enum) and convert it to
enum.method().

Hear that JetBrains? Make it happen :-)

Signature

Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>

Lew - 16 Nov 2007 06:56 GMT
> I very much try to avoid switch (or if/elseif/elesif,etc..) as much as
> feasible.
[quoted text clipped - 11 lines]
>
> Hear that JetBrains? Make it happen :-)

One major advantage of the polymorphic approach is that you get compiler
enforcement.  You cannot "fall" into an unexpected case, or forget to
implement a behavior.

In fact, I find the quirky combination of the class attitude and the enum
constant ancestry along with the peculiarities of Java's implementation as a
pseudo-inherited Enum class with occasional implicit inner classes extending
the enum to be a strangely, emergently powerful mechanism.  For one thing,
enums may hold the power to release us from the temptation to reflection.

Back to the OP's question, Daniel, were you thinking of something like this,
only maybe better refactored?

You'd use it something like:

Object val =
  Noom.valueOf( rsMetaData.getColumnType( col ) )
      .getValue( rs, col );

(throws NPE)

<sscce>
public enum Noom
{
    BOOLEAN( Types.BOOLEAN )
    {
       @Override
       public Boolean getValue( ResultSet rs, int column )
       {
           try
           {
               return (rs.getObject( column ) == null? null :
                       Boolean.valueOf( rs.getBoolean( column )));
           }
           catch ( SQLException ex )
           {
               logger.error( "SQL Exception"+ ex.getMessage(), ex );
               return null;
           }
       }

    }
    ,
    VARCHAR( Types.VARCHAR )
    {
       @Override
       public String getValue( ResultSet rs, int column )
       {
           try
           {
               return rs.getString( column );
           }
           catch ( SQLException ex )
           {
               logger.error( "SQL Exception"+ ex.getMessage(), ex );
               return null;
           }
       }

    }
    ;
    private final int sqlType;
    private Noom( int sqlT )
    {
        this.sqlType = sqlT;
    }

    public static Noom valueOf( int sqlT )
    {
        for ( Noom noom : values() )
        {
            if ( noom.sqlType == sqlT )
            {
                return noom;
            }
        }
        return null;
    }

    private static final Logger logger = Logger.getLogger( Noom.class );

    public abstract Object getValue( ResultSet rs, int column );
}
</sscce>

Signature

Lew

Jeff Higgins - 16 Nov 2007 08:38 GMT
> <sscce>
...
> </sscce> ?
Lew - 16 Nov 2007 14:53 GMT
>> <sscce>
> ....
>> </sscce> ?

<http://www.physci.org/codes/sscce.html>

GIYF.

Signature

Lew

mekane - 16 Nov 2007 16:53 GMT
> One major advantage of the polymorphic approach is that you get compiler
> enforcement.  You cannot "fall" into an unexpected case, or forget to
> implement a behavior.

Agreed. I like compiler enforcement.

> </sscce>
> snip
> </sscce>

That example from Lew may have just completely swayed me. I figured that
 writing methods inside enum definitions would be hideous, but that
example was quite nice looking. I'm going to refactor a hobby project
I'm working on and see how it goes. I was originally going to use the
polymorphic approach, but I went with a switch instead.

Thanks for the interesting discussion.

-marty
Roedy Green - 15 Nov 2007 23:56 GMT
On Wed, 14 Nov 2007 14:54:35 -0500, Mikhail Teterin
<usenet+mill@aldan.algebra.com> wrote, quoted or indirectly quoted
someone who said :

>I would like to be able to initialize fields of an enum with /methods/ (of
>another Class).

For background read the various example bits of code at
http://mindprod.com/jgloss/enum.html

Once you understand your building blocks, I think you will be off and
running.
Signature

Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com

Mark Space - 16 Nov 2007 20:10 GMT
> Hello!
>
[quoted text clipped - 5 lines]
>  import java.util.*;
>  import java.sql.*;

The important bit for me is that last line.  SQL?  Doesn't SQL already
have some methods for dealing with tabular data?  Trying to shoe-horn
this into an enum seems like a bad idea.  Use what's there already, it's
likely to be far more useful and flexible in the long run.  Enums are
likely to box you into a corner.
Mikhail Teterin - 21 Nov 2007 01:47 GMT
> The important bit for me is that last line.  SQL?  Doesn't SQL already
> have some methods for dealing with tabular data?

It does -- there are getString(), getInt(), getDouble(), etc.

The problem I'm facing is that my rows return A LOT of columns, which must
all be tediously assigned to fields of a class. This is, roughly, what I do
in the constructor (each row creates an object of type Entry):

public class Entry
{
public String foo;
public double bar;
...
public Date woof;

public Entry(ResultSet rs)
{
 foo = rs.getString("foo");
 bar = rs.getDouble("bar");
 ...
 woof = rs.getTimestamp("woof");
}
}

What I'm looking for is a way to go through all fields and extract them from
the row in a loop. Something like:

public Entry(ResultSet rs) {
 for (WHAT? field : FieldsOfEntry?) {
  field = rs.MethodForField(field.toString());

 }
}

This would allow me to add/remove fields without changing the code every
time. Sort of make it "data-driven" with the fields of the class themselves
being the "data".

I'll look up "Hibernate", but I was hoping, a solution can be found, since
Java (unlike C) keeps the fields' names and types around at run-time
anyway...

Thanks!

-mi
Stefan Ram - 21 Nov 2007 02:19 GMT
>What I'm looking for is a way to go through all fields and
>extract them from the row in a loop.

{ final java.sql.ResultSetMetaData desc = resultSet.getMetaData();
 final int cols = desc.getColumnCount();
 for( int i = 1; i <= cols; ++i )
 java.lang.System.out.println
 ( desc.getColumnName( i )+ " " + resultSet.getString( i )); }

 I have not tested the above code, so it still might contain bugs.
 You also can get the type from the meta data. See

http://download.java.net/jdk7/docs/api/java/sql/ResultSetMetaData.html
Mikhail Teterin - 21 Nov 2007 16:47 GMT
>>What I'm looking for is a way to go through all fields and
>>extract them from the row in a loop.
[quoted text clipped - 9 lines]
>
> http://download.java.net/jdk7/docs/api/java/sql/ResultSetMetaData.html

Thank you, that's pretty cool. But that goes through the columns of the
ResultSet. I'm trying to go through the fields of my own Class, however.

I know, I can store the data in my own HashTable, but I would rather access
the fields as entry.foo and entry.meow instead of entry.getFoo() and
entry.getMeow().

Thanks!

-mi
Daniel Pitts - 21 Nov 2007 19:19 GMT
>>> What I'm looking for is a way to go through all fields and
>>> extract them from the row in a loop.
[quoted text clipped - 19 lines]
>
>  -mi
If you REALLY REALLY want to go through the fields of a class (Bad
Idea), you can use reflection.

Reflection is difficult to get right, so I suggest delegating that
responsibility to a library that is maintained by a large community.
Hibernate does exactly what you want. *Exactly* what you want. Let me
repeat. Hibernate does *exactly* what you're trying to do.

If you insist on going the route of DIY, read my warning about reflection:

<http://virtualinfinity.net/wordpress/program-design/2007/01/11/the-dangers-of-re
flection-or-put-down-that-mirror/
>

If after reading that, you feel justified in using reflection, the sun
tutorial on reflection is a good starting place:
<http://java.sun.com/docs/books/tutorial/reflect/index.html>

Just know that I've gone down the road you're trying to. It isn't a
pretty journey, and the destination isn't all that nice either.
Signature

Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>

Mikhail Teterin - 12 Dec 2007 22:58 GMT
> If you REALLY REALLY want to go through the fields of a class (Bad
> Idea)

Uhm, why? I'm quite sure, we are not alone here with the need to have an
object for every row return by an SQL-query...

> you can use reflection.

Well, here is what I cooked up:

http://aldan.algebra.com/~mi/selfsetting/SelfSettingFromSQL.java.html
or
http://aldan.algebra.com/~mi/selfsetting/SelfSettingFromSQL.java

It will set the scalar fields and even arrays. The same java.sql.ResultSet
can be used to create (or set) different objects -- the columns without
matching fields in each object's class will simply be ignored.

A typical use would be to define your own class as "extends
SelfSettingFromSQL".

> Hibernate does exactly what you want. Exactly what you want. Let me
> repeat. Hibernate does exactly what you're trying to do.

NOW, I can go and look into how someone else has done it :)

> Just know that I've gone down the road you're trying to. It isn't a
> pretty journey, and the destination isn't all that nice either.

So far I like it :) All I need now is declare the data-fields in my classes
and make sure, the SQL-queries return fields with matching names. The
tedious setting of every field (in every one of those classes) is now a
thing of the past.

The information about all the names and the types of all the fields is there
at run-time. Not using it is foolish...

-mi
Mikhail Teterin - 12 Dec 2007 23:07 GMT
> If you REALLY REALLY want to go through the fields of a class (Bad
> Idea)

Uhm, why? I'm quite sure, we are not alone here with the need to have an
object for every row return by an SQL-query...

> you can use reflection.

Well, here is what I cooked up:

http://aldan.algebra.com/~mi/selfsetting/SelfSettingFromSQL.java.html
or
http://aldan.algebra.com/~mi/selfsetting/SelfSettingFromSQL.java

It will set the scalar fields and even arrays. The same java.sql.ResultSet
can be used to create (or set) different objects -- the columns without
matching fields in each object's class will simply be ignored.

A typical use would be to define your own class as "extends
SelfSettingFromSQL".

> Hibernate does exactly what you want. Exactly what you want. Let me
> repeat. Hibernate does exactly what you're trying to do.

NOW, I can go and look into how someone else has done it :)

> Just know that I've gone down the road you're trying to. It isn't a
> pretty journey, and the destination isn't all that nice either.

So far I like it :) All I need now is declare the data-fields in my classes
and make sure, the SQL-queries return fields with matching names. The
tedious setting of every field (in every one of those classes) is now a
thing of the past.

The information about all the names and the types of all the fields is there
at run-time. Not using it is foolish...

-mi
Stefan Ram - 21 Nov 2007 22:01 GMT
>Thank you, that's pretty cool. But that goes through the columns of the
>ResultSet. I'm trying to go through the fields of my own Class, however.

public class Main
{ public static void main( final java.lang.String[] args )
 throws java.lang.Exception
 { class Example { int i; java.lang.String s; };
   for( java.lang.reflect.Field field: Example.class.getDeclaredFields() )
   java.lang.System.out.println( field.getName() ); }}

i
s
Roedy Green - 21 Nov 2007 11:39 GMT
On Wed, 14 Nov 2007 14:54:35 -0500, Mikhail Teterin
<usenet+mill@aldan.algebra.com> wrote, quoted or indirectly quoted
someone who said :

>FIELD1 (ResultSet.getString),

You will have to pass a value here. e.g.
OtherClass.resultSet.getString()

You seem to be trying to pass a method as av argument.  You can't do
that in Java.  See http://mindprod.com/jgloss/callback.html

Signature

Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com

Wayne - 21 Nov 2007 18:30 GMT
> On Wed, 14 Nov 2007 14:54:35 -0500, Mikhail Teterin
> <usenet+mill@aldan.algebra.com> wrote, quoted or indirectly quoted
[quoted text clipped - 7 lines]
> You seem to be trying to pass a method as av argument.  You can't do
> that in Java.  See http://mindprod.com/jgloss/callback.html

Of course you can create a Method object and pass that, and then
invoke it, but I don't think that's what the OP had in mind.

-Wayne


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.