tags:

views:

86

answers:

1

I use the following method to send out an object from a servlet :

  public void doGet(HttpServletRequest request,HttpServletResponse response) throws IOException
  {
    String Full_URL=request.getRequestURL().append("?"+request.getQueryString()).toString();

    String Contact_Id=request.getParameter("Contact_Id");
    String Time_Stamp=Get_Date_Format(6),query="select from "+Contact_Info_Entry.class.getName()+" where Contact_Id == '"+Contact_Id+"' order by Contact_Id desc";

    PersistenceManager pm=null;
    try
    {
      pm=PMF.get().getPersistenceManager();

      // note that this returns a list, there could be multiple, DataStore does not ensure uniqueness for non-primary key fields
      List<Contact_Info_Entry> results=(List<Contact_Info_Entry>)pm.newQuery(query).execute();

      Write_Serialized_XML(response.getOutputStream(),results.get(0));
    }
    catch (Exception e) { Send_Email(Email_From,Email_To,"Check_License_Servlet Error [ "+Time_Stamp+" ]",new Text(e.toString()+"\n"+Get_Stack_Trace(e)),null); }
    finally { pm.close(); }
  }

  /** Writes the object and CLOSES the stream. Uses the persistance delegate registered in this class.
   * @param os The stream to write to.
   * @param o The object to be serialized.
   */
  public static void writeXMLObject(OutputStream os,Object o)
  {
    // Classloader reference must be set since netBeans uses another class loader to loead the bean wich will fail in some circumstances.
    ClassLoader oldClassLoader=Thread.currentThread().getContextClassLoader();
    Thread.currentThread().setContextClassLoader(Check_License_Servlet.class.getClassLoader());

    XMLEncoder encoder=new XMLEncoder(os);
    encoder.setExceptionListener(new ExceptionListener() { public void exceptionThrown(Exception e) { e.printStackTrace(); }});
    encoder.writeObject(o);
    encoder.flush();
    encoder.close();

    Thread.currentThread().setContextClassLoader(oldClassLoader);
  }

  private static ByteArrayOutputStream writeOutputStream=new ByteArrayOutputStream(16384);

  /** Writes an object to XML.
   * @param out The boject out to write to. [ Will not be closed. ]
   * @param o The object to write.
   */
  public static synchronized void writeAsXML(ObjectOutput out,Object o) throws IOException
  {
    writeOutputStream.reset();
    writeXMLObject(writeOutputStream,o);
    byte[] Bt_1=writeOutputStream.toByteArray();
    byte[] Bt_2=new Des_Encrypter().encrypt(Bt_1,Key);
    out.writeInt(Bt_2.length);
    out.write(Bt_2);
    out.flush();
    out.close();
  }
  public static synchronized void Write_Serialized_XML(OutputStream Output_Stream,Object o) throws IOException { writeAsXML(new ObjectOutputStream(Output_Stream),o); }

At the receiving end the code look like this :

  File_Url="http://"+Site_Url+App_Dir+File_Name;
  try
  {
    Contact_Info_Entry Online_Contact_Entry=(Contact_Info_Entry)Read_Serialized_XML(new URL(File_Url));
  }
  catch (Exception e)
  {
    e.printStackTrace();
  }

  private static byte[] readBuf=new byte[16384];

  public static synchronized Object readAsXML(ObjectInput in) throws IOException
  {
    // Classloader reference must be set since netBeans uses another class loader to load the bean which will fail under some circumstances.
    ClassLoader oldClassLoader=Thread.currentThread().getContextClassLoader();
    Thread.currentThread().setContextClassLoader(Tool_Lib_Simple.class.getClassLoader());

    int length=in.readInt();
    readBuf=new byte[length];

    in.readFully(readBuf,0,length);
    byte Bt[]=new Des_Encrypter().decrypt(readBuf,Key);
    XMLDecoder dec=new XMLDecoder(new ByteArrayInputStream(Bt,0,Bt.length));
    Object o=dec.readObject();
    Thread.currentThread().setContextClassLoader(oldClassLoader);
    in.close();
    return o;
  }

  public static synchronized Object Read_Serialized_XML(URL File_Url) throws IOException { return readAsXML(new ObjectInputStream(File_Url.openStream())); }

But I can't get the object from the Java app that's on the receiving end, why ? The error messages look like this :

java.lang.ClassNotFoundException: PayPal_Monitor.Contact_Info_Entry
Continuing ...
java.lang.NullPointerException: target should not be null
Continuing ...
java.lang.NullPointerException: target should not be null
Continuing ...
java.lang.NullPointerException: target should not be null
Continuing ...
+1  A: 
java.lang.ClassNotFoundException: PayPal_Monitor.Contact_Info_Entry

That class should be also present in the runtime classpath of the receiving side.

BalusC
Thanks, at the receiving end there is a Contact_Info_Entry, everything is the same, just it's in the default package, not in the PayPal_Monitor package, could that be the problem ?
Frank
Default packages are always a problem. [You was explained that before](http://stackoverflow.com/questions/2701565/google-app-engine-classnotpersistencecapableexception/2725566#2725566).
BalusC
Yes, I remember that, but it's a bit unfair to the default package, it was designed for people to use... That aside, is it theoretically wrong to have a class belong to a package on the sending side and the same class in default package on the receiving side to communicate ?
Frank
That's also wrong. You can have classes with the same name but in different packages. To take a real world example: `java.util.Date` and `java.sql.Date`. The default package is just convenient for small and simple one-or-maybe-two-class-sized applications as you were tought in basic tutorials. But in real world enterprise applications? No, forget about it. Forever. All the other classes ain't going to see the packageless ones.
BalusC
Good point, thanks. To solve the problem, what can I do to communicate between the two sides, with objects of the same structure : same string types, int types, vectors, but they just belong to a different package on each side ? What's a practical solution to pass them back and forth ?
Frank
There is no other solution than ensuring that they use **exactly** the same full qualified classname, thus including the package.
BalusC
Since they are passed as object streams, why can't they be cast into another class of the same structure but of a different package ?
Frank
Because the stream contains information about the package.
BalusC
Yes, you are absolutely right. I put all classes in packages, and now it works fine, thanks !
Frank