0

I have a class which I serialize into a file, and then deserialize from the file when needed. I do the deserialization in a function inside the constructor of the same class:

try (ObjectInputStream objectInputStream = 
     new ObjectInputStream(new FileInputStream(comdict_file));)
{
  objectInputStream.readObject();
}
catch (ClassNotFoundException e)
{
  // TODO Auto-generated catch block
  System.out.println(e.getMessage());
  e.printStackTrace();
}

The readObject used is this:

private void readObject(ObjectInputStream in)
  throws IOException, ClassNotFoundException
{
  //read default properties
  in.defaultReadObject();
  String file = path + "meanings_info.bin";
  readBuffer(file);
}

When running the debugger, I realized that it reads and loads everything into an instance correctly, but once I exit the readObject (not defaultReadObject) function, I'm back at the constructor with all member variables being null or whatever their default value is.

My question is, how can I "keep" the values of the serialization?

This is the class and test, although I don't think that's the problem:

public class CompactDictionary implements Serializable
{
  private static final int BUFFER_SIZE_STEP = 10 * 1024 * 1024;
  private TObjectIntHashMap<String> meanings_index = new TObjectIntHashMap<>( 1000 );
  transient private ByteBuffer meanings_info = ByteBuffer.allocate(BUFFER_SIZE_STEP);
  //private int meanings_position = 0;
  private final static long serialVersionUID = 1L;
  //private final static Logger log = LogManager.getLogger();
  private transient Charset charset;
  //private boolean truncate;
  private String path;

  public CompactDictionary(String path, Charset cs, boolean trun)
    throws IOException
  {
    charset = cs;
    this.path = Objects.requireNonNull(path, "path must not be null");
    fileInitiation(trun);
  }

  private void fileInitiation(boolean trun) throws IOException
  {
    String meanings_file = path + "meanings_info.bin";
    String comdict_file = path + "comdict.bin";
    if (!trun) {
      File f = new File(meanings_file);
      File f2 = new File(comdict_file);
      if (!f.exists() || !f.isFile() || !f2.exists() || !f2.isFile()) {
        throw new FileNotFoundException("You chose to not truncate but the saved files are not in the specified directory or they don't have permissions.");
      }
      try (ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(comdict_file));){
        objectInputStream.readObject();
      } catch (ClassNotFoundException e) {
        // TODO Auto-generated catch block
        System.out.println(e.getMessage());
        e.printStackTrace();
      }
    } else {
      try (FileWriter fwOb = new FileWriter(meanings_file, false);
           PrintWriter pwOb = new PrintWriter(fwOb, false);
           FileWriter fwOb2 = new FileWriter(comdict_file, false);
           PrintWriter pwOb2 = new PrintWriter(fwOb, false);)
      {
        pwOb.flush();
        pwOb2.flush();
      }
    }
  }

  public void setCharset(Charset c) {
    charset = c;
  }

  public int size() {
    return meanings_index.size();
  }

  //TODO
  public boolean contains(String form, char pos)
  {
    return false;
  }

  public boolean contains(String meaning)
  {
    assert StringUtils.isNotBlank(meaning);
    return meanings_index.containsKey(meaning);
  }

  public List<String> getMeanings(String key)
  {
    assert StringUtils.isNotBlank(key);

    int position = getMeaningPosition(key);
    if (position == -1)
     return new ArrayList<>();

    final int old_pos = meanings_info.position();
    meanings_info.position(position);

    final int num_meanings = meanings_info.getShort();

    final List<String> meanings = IntStream.range(0, num_meanings)
        .mapToObj(i ->
    {
       final int num_bytes = meanings_info.getShort();
       byte[] bytes = new byte[num_bytes];
       meanings_info.get(bytes);
       return new String(bytes, charset);
    }).collect(toList());

      meanings_info.position(old_pos);
      return meanings;
  }

  @SuppressWarnings("UnusedReturnValue")
  public boolean addEntry(final String key, List<String> values)
  {
      //assert StringUtils.isNotBlank(meaning) && StringUtils.isNotBlank(label) && glosses != null;

      values.removeIf(String::isEmpty);
      if (contains(key))
            return false;

      final List<byte[]> bytes_list = new ArrayList<>(values.size());

      values.forEach(m ->
      { 
        final byte[] bytes_string = m.getBytes(charset);

        ByteBuffer buffer = ByteBuffer.allocate(2);
        buffer.putShort((short) bytes_string.length);
        final byte[] bytes_count = buffer.array();
        byte[] bytes = ArrayUtils.addAll(bytes_count, bytes_string);
        bytes_list.add(bytes);
      });

      //increase buffer size if necessary
      int num_bytes = Short.BYTES + bytes_list.stream()
        .mapToInt(a -> a.length)
        .sum();
      if (meanings_info.remaining() < num_bytes)
      {
        final ByteBuffer newBuf = ByteBuffer.allocate(meanings_info.capacity() + BUFFER_SIZE_STEP);
        meanings_info.flip();
        newBuf.put(meanings_info);
        meanings_info = newBuf;
      }

      final int position = meanings_info.position();


      meanings_info.putShort((short) values.size()); // a short with max value 32767 should suffice

      // store the bytes for each gloss
      for (final byte[] bytes : bytes_list)
      {
        meanings_info.put(bytes);
      }

      updateMeaningsIndex(key, position);
      return true;
  }

  private int getMeaningPosition(String m)
  {
    if (meanings_index.containsKey(m))
        return meanings_index.get(m);
    return -1;
  }

  private void updateMeaningsIndex(String meaning, int position)
  {
    meanings_index.put(meaning, position);
  }

  private void readBuffer(String filename)
    throws IOException
  {
    FileInputStream fileIn = new FileInputStream(filename);
    ObjectInputStream in = new ObjectInputStream(fileIn);
    int bufferSize = in.readInt();
    byte[] buffer = new byte[bufferSize];
    in.readFully(buffer, 0, bufferSize);
    meanings_info = ByteBuffer.wrap(buffer, 0, bufferSize);
    //meanings_info.position(meanings_position);
    in.close();
    //pasar a try
  }

  private void readObject(ObjectInputStream in)
    throws IOException, ClassNotFoundException
  {
    //final StopWatch timer = new StopWatch(); timer.start();

    //read default properties
    in.defaultReadObject();
    String file = path + "meanings_info.bin"; //pasar luego a join Path
    readBuffer(file);
  }

  public void save()
  {
    String comdict_file = path + "comdict.bin";
    try(FileOutputStream fos = new FileOutputStream(comdict_file);
        ObjectOutputStream oos = new ObjectOutputStream(fos);)
    {
      oos.writeObject(this);
    } catch (Exception e) {
      System.out.println(e.getMessage());
    }
    String meanings_file = path + "meanings_info.bin";

    try(FileOutputStream fos = new FileOutputStream(meanings_file);
        ObjectOutputStream oos = new ObjectOutputStream(fos);)
    {
        oos.writeInt(meanings_info.position());
        oos.write(meanings_info.array());
    }
    catch (Exception e) {
      System.out.println(e.getMessage());
    }
  }
}


@Test
public void testSave() throws Exception
{
  List<String> value2 = new ArrayList<>();
  List<String> value3 = Arrays.asList(new String[]{"first", "second"});

  index.addEntry("testKey2", value2);
  index.addEntry("testKey3", value3);
  index.save();

  index = new CompactDictionary("src/test/resources/indexes/", StandardCharsets.UTF_8, false);

  List<String> actual;

  actual = index.getMeanings("testKey2");
  assertEquals("Seems that your index is messed up...", value2, actual);

  actual = index.getMeanings("testKey3");
  assertEquals("Seems that your index is messed up...", value3, actual);
}
SternK
  • 11,649
  • 22
  • 32
  • 46
  • @S.D Please look at [this](https://stackoverflow.com/questions/5245600/what-does-the-keyword-transient-mean-in-java). – SternK Dec 03 '19 at 16:31

1 Answers1

2

You read an object and then discard it (the return value).

        objectInputStream.readObject();

The fact that this method is called from a constructor of the same class but different instance is neither hear nor there.

Only values should be serialised (probably using something other than Java Serialization). Do all the file I/O business in methods of a different class.

Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305