Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.java.programmer > #37169 > unrolled thread

Using main from abstract class in concrete class

Started byCecil Westerhof <Cecil@decebal.nl>
First post2017-08-13 11:47 +0200
Last post2017-08-13 12:03 -0500
Articles 13 — 4 participants

Back to article view | Back to comp.lang.java.programmer


Contents

  Using main from abstract class in concrete class Cecil Westerhof <Cecil@decebal.nl> - 2017-08-13 11:47 +0200
    Re: Using main from abstract class in concrete class Andreas Leitgeb <avl@logic.at> - 2017-08-13 10:59 +0000
      Re: Using main from abstract class in concrete class Andreas Leitgeb <avl@logic.at> - 2017-08-13 11:38 +0000
    Re: Using main from abstract class in concrete class Cecil Westerhof <Cecil@decebal.nl> - 2017-08-13 15:43 +0200
    Re: Using main from abstract class in concrete class Eric Sosman <esosman@comcast-dot-net.invalid> - 2017-08-13 10:32 -0400
      Re: Using main from abstract class in concrete class Eric Sosman <esosman@comcast-dot-net.invalid> - 2017-08-13 10:37 -0400
      Re: Using main from abstract class in concrete class Cecil Westerhof <Cecil@decebal.nl> - 2017-08-13 17:17 +0200
        Re: Using main from abstract class in concrete class Andreas Leitgeb <avl@logic.at> - 2017-08-17 18:56 +0000
          Re: Using main from abstract class in concrete class Cecil Westerhof <Cecil@decebal.nl> - 2017-08-18 06:37 +0200
            Re: Using main from abstract class in concrete class Andreas Leitgeb <avl@logic.at> - 2017-08-18 19:48 +0000
              Re: Using main from abstract class in concrete class Cecil Westerhof <Cecil@decebal.nl> - 2017-08-18 23:37 +0200
                Re: Using main from abstract class in concrete class Cecil Westerhof <Cecil@decebal.nl> - 2017-08-19 01:32 +0200
    Re: Using main from abstract class in concrete class Joshua Cranmer 🐧 <Pidgeot18@verizon.invalid> - 2017-08-13 12:03 -0500

#37169 — Using main from abstract class in concrete class

FromCecil Westerhof <Cecil@decebal.nl>
Date2017-08-13 11:47 +0200
SubjectUsing main from abstract class in concrete class
Message-ID<87h8xbx0ig.fsf@munus.decebal.nl>
I have an abstract class. There can be several concrete classes that
extend this class. Is it possible to write a main in the abstract
class which will be used by the concrete classes and that in the main
a instance of the concrete class is created?

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [next] | [standalone]


#37173

FromAndreas Leitgeb <avl@logic.at>
Date2017-08-13 10:59 +0000
Message-ID<slrnop0cga.o2q.avl@logic.at>
In reply to#37169
Cecil Westerhof <Cecil@decebal.nl> wrote:
> I have an abstract class. There can be several concrete classes that
> extend this class. Is it possible to write a main in the abstract
> class which will be used by the concrete classes and that in the main
> a instance of the concrete class is created?

The first part of the question is trivially yes: derived classes that
don't provide their own main() will get your "abstract" class's main().
I guess, you knew that already.

For the other part,
https://stackoverflow.com/questions/939932/how-to-determine-main-class-at-runtime-in-threaded-java-application
seems to imply that short of some non-reliable environment variables
or system properties there is no reliable way to know which class was
originally started.

[toc] | [prev] | [next] | [standalone]


#37176

FromAndreas Leitgeb <avl@logic.at>
Date2017-08-13 11:38 +0000
Message-ID<slrnop0ep7.o2q.avl@logic.at>
In reply to#37173
Andreas Leitgeb <avl@logic.at> wrote:
> Cecil Westerhof <Cecil@decebal.nl> wrote:
>> I have an abstract class. There can be several concrete classes that
>> extend this class. Is it possible to write a main in the abstract
>> class which will be used by the concrete classes and that in the main
>> a instance of the concrete class is created?
>
> The first part of the question is trivially yes: derived classes that
> don't provide their own main() will get your "abstract" class's main().
> I guess, you knew that already.
>
> For the other part,
> https://stackoverflow.com/questions/939932/how-to-determine-main-class-at-runtime-in-threaded-java-application
> seems to imply that short of some non-reliable environment variables
> or system properties there is no reliable way to know which class was
> originally started.

maybe a workaround:

Make your abstract class the real main class, and just pass it the name of
the requested subclass as first argument:

  java your.path.AbstractMain users.path.ConcreteSub ...

(and write the AbstractMain.main method accordingly)

[toc] | [prev] | [next] | [standalone]


#37178

FromCecil Westerhof <Cecil@decebal.nl>
Date2017-08-13 15:43 +0200
Message-ID<871sofwpl8.fsf@munus.decebal.nl>
In reply to#37169
ram@zedat.fu-berlin.de (Stefan Ram) writes:

> Cecil Westerhof <Cecil@decebal.nl> writes:
>>I have an abstract class. There can be several concrete classes that
>>extend this class. Is it possible to write a main in the abstract
>>class which will be used by the concrete classes and that in the main
>>a instance of the concrete class is created?
>
>   The noun phrase »a main« does not have a general meaning in the
>   Java community. I assume you mean a method with the well-known
>   proclamation
>
> public static void main( final java.lang.String[] args )

Yes, that was what I mend. I should have been more clear.


>
>   . Main.java
>
> abstract class Abstract
> { 
>   public static void main( final java.lang.String[] args ) 
>   { try
>     { java.lang.Class.forName( args[ 0 ]).
>       getDeclaredConstructor().newInstance(); } 
>     catch
>     ( final 
>       java.lang.ClassNotFoundException | 
>       java.lang.NoSuchMethodException | 
>       java.lang.InstantiationException | 
>       java.lang.IllegalAccessException | 
>       java.lang.reflect.InvocationTargetException
>       exception )
>     { java.lang.System.err.println( exception ); }}}
>
> public final class Main extends Abstract
> { 
>
>   public Main()
>   { java.lang.System.out.println( "new Main()" ); }
>
>   public static void main( final java.lang.String[] args ) 
>   { final java.lang.String[] arguments =
>     { Main.class.getCanonicalName() };
>     Abstract.main( arguments ); }}
>
>   transcript
>
> new Main()
>

At the moment I have:
    public static void main(final String[] args) throws SQLException {
        SQL.mainWork(SQLite3.class.getCanonicalName(), args);
    }

And in SQL.java I have:
    static void mainWork(final String className, final String[] args)
        throws SQLException {
        String   action;
        String   database;
        String[] parameters;

        if (args.length < 2) {
            System.err.println("Need at least two parameters: command and database.");
            System.exit(1);
        }
        // First  argument is action
        // Second argument is database
        action     = args[0];
        database   = args[1];
        parameters = Arrays.copyOfRange(args, 2, args.length);
        try {
            SQL connection = (SQL) Class.forName(className)
                .getDeclaredConstructor(new Class<?>[] {String.class})
                .newInstance(database);
            switch (action) {
            case "--testConnection":

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [prev] | [next] | [standalone]


#37179

FromEric Sosman <esosman@comcast-dot-net.invalid>
Date2017-08-13 10:32 -0400
Message-ID<ompnlf$7j6$1@dont-email.me>
In reply to#37169
On 8/13/2017 5:47 AM, Cecil Westerhof wrote:
> I have an abstract class. There can be several concrete classes that
> extend this class. Is it possible to write a main in the abstract
> class which will be used by the concrete classes and that in the main
> a instance of the concrete class is created?

     It is certainly possible for an abstract class to implement a
`public static void main(String[])' method, and it is also possible
for the JVM to start executing your program by calling that method.

     That method can create instances of any (accessible) class it
wants, including concrete subclasses of its own abstract class.
There is, however, no automatic way for the method to learn about
any particular class -- since the method is `static' it has no `this'
on which it could call getClass(), for example.  So the method will
either need to know or be told what class to instantiate:

	public abstract class Abstract {
	    public static void main(String[] args) {
	        // "I know what I want"
	        Abstract known = new ConcreteSubclass();

	        // "I do what I'm told"
	        // (exception-handling omitted)
	        Class<?> clown = Class.forName(args[0]);
	        Abstract learned = (Abstract) clown.newInstance();

	        ...
	    }
	}

     Finally, as to "used by the concrete classes" -- it's a `public'
method, so methods of the subclasses can certainly call it if that's
what you mean by "use."  What *won't* work is to tell the JVM to run
the main() method of a subclass that doesn't actually have one, and
have the JVM somehow know to run Abstract::main in its place.  Static
methods are not inherited (nor inheritable).  You could give each
concrete subclass its own main() that in turn calls the main() of
the abstract class:

	class ConcreteSubclass extends Abstract {
	    public static void main(String[] args) {
	        Abstract.main(args);
	        // super.main(args) might work; not sure off-hand
	    }
	}

However, in this situation I think it'd be simpler for the subclass
to do its own instantiating and just hand the object to a method of
the superclass:

	public abstract class Abstract2 {
	    protected static void start(Abstract2 obj, String[] args) {
	        // obj is the desired instance
	        ...
	    }
	}

	class Concrete2 extends Abstract2 {
	    public static void main(String[] args) {
	        Abstract.start(new Concrete2(), args);
	    }
	}

-- 
esosman@comcast-dot-net.invalid
Twelve hundred fifty-six days to go.

[toc] | [prev] | [next] | [standalone]


#37180

FromEric Sosman <esosman@comcast-dot-net.invalid>
Date2017-08-13 10:37 -0400
Message-ID<ompnve$8g6$1@dont-email.me>
In reply to#37179
On 8/13/2017 10:32 AM, Eric Sosman wrote:
> [...]
> What *won't* work is to tell the JVM to run
> the main() method of a subclass that doesn't actually have one, and
> have the JVM somehow know to run Abstract::main in its place.

     ... for suitable values of "*won't*", such as (for example)
"WILL CERTAINLY".

     Sorry about that.

-- 
esosman@comcast-dot-net.invalid
Twelve hundred fifty-six days to go.

[toc] | [prev] | [next] | [standalone]


#37181

FromCecil Westerhof <Cecil@decebal.nl>
Date2017-08-13 17:17 +0200
Message-ID<87wp67v6of.fsf@munus.decebal.nl>
In reply to#37179
Eric Sosman <esosman@comcast-dot-net.invalid> writes:

> However, in this situation I think it'd be simpler for the subclass
> to do its own instantiating and just hand the object to a method of
> the superclass:
>
> 	public abstract class Abstract2 {
> 	    protected static void start(Abstract2 obj, String[] args) {
> 	        // obj is the desired instance
> 	        ...
> 	    }
> 	}
>
> 	class Concrete2 extends Abstract2 {
> 	    public static void main(String[] args) {
> 	        Abstract.start(new Concrete2(), args);
> 	    }
> 	}

I do something like that now:
    public class SQLite3 extends SQL {
        // ################ main
        public static void main(final String[] args) throws SQLException {
            SQL.mainWork(SQLite3.class.getCanonicalName(), args);
        }

The ‘problem’ is that I have to write it for every concrete class, but
that is doable.

I renamed main in the abstract class SQL to mainWork and removed
public.

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [prev] | [next] | [standalone]


#37259

FromAndreas Leitgeb <avl@logic.at>
Date2017-08-17 18:56 +0000
Message-ID<slrnopbpu1.o2q.avl@logic.at>
In reply to#37181
Cecil Westerhof <Cecil@decebal.nl> wrote:
> I do something like that now:
>     public class SQLite3 extends SQL {
>         // ################ main
>         public static void main(final String[] args) throws SQLException {
>             SQL.mainWork(SQLite3.class.getCanonicalName(), args);
>         }

Why not change "mainWork" such, that it accepts a Class ref directly,
rather than the canonical name?

Maybe even simpler would be to have it accept a SQL ref and just pass
it: new SQLite3()

There is certainly more than one way to Rome.

> I renamed main in the abstract class SQL to mainWork and removed
> public.

You might want to add "protected", so that derived classes even in
other packages can still call it.  "protected" is more permissive than 
default access.

[toc] | [prev] | [next] | [standalone]


#37268

FromCecil Westerhof <Cecil@decebal.nl>
Date2017-08-18 06:37 +0200
Message-ID<87valljxtp.fsf@munus.decebal.nl>
In reply to#37259
Andreas Leitgeb <avl@logic.at> writes:

> Cecil Westerhof <Cecil@decebal.nl> wrote:
>> I do something like that now:
>>     public class SQLite3 extends SQL {
>>         // ################ main
>>         public static void main(final String[] args) throws SQLException {
>>             SQL.mainWork(SQLite3.class.getCanonicalName(), args);
>>         }
>
> Why not change "mainWork" such, that it accepts a Class ref directly,
> rather than the canonical name?
>
> Maybe even simpler would be to have it accept a SQL ref and just pass
> it: new SQLite3()
>
> There is certainly more than one way to Rome.

The idea is that mainWork is always called from the main of a class.
But I can always ponder about this possibility.
Also I probably make AbstractSQL a concrete class named SQLWrapper.


>> I renamed main in the abstract class SQL to mainWork and removed
>> public.
>
> You might want to add "protected", so that derived classes even in
> other packages can still call it.  "protected" is more permissive than 
> default access.

It is something to think about. Is there a good reason to want derived
classes in another package?


I am thinking about changing AbstractSQL to SQLWrapper (and removing
abstract) and letting SQLWrapper be called with a URLPrefix, so it can
be used for databases where there is no concrete class for yet.


There are databases that can use in memory databases. For example
sqlite3 uses :memory:. I first had testDB.sqlite as database to test.
I am thinking about changing it to :memory:. Is that good enough, or
should I always check also for a stored database?

For sqlite3 I need to use (also) a ‘real’ database anyway, because I
need to check the lock functionality.


I have unit tests to test AbstractSQL, SQLResultSet and SQLStatement
(the classes I so far defined). I test those classes with the SQLite3
class. Is that good enough, or should they be tested with every
concrete class?

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [prev] | [next] | [standalone]


#37276

FromAndreas Leitgeb <avl@logic.at>
Date2017-08-18 19:48 +0000
Message-ID<slrnopehbp.o2q.avl@logic.at>
In reply to#37268
Cecil Westerhof <Cecil@decebal.nl> wrote:
> Andreas Leitgeb <avl@logic.at> writes:
>> Cecil Westerhof <Cecil@decebal.nl> wrote:
>>> I do something like that now:
>>>     public class SQLite3 extends SQL {
>>>         // ################ main
>>>         public static void main(final String[] args) throws SQLException {
>>>             SQL.mainWork(SQLite3.class.getCanonicalName(), args);
>>>         }
>> Why not change "mainWork" such, that it accepts a Class ref directly,
>> rather than the canonical name?
>>
>> Maybe even simpler would be to have it accept a SQL ref and just pass
>> it: new SQLite3()
>
> The idea is that mainWork is always called from the main of a class.

Yes, that was already pretty clear from your example snippet.

But even a static method of a subclass *can* create an instance of
its own class (and also of any other accessible class):

  public class SQLite3 extends SQL {
      // ################ main
      public static void main(final String[] args) throws SQLException {
          SQL.mainWork(new SQLite3(), args);
      }

and SQL.mainWork would be declared as taking (SQL sqlSubInstance, String[] args)

If you expect that your abstract class will need to create more
instances of the relevant subclass, then using the factory pattern
might be preferable to repeated .forName'ing.


>> You might want to add "protected", so that derived classes even in
>> other packages can still call it.  "protected" is more permissive than 
>> default access.
>
> Is there a good reason to want derived classes in another package?

In some earlier posts you expressed your intention to make your class
also usable for others.

If someone else wanted to derive from your abstract SQL class, they
probably wouldn't want to put their derived class in a package starting
with nl.decebal., but probably rather in a package reflecting their
own domain.

[toc] | [prev] | [next] | [standalone]


#37278

FromCecil Westerhof <Cecil@decebal.nl>
Date2017-08-18 23:37 +0200
Message-ID<87k220iml8.fsf@munus.decebal.nl>
In reply to#37276
Andreas Leitgeb <avl@logic.at> writes:

> Cecil Westerhof <Cecil@decebal.nl> wrote:
>> Andreas Leitgeb <avl@logic.at> writes:
>>> Cecil Westerhof <Cecil@decebal.nl> wrote:
>>>> I do something like that now:
>>>>     public class SQLite3 extends SQL {
>>>>         // ################ main
>>>>         public static void main(final String[] args) throws SQLException {
>>>>             SQL.mainWork(SQLite3.class.getCanonicalName(), args);
>>>>         }
>>> Why not change "mainWork" such, that it accepts a Class ref directly,
>>> rather than the canonical name?
>>>
>>> Maybe even simpler would be to have it accept a SQL ref and just pass
>>> it: new SQLite3()
>>
>> The idea is that mainWork is always called from the main of a class.
>
> Yes, that was already pretty clear from your example snippet.
>
> But even a static method of a subclass *can* create an instance of
> its own class (and also of any other accessible class):
>
>   public class SQLite3 extends SQL {
>       // ################ main
>       public static void main(final String[] args) throws SQLException {
>           SQL.mainWork(new SQLite3(), args);
>       }
>
> and SQL.mainWork would be declared as taking (SQL sqlSubInstance,
> String[] args)

There is some checking done in mainWork. But I could put that in a
separate function and call this from the main and return this to the
main. It makes the mains a little bigger, but removes not that clear
code from mainWork.
Something to implement.


> If you expect that your abstract class will need to create more
> instances of the relevant subclass, then using the factory pattern
> might be preferable to repeated .forName'ing.

At the moment that does not seem very likely. The main function is
only for some simple functions. For example I use it with SQLite to
check the lock status of databases.


>>> You might want to add "protected", so that derived classes even in
>>> other packages can still call it.  "protected" is more permissive than 
>>> default access.
>>
>> Is there a good reason to want derived classes in another package?
>
> In some earlier posts you expressed your intention to make your class
> also usable for others.
>
> If someone else wanted to derive from your abstract SQL class, they
> probably wouldn't want to put their derived class in a package starting
> with nl.decebal., but probably rather in a package reflecting their
> own domain.

That is a good point. I will change it.

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [prev] | [next] | [standalone]


#37279

FromCecil Westerhof <Cecil@decebal.nl>
Date2017-08-19 01:32 +0200
Message-ID<87fucoih9a.fsf@munus.decebal.nl>
In reply to#37278
Cecil Westerhof <Cecil@decebal.nl> writes:

> Andreas Leitgeb <avl@logic.at> writes:
>
>> Cecil Westerhof <Cecil@decebal.nl> wrote:
>>> Andreas Leitgeb <avl@logic.at> writes:
>>>> Cecil Westerhof <Cecil@decebal.nl> wrote:
>>>>> I do something like that now:
>>>>>     public class SQLite3 extends SQL {
>>>>>         // ################ main
>>>>>         public static void main(final String[] args) throws SQLException {
>>>>>             SQL.mainWork(SQLite3.class.getCanonicalName(), args);
>>>>>         }
>>>> Why not change "mainWork" such, that it accepts a Class ref directly,
>>>> rather than the canonical name?
>>>>
>>>> Maybe even simpler would be to have it accept a SQL ref and just pass
>>>> it: new SQLite3()
>>>
>>> The idea is that mainWork is always called from the main of a class.
>>
>> Yes, that was already pretty clear from your example snippet.
>>
>> But even a static method of a subclass *can* create an instance of
>> its own class (and also of any other accessible class):
>>
>>   public class SQLite3 extends SQL {
>>       // ################ main
>>       public static void main(final String[] args) throws SQLException {
>>           SQL.mainWork(new SQLite3(), args);
>>       }
>>
>> and SQL.mainWork would be declared as taking (SQL sqlSubInstance,
>> String[] args)
>
> There is some checking done in mainWork. But I could put that in a
> separate function and call this from the main and return this to the
> main. It makes the mains a little bigger, but removes not that clear
> code from mainWork.
> Something to implement.

It has become:
	public static void main(final String[] args) throws SQLException {
		MainWorkParams params = checkArgs(args);

		try (SQLite3 sqlite3 = new SQLite3(
				params.database,
				params.user,
				params.password)) {
			sqlite3.mainWork(params.action, params.restArgs);
		}
	}


>>>> You might want to add "protected", so that derived classes even in
>>>> other packages can still call it.  "protected" is more permissive than 
>>>> default access.
>>>
>>> Is there a good reason to want derived classes in another package?
>>
>> In some earlier posts you expressed your intention to make your class
>> also usable for others.
>>
>> If someone else wanted to derive from your abstract SQL class, they
>> probably wouldn't want to put their derived class in a package starting
>> with nl.decebal., but probably rather in a package reflecting their
>> own domain.
>
> That is a good point. I will change it.

Done.

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [prev] | [next] | [standalone]


#37186

FromJoshua Cranmer 🐧 <Pidgeot18@verizon.invalid>
Date2017-08-13 12:03 -0500
Message-ID<omq0h2$33q$1@dont-email.me>
In reply to#37169
On 8/13/2017 4:47 AM, Cecil Westerhof wrote:
> I have an abstract class. There can be several concrete classes that
> extend this class. Is it possible to write a main in the abstract
> class which will be used by the concrete classes and that in the main
> a instance of the concrete class is created?

Well, your question is gibberish, but I'm assuming what you're really 
asking is "can I have a static method that is invoked by dynamic 
dispatch on the receiver class?" The answer to that question is "not 
really."

So static methods are inherited in scope, such that calling 'Sub.foo' 
looks for a static method in Sub first and then looks for it in Super if 
it couldn't find it. But static methods have no concept of a "this" 
pointer like instance methods do. Thus, there is nothing that could 
possibly be dispatched on.

You can work around this flaw by using Class objects and using 
reflection to search for the method. Of course, the superclass method 
still doesn't have a notion of the current class object being invoked, 
so you'd have to pass the class parameter in. And you face the issue 
that this kind of reflection is not first-class in Java.

An alternative? Well, factories! Constructors are essentially a kind of 
static method [1], and it's very desirable to be able to have some sort 
of generic construction mechanism. The standard design pattern is to 
have a factory class, which has a method that can actually construct the 
object in question. Now you can add on to this factory class other 
methods that can dispatch on the factory class instance--which is 
effectively the same as class object itself.


[1] Okay, internally they're a special nonvirtual method. But given that 
you need to know the type of the receiver to execute the new opcode, 
they're more like a static method than an instance method in terms of use.


-- 
Beware of bugs in the above code; I have only proved it correct, not 
tried it. -- Donald E. Knuth

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.java.programmer


csiph-web