code: private void writePredecessors(Task mpxjTask, net.sf.mpxj.planner.schema.Task plannerTask)
     {
        Predecessors plannerPredecessors = m_factory.createPredecessors();
        plannerTask.setPredecessors(plannerPredecessors);
        List<Predecessor> predecessorList = plannerPredecessors.getPredecessor();
        int id = 0;
  
        List<Relation> predecessors = mpxjTask.getPredecessors();
        for (Relation rel : predecessors)
        {
           Integer taskUniqueID = rel.getTargetTask().getUniqueID();
           Predecessor plannerPredecessor = m_factory.createPredecessor();
           plannerPredecessor.setId(getIntegerString(++id));
           plannerPredecessor.setPredecessorId(getIntegerString(taskUniqueID));
           plannerPredecessor.setLag(getDurationString(rel.getLag()));
           plannerPredecessor.setType(RELATIONSHIP_TYPES.get(rel.getType()));
           predecessorList.add(plannerPredecessor);
           m_eventManager.fireRelationWrittenEvent(rel);
        }
     }
docs: This method writes predecessor data to a Planner file.
  We have to deal with a slight anomaly in this method that is introduced
  by the MPX file format. It would be possible for someone to create an
  MPX file with both the predecessor list and the unique ID predecessor
  list populated... which means that we must process both and avoid adding
  duplicate predecessors. Also interesting to note is that MSP98 populates
  the predecessor list, not the unique ID predecessor list, as you might
  expect.
  
  @param mpxjTask MPXJ task instance
  @param plannerTask planner task instance