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


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

Generics

Started byEric Douglas <e.d.programmer@gmail.com>
First post2016-08-17 11:59 -0700
Last post2016-08-18 05:34 -0700
Articles 7 — 4 participants

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


Contents

  Generics Eric Douglas <e.d.programmer@gmail.com> - 2016-08-17 11:59 -0700
    Re: Generics Marcel Mueller <news.5.maazl@spamgourmet.org> - 2016-08-17 21:20 +0200
    Re: Generics Eric Sosman <esosman@comcast-dot-net.invalid> - 2016-08-17 15:22 -0400
      Re: Generics Eric Douglas <e.d.programmer@gmail.com> - 2016-08-17 14:03 -0700
        Re: Generics Eric Sosman <esosman@comcast-dot-net.invalid> - 2016-08-17 20:06 -0400
        Re: Generics Robert Klemme <shortcutter@googlemail.com> - 2016-08-18 08:23 +0200
          Re: Generics Eric Douglas <e.d.programmer@gmail.com> - 2016-08-18 05:34 -0700

#35378 — Generics

FromEric Douglas <e.d.programmer@gmail.com>
Date2016-08-17 11:59 -0700
SubjectGenerics
Message-ID<681a67de-8a78-46ab-a028-5176a48df402@googlegroups.com>
Say we have 3 classes.

public class TestA<E extends TestB> {
}

public abstract class TestB {
}

public class TestC extends TestB {
}

Now we create an instance.

TestA<TestC> testMe = new TestA();

Now within class TestA how do we tell it instance testMe is referencing TestC?
The only thing I could find is to add a method or constructor which passes in a reference to TestC.class or the class name, so there's that for last resort, but I do want to make sure if I have to pass it in separately that it matches the value of E.

[toc] | [next] | [standalone]


#35379

FromMarcel Mueller <news.5.maazl@spamgourmet.org>
Date2016-08-17 21:20 +0200
Message-ID<np2dd0$mtg$1@gwaiyur.mb-net.net>
In reply to#35378
On 17.08.16 20.59, Eric Douglas wrote:
> Say we have 3 classes.
>
> public class TestA<E extends TestB> {
> }
>
> public abstract class TestB {
> }
>
> public class TestC extends TestB {
> }
>
> Now we create an instance.
>
> TestA<TestC> testMe = new TestA();
>
> Now within class TestA how do we tell it instance testMe is referencing TestC?

Not at all.

Java uses the type erasure pattern to implement generics. This means 
that any instance of TestA will never know to what type it relies to. 
Basically generics in Java are only compile time checks for type 
integrity and automatically generated down casts in the compiled code.
In fact you can even cast from TestA<TestB> to TestA<TestC> and with 
some warnings also to TestA which is equvalent to TestA<object>. And 
like any other downcast the are valid as long as the TestA instance is 
only used with TestC instances so far.

This is different e.g. from .NET where you can access the type 
information at compile time and run time per reflection. And it is even 
more different from C++ templates where even the implementation for each 
type might be entirely distinct.

> The only thing I could find is to add a method or constructor which passes in a reference to TestC.class or the class name,

Yes, that's an option.

But the more interesting question is: why do you need to know the type 
of TestC within of TestA? It won't help you much without reflection.

You should also keep in mind that even if the type definition says 
TestA<TestC> your TestA instance might be used to handle object of type 
TestD which inherits from TestC. So the compile time type and the 
runtime type are not the same unless TestC is final.


Marcel

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


#35380

FromEric Sosman <esosman@comcast-dot-net.invalid>
Date2016-08-17 15:22 -0400
Message-ID<np2dhf$tvo$1@dont-email.me>
In reply to#35378
On 8/17/2016 2:59 PM, Eric Douglas wrote:
> Say we have 3 classes.
>
> public class TestA<E extends TestB> {
> }
>
> public abstract class TestB {
> }
>
> public class TestC extends TestB {
> }
>
> Now we create an instance.
>
> TestA<TestC> testMe = new TestA();

     TestA<TestC> testMe = new TestA<TestC>();

or, more briefly,

     TestA<TestC> testMe = new TestA<>();

> Now within class TestA how do we tell it instance testMe is referencing TestC?
> The only thing I could find is to add a method or constructor which passes in a reference to TestC.class or the class name, so there's that for last resort, but I do want to make sure if I have to pass it in separately that it matches the value of E.

     I'm not sure what you're asking, so I'll try answers to two
different questions -- if neither is helpful, please post again.

     1) The methods and fields and whatnot within TestA should
traffic in things of type "E", like

	public class TestA<E extends TestB> {
	    private final E theTest;

	    public TestA(E theTest) {
	        this.theTest = theTest;
	    }

	    public E getTheTest() {
	        return theTest;
	    }

	    // ...
	}

     2) If some code inside TestA needs to be aware of the TestC-ness
of some reference or other, use "instanceof":

	public class TestA<E extends TestB> {
	    private boolean isItTestC(E thing) {
	        return thing instanceof TestC;
	    }
	}

However, I'd view this need with suspicion.  The "instanceof" operator
(and its reflective counterparts) are often signs that the design
should be reconsidered -- and perhaps retained, but only after due
thought has lowered the raised eyebrows.  More commonly, it's a sign
that polymorphism is not being used to best advantage.

-- 
esosman@comcast-dot-net.invalid
The Tooth Fairy has gone high-tech, now pays in Bitecoin.

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


#35384

FromEric Douglas <e.d.programmer@gmail.com>
Date2016-08-17 14:03 -0700
Message-ID<2ce12c5a-fdb0-43ad-b4a3-4ffc28836df3@googlegroups.com>
In reply to#35380
On Wednesday, August 17, 2016 at 3:22:32 PM UTC-4, Eric Sosman wrote:
> However, I'd view this need with suspicion.  The "instanceof" operator
> (and its reflective counterparts) are often signs that the design
> should be reconsidered -- and perhaps retained, but only after due
> thought has lowered the raised eyebrows.  More commonly, it's a sign
> that polymorphism is not being used to best advantage.

This seemed like a separate topic for a new thread but in this case is related to the XML.  As the design states, TestA is just a wrapper class.  It holds a variable that is a List<E> which may contain anything which extends TestB which may be TestC, or TestD, etc.  I want each instance of TestA to be able to marshal itself which requires knowing the specific classes of TestC, etc. but I want to hide the marshalling so the instance of TestA only has to tell it that class name once.  So I'm using a method to pass in the class name because TestA is the root object for this XML so adding a parameter to the constructor gets ugly..

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


#35387

FromEric Sosman <esosman@comcast-dot-net.invalid>
Date2016-08-17 20:06 -0400
Message-ID<np2u7f$lgl$1@dont-email.me>
In reply to#35384
On 8/17/2016 5:03 PM, Eric Douglas wrote:
> On Wednesday, August 17, 2016 at 3:22:32 PM UTC-4, Eric Sosman wrote:
>> However, I'd view this need with suspicion.  The "instanceof" operator
>> (and its reflective counterparts) are often signs that the design
>> should be reconsidered -- and perhaps retained, but only after due
>> thought has lowered the raised eyebrows.  More commonly, it's a sign
>> that polymorphism is not being used to best advantage.
>
> This seemed like a separate topic for a new thread but in this case is related to the XML.

     Okay.  Disclaimer: I'm not an expert on XML, and even less of an
expert on frameworks-that-semiautomatically-XMLize-Java-classes, so
much of what follows may be worth less than you're paying for it ...

> As the design states, TestA is just a wrapper class.  It holds a variable that is a List<E> which may contain anything which extends TestB which may be TestC, or TestD, etc.

     Back on familiar ground, I must ask: Do you really need a List<E>,
or would a List<TestB> be just as good (possibly better)?  There *is*
a difference, but I'm not sure you've made a case one way or the other.

> I want each instance of TestA to be able to marshal itself which requires knowing the specific classes of TestC, etc.

     This strikes me as bass-ackwards design: You're asking the container
class TestA to have special knowledge of every possible contained class
TestC, TestD, TestUnanticipated, TestUnheardOf, TestOsterone, ...  Does
that strike you as a good idea?  Thought experiment: Should Object's
toString() method have special knowledge of all subclasses of Object,
so that it can know how to render them all?

     So, you've introduced the abstract class TestB to be the superclass
of all the possible contained classes; that's fine.  Why shouldn't TestB
have a (probably abstract) method to do the required marshalling, so
TestA (the container; damn, I wish you'd used descriptive names!) can
call it on each contained object instance?

> but I want to hide the marshalling so the instance of TestA only has to tell it that class name once.

     ... whereas a more "traditional" design -- each class is responsible
for its own marshalling -- would require telling TestA the class name,
er, zero times.  *And* would allow for future introduction of TestImony
without modifying TestA.

> So I'm using a method to pass in the class name because TestA is the root object for this XML so adding a parameter to the constructor gets ugly..

     ... and I'm out of my comfort zone again, not being familiar with
the oddities of these various auto-XMLization frameworks.  Perhaps they
really *do* require bass-ackwards object-disoriented design, but if so
I'd have to question their worth.

     As I said, possibly worth less than you paid ...

-- 
esosman@comcast-dot-net.invalid
The Tooth Fairy has gone high-tech, now pays in Bitecoin.

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


#35388

FromRobert Klemme <shortcutter@googlemail.com>
Date2016-08-18 08:23 +0200
Message-ID<e1l2iaFpk2aU1@mid.individual.net>
In reply to#35384
On 17.08.2016 23:03, Eric Douglas wrote:
> On Wednesday, August 17, 2016 at 3:22:32 PM UTC-4, Eric Sosman
> wrote:
>> However, I'd view this need with suspicion.  The "instanceof"
>> operator (and its reflective counterparts) are often signs that the
>> design should be reconsidered -- and perhaps retained, but only
>> after due thought has lowered the raised eyebrows.  More commonly,
>> it's a sign that polymorphism is not being used to best advantage.
>
> This seemed like a separate topic for a new thread but in this case
> is related to the XML.  As the design states, TestA is just a wrapper
> class.  It holds a variable that is a List<E> which may contain
> anything which extends TestB which may be TestC, or TestD, etc.  I
> want each instance of TestA to be able to marshal itself which
> requires knowing the specific classes of TestC, etc. but I want to
> hide the marshalling so the instance of TestA only has to tell it
> that class name once.

That does not seem to make sense - or I am misunderstanding you. 
Depending on the contents of the List there may be any number of classes 
(including zero).  You would need the type per entry in the list and 
then you can just ask the individual object via getClass().

Main question is, what is that type used for?  As has been suggested the 
OO solution would be to have all classes implement their own marshalling 
(see how custom serialization works).  If that cannot be done because 
marshalling is supposed to be a separate aspect then you can have a 
Map<Class<? extends E>,Marshaller> to attach additional functionality to 
these classes.

>  So I'm using a method to pass in the class
> name because TestA is the root object for this XML so adding a
> parameter to the constructor gets ugly..

What about JAXB?

Kind regards

	robert

-- 
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

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


#35390

FromEric Douglas <e.d.programmer@gmail.com>
Date2016-08-18 05:34 -0700
Message-ID<9f75e726-f69c-45a8-a4ba-fc60c74b110a@googlegroups.com>
In reply to#35388
On Thursday, August 18, 2016 at 2:23:26 AM UTC-4, Robert Klemme wrote:
> That does not seem to make sense - or I am misunderstanding you. 
> Depending on the contents of the List there may be any number of classes 
> (including zero).  You would need the type per entry in the list and 
> then you can just ask the individual object via getClass().
> 
> Main question is, what is that type used for?  As has been suggested the 
> OO solution would be to have all classes implement their own marshalling 
> (see how custom serialization works).  If that cannot be done because 
> marshalling is supposed to be a separate aspect then you can have a 
> Map<Class<? extends E>,Marshaller> to attach additional functionality to 
> these classes.

I think I see what you mean.

I start with the root class declared as such:
public class DataFile<DataRecordT extends DataRecord> {

Within that I have a variable that holds all records of one file type:
private TreeMap<String, DataRecordT> records;

Now, say we have Customer Master file CUST which is a Java class which extends DataRecord, and has a matching xsd file CUST.xsd.  I was using the DataFile (root element) class as the file instance for every file, specifically for CUST declaring as such.
final DataFile<CUST> myCUST = new DataFile<>();

Now to add a new record to this file I'm passing in an instance which adds it to the list.
CUST myCUSTrec = new CUST();
myCUSTrec.setCUSTNAME("John Doe")
myCUST.writeRecord(myCUSTrec);

Now while we can have a second file let's say open sales orders called OPENSO set up the same way, with a Java matching that name extending DataRecord and a matching .xsd, and we can expect to write to it the same way this may not be the clearest structure?

While trying to do it all from the DataFile class I set up class variables as such:
     private Class fileTypeClass;
     private String fileTypeClassName;
Initially I told it to request the file name when we open the file, though it would probably make more sense to do that when we create the instance of DataFile, if not from the constructor then using a static newInstance() method, but passing the string regardless:
     public void openFile(final String fileName) throws ClassNotFoundException {
          fileTypeClass = Class.forName("com.mypackage." + fileName);
          fileTypeClassName = fileTypeClass.getSimpleName();
          unmarshalXml();
     }

While each data file has it's own Java file for field specific stuff ie setCUSTNAME(), all the record stuff (reading/writing xml file, finding next record) is the same logic for every file so I don't want to duplicate that.

     private void unmarshalXml() {
          records = null;
          try {
               final File file = new File(DATAPATH + fileTypeClassName + ".xml");
               if (file.exists() && file.canRead()) {
                    final ArrayList<Class> jClasses = new ArrayList();
                    jClasses.add(DataFile.class);
                    jClasses.add(fileTypeClass);
                    final SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
                    Schema schema = null;
                    final URL schemaURL = DataFile.class.getResource("/stylesheets/" + fileTypeClassName + ".xsd");
                    if (schemaURL != null) {
                         try {
                              schema = sf.newSchema(schemaURL);
                         } catch (final SAXException e) {
                              e.printStackTrace();
                         }
                    }
                    final JAXBContext jaxbContext = JAXBContext.newInstance(jClasses.toArray(new Class[0]));
                    final Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
                    if (schema != null) {
                         jaxbUnmarshaller.setSchema(schema);
                    }
                    jaxbUnmarshaller.setEventHandler(new MyValidationEventHandler());
                    DataFile data = (DataFile) jaxbUnmarshaller.unmarshal(file);
                    setRecords(data.getRecords());
                    data = null;
               }
          } catch (final JAXBException e) {
               e.printStackTrace();
          }
     }

and a matching private generic to create the xml which gets called either from writeRecord() and removeRecord(), or if that's too much overhead then just on closeFile().

     /**
      * Write data to file; do this on close or every time we add/update a record?
      */
     private void marshalXml() {
          try {
               final File file = new File(DATAPATH + fileTypeClassName + ".xml");
               final ArrayList<Class> jClasses = new ArrayList();
               jClasses.add(DataFile.class);
               jClasses.add(BBaTreeMapType.class);
               Schema schema = null;
               if (records != null && records.size() > 0) {
                    jClasses.add(fileTypeClass);
                    final SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
                    final URL schemaURL = DataFile.class.getResource("/stylesheets/" + fileTypeClass.getSimpleName() + ".xsd");
                    if (schemaURL != null) {
                         schema = sf.newSchema(schemaURL);
                    }
               }
               final JAXBContext jaxbContext = JAXBContext.newInstance(jClasses.toArray(new Class[0]));
               final Marshaller jaxbMarshaller = jaxbContext.createMarshaller();

               // default = UTF-8
               jaxbMarshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
               // output pretty printed
               jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
               // jaxbMarshaller.setProperty(Marshaller.JAXB_NO_NAMESPACE_SCHEMA_LOCATION, "");
               jaxbMarshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "");
               // default = false
               jaxbMarshaller.setProperty(Marshaller.JAXB_FRAGMENT, false);
               if (schema != null) {
                    jaxbMarshaller.setSchema(schema);
               }
               jaxbMarshaller.setEventHandler(new MyValidationEventHandler());
               // for debugging only
               jaxbMarshaller.marshal(this, System.out);
               jaxbMarshaller.marshal(this, file);
          } catch (final JAXBException e) {
               e.printStackTrace();
          } catch (final SAXException e) {
               e.printStackTrace();
          }
     }

Now with this structure you could declare a generic as such
final DataFile<DataRecord> myFILE = new DataFile<>();

Now you could attempt to put records into one DataFile from 2 different types which extend DataRecord, though since each file has XSD if we run the validation on the add it would only allow one type since I set it up to accept a single file reference.

So the alternative is to set up DataFile as abstract so we can't try that, and set up each individual file with a main class that is the root and extends DataFile?

[toc] | [prev] | [standalone]


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


csiph-web