天道酬勤,学无止境

Generics and ReadObject

Question

I have a simple server that uses generics and object serialization. (T is the input format, U is the output format). A simplified version that only deals with input is shown below:

public class Server <T, U> implements Runnable {

    @override
    public void run () {

    try (ObjectInputStream inReader = new ObjectInputStream (this.connection.getInputStream ())) {
        T   lastObj;
        while (true) {
            lastObj = (T) inReader.readObject ();
            System.out.println (lastObj.getClass ().getName ());
            if (null != lastObj) {
                this.acceptMessage (lastObj);
            }
        } catch (IOException | ClassNotFoundException ex) {
            Logger.getLogger (this.getClass ().getName ()).log (Level.SEVERE, ex.getMessage (), ex);
        }
    }
}

If I start the server with

Server <Integer, String> thisServer = new Server ();

then I would expect it to only accept Integer objects and return Strings as output.

However, I was using a simple client that read from System.in for testing and sending strings to the server. Much to my surprise, the server accepted the input. Just to make sure that it really was accepting an object that wasn't of type T I added the line to echo out what class the last object was.

System.out.println (lastObj.getClass ().getName ());

This did in fact output Java.lang.String.

This is totally unexpected. I thought Generics were supposed to allow you to pass objects of a type that wasn't specified in the class itself without having to cast objects? The cast to T doesn't seem to have an effect either.

This means in theory I could attack the server (or its consumer) by feeding it Java objects of a type it wasn't expecting. Whilst this doesn't have to be super-robust (because it's an academic project and not production software) I think knowing that the object that you got with readObject wasn't the one you wanted so you can deal with it is important.

I tried adding the following, but it just got flagged up as a compile time error.

if (lastObj instanceof T) {
}

How would I handle this correctly?

Answer1

As others have pointed out, this issue is related to type erasure. At runtime, T has been erased to its upper bound, Object.

When you cast to T, that's known as an unchecked cast because it doesn't exist at runtime. Instead, other casts have been inserted by the compiler in places where instances of T are assigned back to a reified type like Integer. When run consumes an unexpected type like String, the JVM can't tell the difference, and it doesn't fail fast. If there were a method T getLastObject, the caller of that method might fail instead:

Server<Integer, String> thisServer = ...;
thisServer.run(); // consumes a String, but doesn't fail
Integer i = thisServer.getLastObject(); // ClassCastException thrown here

The workaround is to provide Server with a Class<T> object representing the type of object to be consumed and use the cast method:

public class Server <T, U> implements Runnable {

   private final Class<T> readObjectType;

   public Server(final Class<T> readObjectType) {
       this.readObjectType = readObjectType;
   }

    @Override
    public void run () {

    try (ObjectInputStream inReader = new ObjectInputStream (this.connection.getInputStream ())) {
        T   lastObj;
        while (true) {
            lastObj = readObjectType.cast(inReader.readObject());
            System.out.println (lastObj.getClass ().getName ());
            if (null != lastObj) {
                this.acceptMessage (lastObj);
            }
        } catch (IOException | ClassNotFoundException ex) {
            Logger.getLogger (this.getClass ().getName ()).log (Level.SEVERE, ex.getMessage (), ex);
        }
    }
}

readObjectType.cast(inReader.readObject()) will now fail fast when the wrong type of object has been read.

Answer2

The thing to remember about generics is that they are compile time checks only. Their sole purpose is to remove type casting everywhere.

the following line

lastObj = (T) inReader.readObject ();

at runtime translates to

lastObj = (Object) inReader.readObject ();

not

lastObj = (Integer) inReader.readObject ();

to allow for runtime casting what we can do is this

public class Server <T extends Integer, U> implements Runnable {

this will translate at

lastObj = (T) inReader.readObject ();

to

lastObj = (Integer) inReader.readObject ();

So lastObj can start to use Integer methods. This will also throw a ClassCastException should the read object not be an Integer. There are limitations on what Generics can achieve in java due to the runtime erasure.

The reason we need a Cast is to do with the separation between compile time checking and runtime checking.

InputStream.readObject() returns an Object not a T whatever that is so while the runtime says T is Object, the Compile time checker cannot make that assumption so must ask for a cast.

Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • Lines and paragraphs break automatically.
  • Web page addresses and email addresses turn into links automatically.

相关推荐
  • How to write and read java serialized objects into a file
    Question I am going to write multiple objects to a file and then retrieve them in another part of my code. My code has no error, but it is not working properly. Could you please help me find what is wrong about my code. I read different codes from different websites, but none of them worked for me! Here is my code to write my objects to a file: MyClassList is an arraylist which includes objects of my class (which must be written to a file). for (int cnt = 0; cnt < MyClassList.size(); cnt++) { FileOutputStream fout = new FileOutputStream("G:\\address.ser", true); ObjectOutputStream oos = new
  • How to Convert JSON object to Custom C# object?
    Question Is there an easy way to populate my C# Object with the JSON object passed via AJAX? This is the JSON Object passed to C# WEBMETHOD from the page using JSON.stringify { "user": { "name": "asdf", "teamname": "b", "email": "c", "players": ["1", "2"] } } C# WebMetod That receives the JSON Object [WebMethod] public static void SaveTeam(Object user) { } C# Class that represents the object structure of JSON Object passed in to the WebMethod public class User { public string name { get; set; } public string teamname { get; set; } public string email { get; set; } public Array players { get
  • Summary of Android advanced interview questions-Java articles (1)
    (1) Java basic interview knowledge points 1. The difference between ==, equals and hashCode in java “==”: == is an operator, used to compare two values, whether the memory addresses of two objects are equal “equals()”: Equals is a method of the Object class. By default, it compares whether two objects are the same object. The internal implementation is achieved through "==". If you want to compare the other contents of the two objects, you can override the equals method “hashCode()”: hashCoed is also a method in the Object class. The return value is the hash code of an object. The hash code of
  • Android senior engineer interview questions finishing-java interview questions
    I believe that before each interview, everyone will brush a lot of interview questions to interview with various companies. Let's sort out the interview questions on android to share with you. This article is mainly divided into the following parts: java interview questions Android interview questionsAdvanced Development Technical Interview QuestionsCross-platform Hybrid development 1. The difference between equals, hascode and == in Java == (double equal sign) : For basic data types (byte, short, char, int, long, float, double, boolean), their values ​​are compared; for reference types
  • "Effective Java" is really a good book worth studying all the time
    Article Directory "Effective Java" reading notesChapter 1 IntroductionChapter 2 Creating and Destroying Objects 1 Consider using static factory methods instead of construction methods** 2 Use builder mode when there are too many parameters in the construction method** 3 Use private constructors or classes to implement Singleton properties* 4 Use private constructors to perform non-instancing* 5 Dependency injection is better than hardwiring resources** 6 Avoid creating unnecessary objects* 7 Eliminate expired object references* 8 Avoid using Finalizer and Cleaner mechanism** 9 Use try-with
  • Bug in eclipse compiler or in javac (“type parameters of T cannot be determined”)
    Question The following code public class GenericsTest2 { public static void main(String[] args) throws Exception { Integer i = readObject(args[0]); System.out.println(i); } public static <T> T readObject(String file) throws Exception { return readObject(new ObjectInputStream(new FileInputStream(file))); // closing the stream in finally removed to get a small example } @SuppressWarnings("unchecked") public static <T> T readObject(ObjectInputStream stream) throws Exception { return (T)stream.readObject(); } } compiles in eclipse, but not with javac (type parameters of T cannot be determined; no
  • java object serialization readObject/defaultReadObject
    Question What's the difference between readObject and defaultReadObject in the ObjectInputStream class? I can't seem to find very much information on the difference. Answer1 defaultReadObject() invokes the default deserialization mechanism, and is used when you define the readObject() method on your Serializable class. In other words, when you have custom deserialization logic, you can still get back to the default serialization, which will deserialize your non-static, non-transient fields. For example: public class SomeClass implements Serializable { private String fld1; private int fld2
  • Java serialization, ObjectInputStream.readObject(), check if will block
    Question I'm using an ObjectInputStream to call readObject for reading in serialized Objects. I would like to avoid having this method block, so I'm looking to use something like Inputstream.available(). InputStream.available() will tell you there are bytes available and that read() will not block. Is there an equivalent method for seriailzation that will tell you if there are Objects available and readObject will not block? Answer1 No. Although you could use the ObjectInputStream in another thread and check to see whether that has an object available. Generally polling isn't a great idea
  • What is the difference between Serializable - writeObject()/ReadObject and Externalizable - readExternal()/writeExternal() in Java? [duplicate]
    Question This question already has answers here: why we have Externalizable when we can override writeObject and readObject in java (3 answers) Closed 16 days ago. I understood from this posting that Serializable is incredibly easy to implement, and resilient to change (in most cases all you have to do is update the serialversionUID). If we want to control of read and write process we can implement Externalizable. If all we want is the control of read and write process, we can override the below methods for serialization right? why do we need to introduce the new interface Externalizable
  • Java serialization: readObject() vs. readResolve()
    Question The book Effective Java and other sources provide a pretty good explanation on how and when to use the readObject() method when working with serializable Java classes. The readResolve() method, on the other hand, remains a bit of a mystery. Basically all documents I found either mention only one of the two or mention both only individually. Questions that remain unanswered are: What is the difference between the two methods? When should which method be implemented? How should readResolve() be used, especially in terms of returning what? I hope you can shed some light on this matter
  • How to prevent InputStream.readObject() from throwing EOFException?
    Question I serialize an object and save it as a file on my HDD. When I'm reading it, in only some occasions it throws EOFException. After couple of hours debugging I am not able to find a problem. Here is my code: public void serialize(MyClass myClass,String path) { FileOutputStream foStream = null; ObjectOutputStream ooStream = null; try { File file = new File(path); if (!file.exists()) { file.createNewFile(); } foStream = new FileOutputStream(file); ooStream = new ObjectOutputStream(foStream); ooStream.writeObject(myClass); } catch (Throwable t) { log.error(t); } finally { if (ooStream !=
  • Java: efficiency of writeObject vs writeExternal
    Question It's said that Java's default serialization mechanism is not very efficient because a)it discovers which fields to write/read through reflection which is usually slow b) it writes extra data to stream. One way to make it more efficient is to implement Externalizable and its writeExternal/readExternal methods. Here's the question: if I instead provide 'writeObject/readObject' methods and don't call deafiltWriteObject/defaultReadObject in them, then this mechanism won't use reflection to figure out which fields to write/read, plus it won't write extra data to stream (or will it? not
  • The complete collection of 2021 latest java basic crazy questions, a good helper for getting started with Java, and an explanation of classic exercises that must be brushed in the written test of java interview
    table of ContentsOne, JAVA foundation 1. JAVA abnormal classification and treatment 2. Anomaly classification 3. Exception handling 4. The difference between Throw and throwsSecond, JAVA reflection 1. Dynamic language 2. The concept of reflection mechanism (all the attributes and methods of the class are known in the running state) 3. Application of reflection 4. Java reflection API 5. Steps to use reflection (obtain the Class object, call the object method) 6, 3 ways to obtain the Class object 7. Two ways to create objectsThree, JAVA annotation 1. Concept 2, 4 standard meta-annotations 3
  • Effective Java summary
    One, create and destroy objects 1. Consider using a static factory method instead of the constructor <br /> The static factory method and the factory method pattern in the design pattern are different The different advantages of static factory methods and constructors are: (1) The static factory method can customize the method name, and the method name of the constructor can only be the same as the class name. (2) Static factory methods do not need to create a new object every time they are called. (3) Static factory methods can return objects of any subtype of the original return type. (4)
  • SocketException: Connection reset on server with ObjectInputStream
    Question I'm trying to get my head around the ObjectInputStream/ObjectOutputStream, so I create a very simple server-client application where the client sends a HashMap object over the created stream and the server receives that and prints it out. This my server code: import java.io.*; import java.net.*; public class Server { public static void main(String[] args) throws IOException, ClassNotFoundException { ServerSocket server = new ServerSocket(4444); while (true) { Socket socket = server.accept(); ObjectInputStream objIn = new ObjectInputStream(socket.getInputStream()); if (objIn.readObject
  • java week seventeen
    Summary of Java basic knowledge points <br /> Each part of the content will focus on writing some common knowledge points to facilitate review and memory, but not all of the content. Object-oriented inheritance of three major characteristics: general classes can only inherit single, internal classes implement multiple inheritance, and interfaces can inherit multiple Encapsulation: access control public> protected> package> private inner class is also a kind of encapsulation Polymorphism: Compile-time polymorphism, which is reflected in up-casting and down-casting, and judges which method to
  • Why is ObjectInputStream readObject() throwing EOF exception
    Question I am stuck with this very strange problem. In the client I am passing in objects like try{ oos.writeObject(new GameStartSerializedObject()); oos.flush(); } catch(Exception e){ e.printStackTrace(); } and in the server I am reading the object try{ //Its my turn thrown_message = player_reader.readObject(); } catch(Exception e){ My question is why am i getting EOF exception. My understanding of object input stream is when i call readObject() i should block until i get an object so how does it know if the eof is reached? Please help! This is how I create object streams ois = new
  • readobject method throws ClassNotFoundException
    Question I'm trying to pick up Java and wanted to test around with Java's client/server to make the client send a simple object of a self defined class(Message) over to the server. The problem was that I kept getting a ClassNotFoundException on the server side. I think the rest of the codes seem to be alright because other objects such as String can go through without problems. I had two different netbeans projects in different locations for client and server each. Each of them have their own copy of Message class under their respective packages. Message class implements Serializable. On the
  • Why does HashMap need to implement writeObject and readObject methods by itself?
    Original: Miss Sister Taste (WeChat public account ID: xjjdog), welcome to share, please keep the source for reprinting.phenomenonIf you have read the source code of HashMap carefully, then you must have noticed a problem: There are two private methods in HashMap.private void writeObject(java.io.ObjectOutputStream s) throws IOException private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException复制代码These two methods have two things in common:All private methodsAlthough it is a private method, but there is no place to call them inside the HashMapdoubtWhy are
  • JavaSE# notes [IO stream summary Properties class buffer stream conversion stream sequence stream decoration mode IO stream exception handling] @Gray
    Summary of IO flow 1. Properties class [important] Overview ​ Properties is a subclass of Hashtable, and its essence is a collection. But it can work with IO streams to manipulate files. ​ Other collections must have generics, but Properties do not have generics. This collection will always store key-value pairs of strings. 1.1 Construction method methodDescription public Properties() Create an empty attribute list. 1.2 Common methods methodDescription Object setProperty(String key ,String value)Add key-value pairs String getProperty(String key)Get value based on key load (input stream)Read