/*PLEASE DO NOT EDIT THIS CODE*/
/*This code was generated using the UMPLE 1.34.0.7242.6b8819789 modeling language!*/

package example;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.sql.*;
import java.lang.reflect.Constructor;

// line 16 "../ToJsonComplexTest.ump"
public class Student extends Person
{

  //------------------------
  // MEMBER VARIABLES
  //------------------------

  //Student Attributes
  private float tuitionPaid;

  //Student Associations
  private University university;
  private List<Registration> registrations;

  //------------------------
  // CONSTRUCTOR
  //------------------------

  public Student(int aId, String aName, float aTuitionPaid, University aUniversity)
  {
    super(aId, aName);
    tuitionPaid = aTuitionPaid;
    boolean didAddUniversity = setUniversity(aUniversity);
    if (!didAddUniversity)
    {
      throw new RuntimeException("Unable to create student due to university. See https://manual.umple.org?RE002ViolationofAssociationMultiplicity.html");
    }
    registrations = new ArrayList<Registration>();
  }

  //------------------------
  // INTERFACE
  //------------------------

  public boolean setTuitionPaid(float aTuitionPaid)
  {
    boolean wasSet = false;
    tuitionPaid = aTuitionPaid;
    wasSet = true;
    return wasSet;
  }

  public float getTuitionPaid()
  {
    return tuitionPaid;
  }
  /* Code from template association_GetOne */
  public University getUniversity()
  {
    return university;
  }
  /* Code from template association_GetMany */
  public Registration getRegistration(int index)
  {
    Registration aRegistration = registrations.get(index);
    return aRegistration;
  }

  public List<Registration> getRegistrations()
  {
    List<Registration> newRegistrations = Collections.unmodifiableList(registrations);
    return newRegistrations;
  }

  public int numberOfRegistrations()
  {
    int number = registrations.size();
    return number;
  }

  public boolean hasRegistrations()
  {
    boolean has = registrations.size() > 0;
    return has;
  }

  public int indexOfRegistration(Registration aRegistration)
  {
    int index = registrations.indexOf(aRegistration);
    return index;
  }
  /* Code from template association_SetOneToMany */
  public boolean setUniversity(University aUniversity)
  {
    boolean wasSet = false;
    if (aUniversity == null)
    {
      return wasSet;
    }

    University existingUniversity = university;
    university = aUniversity;
    if (existingUniversity != null && !existingUniversity.equals(aUniversity))
    {
      existingUniversity.removeStudent(this);
    }
    university.addStudent(this);
    wasSet = true;
    return wasSet;
  }
  /* Code from template association_MinimumNumberOfMethod */
  public static int minimumNumberOfRegistrations()
  {
    return 0;
  }
  /* Code from template association_AddManyToOne */
  public Registration addRegistration(CourseSection aCourseSection)
  {
    return new Registration(this, aCourseSection);
  }

  public boolean addRegistration(Registration aRegistration)
  {
    boolean wasAdded = false;
    if (registrations.contains(aRegistration)) { return false; }
    Student existingStudent = aRegistration.getStudent();
    boolean isNewStudent = existingStudent != null && !this.equals(existingStudent);
    if (isNewStudent)
    {
      aRegistration.setStudent(this);
    }
    else
    {
      registrations.add(aRegistration);
    }
    wasAdded = true;
    return wasAdded;
  }

  public boolean removeRegistration(Registration aRegistration)
  {
    boolean wasRemoved = false;
    //Unable to remove aRegistration, as it must always have a student
    if (!this.equals(aRegistration.getStudent()))
    {
      registrations.remove(aRegistration);
      wasRemoved = true;
    }
    return wasRemoved;
  }
  /* Code from template association_AddIndexControlFunctions */
  public boolean addRegistrationAt(Registration aRegistration, int index)
  {  
    boolean wasAdded = false;
    if(addRegistration(aRegistration))
    {
      if(index < 0 ) { index = 0; }
      if(index > numberOfRegistrations()) { index = numberOfRegistrations() - 1; }
      registrations.remove(aRegistration);
      registrations.add(index, aRegistration);
      wasAdded = true;
    }
    return wasAdded;
  }

  public boolean addOrMoveRegistrationAt(Registration aRegistration, int index)
  {
    boolean wasAdded = false;
    if(registrations.contains(aRegistration))
    {
      if(index < 0 ) { index = 0; }
      if(index > numberOfRegistrations()) { index = numberOfRegistrations() - 1; }
      registrations.remove(aRegistration);
      registrations.add(index, aRegistration);
      wasAdded = true;
    } 
    else 
    {
      wasAdded = addRegistrationAt(aRegistration, index);
    }
    return wasAdded;
  }

  public void delete()
  {
    University placeholderUniversity = university;
    this.university = null;
    if(placeholderUniversity != null)
    {
      placeholderUniversity.removeStudent(this);
    }
    for(int i=registrations.size(); i > 0; i--)
    {
      Registration aRegistration = registrations.get(i - 1);
      aRegistration.delete();
    }
    super.delete();
  }


  public String toString()
  {
    return super.toString() + "["+
            "tuitionPaid" + ":" + getTuitionPaid()+ "]" + System.getProperties().getProperty("line.separator") +
            "  " + "university = "+(getUniversity()!=null?Integer.toHexString(System.identityHashCode(getUniversity())):"null");
  }
       
  /*
  * Generate Json for this object and connected objects visited objects to enable avoidance of infinite loops
  *
  * @return a string in Json  format of this object
  */ 
  public String toJson()
  {
    HashSet<Object> visitedList = new HashSet<Object>();
    StringBuilder toJsonOutput = new StringBuilder();
    toJsonOutput.append("{\n");
    this.toJsonHelper(toJsonOutput, visitedList,1,true);
    toJsonOutput.append("\n}");
    return(toJsonOutput.toString());
  }
   
  /*
  * Helper function to generate Json for this object and connected objects visited objects to enable avoidance of infinite loops
  *
  * @param toJsonOutput  Output is aded to this as the network of objects is traversed
  * @param visitedList  Every concrete object visited is added so we don't re-outpu
  * @param nestLevel    As we output deeper objects, indent them more
  * @param atConcreteClass false when we are recursing to a superclass
  *     so we get the superclass data
  * @return whether or not anything was output (so we can tell whether we need to output a comma)
  */ 
  public boolean toJsonHelper(StringBuilder toJsonOutput, HashSet<Object> visitedList, int nestLevel, boolean atConcreteClass){
      
      String indent = "  ".repeat(nestLevel);
      boolean alreadyVisited = false;
      boolean haveOutputItem = false;
      
    if(atConcreteClass) {
      // This will not be true in a super call; output header
      toJsonOutput.append(indent+"\""+this.toString().split("@")[0]+ "\" : {\n"+indent+ "  \"umpleObjectID\" : \""+System.identityHashCode(this)+"\"");
      // Check if we have already visited this object. If so we will not output details
      alreadyVisited = visitedList.contains(this);
      if(!alreadyVisited) {
        toJsonOutput.append(",\n");
        visitedList.add(this);
      }
    }
    
    // There is no superclass of this class
    if(alreadyVisited) {
      toJsonOutput.append("\n");
    }
    else {
      // Check if this class has a superclass. If it does, we make a call to output superclass content 
      // This will keep calling super so the topmost attributes and associations appear first
        haveOutputItem = super.toJsonHelper(toJsonOutput, visitedList, nestLevel, false);
      // When an object has not already been visited, output its details
      if(haveOutputItem){
      //toJsonOutput.append(",\n");  
      }
        
          if(haveOutputItem){
            toJsonOutput.append(",\n");
          }
          toJsonOutput.append(indent);
          toJsonOutput.append("  \"");
          toJsonOutput.append("tuitionPaid");
          toJsonOutput.append("\" : \"");
          String primValue_0=""+getTuitionPaid()+"";
          toJsonOutput.append(primValue_0.replace("\\","\\\\").replace("\"","\\\""));
          toJsonOutput.append("\"");
          haveOutputItem=true;
      //haveOutputItem = false;
      //haveOutputItem = false;
         if(haveOutputItem) {
           toJsonOutput.append(",\n");
         }
          toJsonOutput.append(indent);
            toJsonOutput.append("\n"+indent);
            toJsonOutput.append("  \"");
            toJsonOutput.append("university");
            toJsonOutput.append("\"");
            toJsonOutput.append(" : ");
            toJsonOutput.append("\n");
            toJsonOutput.append(indent+"  {");
            toJsonOutput.append("\n");University anotherItem_0 = getUniversity();
            anotherItem_0.toJsonHelper(toJsonOutput, visitedList, nestLevel+2, true);
            toJsonOutput.append("\n");
            toJsonOutput.append(indent+"  }");
            haveOutputItem=true;
         if(haveOutputItem) {
           toJsonOutput.append(",\n");
         }
          toJsonOutput.append(indent);
            toJsonOutput.append("  \"");
            toJsonOutput.append("registrations");
            toJsonOutput.append("\"");
            toJsonOutput.append(" : [");
            toJsonOutput.append("\n");
            haveOutputItem = false;
            try{
              for (Registration anItem_1 :getRegistrations()){
              if(haveOutputItem) {
                toJsonOutput.append(",\n");
              }
              toJsonOutput.append(indent+"  {");
              toJsonOutput.append("\n");
              anItem_1.toJsonHelper(toJsonOutput, visitedList,nestLevel+2,true);
              toJsonOutput.append("\n");
              toJsonOutput.append(indent+"  }");
              haveOutputItem=true;
            }
            }catch (NullPointerException e){
            }
            toJsonOutput.append("\n");    
            toJsonOutput.append(indent+"  ]");
            haveOutputItem=true;
              
          toJsonOutput.append(indent+"  \n");
    }
    // Finalize the output of the concrete class
    if(atConcreteClass) {
      if(!alreadyVisited) {
        toJsonOutput.append("\n");
      }
      toJsonOutput.append(indent+"}");
    }
    haveOutputItem = true;
    return haveOutputItem;
  }

  
      
  /*
  * Deserialize Json string to instantiate Objects from top-level class
  *
  * @param umpleObjectIDMap<String, Object> mapping parsed objectID (from Json string) with newly instantiated object's objectID
  * 
  * @param String aJsonString is the string in json format that is to be processed and turned into an object
  *
  * @return newly instantiated Object 
  */  

  public static Student fromJson(String aJsonString){
    // process the input jsonString so that it can further processed using regex
    aJsonString=aJsonString.replace("\n","").replace(" ","");   
    // a map to store the umpleObjectID present in jsonString
    Map<String, Object> umpleObjectIDMap=new HashMap<>();
    
    // instantiate a new object
Student anObject = new Student(aJsonString, umpleObjectIDMap);
    return anObject;
  }
   
  /*
  * A new constructor specifically implemented if -s genJson is specified
  * 
  * @param String aJsonString is the string in json format that is to be processed and turned into an object
  *
  * @param umpleObjectIDMap<String, Integer> mapping parsed objectID (from Json string) with newly instantiated object's objectID
  */ 
  @SuppressWarnings("unchecked")
  public Student(String aJsonString, Map<String, Object> umpleObjectIDMap){
    // Initialize a HashMap to store the parsed result
    // key is the attribute name present in the jsonString
    // value is the attribute value present in the jsonString
      super(aJsonString,umpleObjectIDMap);
      boolean visitedSuperClass=true;
    
    HashMap<String,String> parsedResult = new HashMap<String,String>();
    parsedResult = fromJsonParser(aJsonString);
    if(!parsedResult.isEmpty()){
    boolean classExist;
    boolean classChildExist;
    String parsedClassName=parsedResult.get("className");
    String childName=this.getClass().getSimpleName();
    classExist="Student".equals(parsedClassName);
    classChildExist=childName.equals(parsedClassName);
    // if top-level class does not exist, throw exception
    if(!classExist&&!classChildExist){
      throw new IllegalArgumentException("Top-level class \""+parsedClassName+"\" does not exist, please check the input json string");
    }
    String umpleObjectId=parsedResult.get("umpleObjectID");
    // Check if the object has already been visited and created
    //if((umpleObjectIDMap.get(umpleObjectId)==null)||visitedSuperClass){
      try{
      
    visitedSuperClass=false;
    // map the old objectID (in jsonString) with the newly created object's hashCode in umpleObjectIDMap 
    umpleObjectIDMap.put(umpleObjectId,this);
    
    String jsonKey="";
       jsonKey="tuitionPaid";
       //more types should be considered here
        float valueFloat=Float.parseFloat(parsedResult.get(jsonKey));
        this.tuitionPaid=valueFloat;
    
    // below for-loop check the association class of the top level class
       
       jsonKey="university";
       String newJsonString_0=parsedResult.get(jsonKey);
       String newIDRegex_0="\\\"umpleObjectID\\\"\\:\\\"[0-9]*\\\"";
       String newUmpleID_0=fromJsonParserHelper(newJsonString_0,newIDRegex_0);
       
       //Multiple associations
          
          if(!umpleObjectIDMap.containsKey(newUmpleID_0)){
            String newClassNameOne_0=fromJsonParserClassName(newJsonString_0);
            Class clazzOne_0=Class.forName(newClassNameOne_0);
            Constructor constructorOne_0=clazzOne_0.getConstructor(String.class, Map.class);
            Object objectNewOne_0=constructorOne_0.newInstance(newJsonString_0,umpleObjectIDMap);
University oneAssoObj_0=(University)objectNewOne_0;
university=oneAssoObj_0;
          }
          else{
university=(University)umpleObjectIDMap.get(newUmpleID_0);
          }

       
       jsonKey="registrations";
       String newJsonString_1=parsedResult.get(jsonKey);
       String newIDRegex_1="\\\"umpleObjectID\\\"\\:\\\"[0-9]*\\\"";
       String newUmpleID_1=fromJsonParserHelper(newJsonString_1,newIDRegex_1);
       
       //Multiple associations
           List<String> multiAssoObjList_1 = new ArrayList<String>();
           multiAssoObjList_1=fromJsonParserList(newJsonString_1);
registrations=new ArrayList<Registration>();
           for(String obj: multiAssoObjList_1){
             newUmpleID_1=fromJsonParserHelper(obj,newIDRegex_1);
             
             String newClassName_1=fromJsonParserClassName(obj);
           if(!umpleObjectIDMap.containsKey(newUmpleID_1)){
           
            boolean subClassFound=false;
            Class clazz_1=Class.forName(newClassName_1);
            Constructor constructor_1=clazz_1.getConstructor(String.class, Map.class);
            Object objectNew_1=constructor_1.newInstance(obj,umpleObjectIDMap);
registrations.add((Registration)objectNew_1);
            }
           else{
registrations.add((Registration)umpleObjectIDMap.get(newUmpleID_1));
           }
         }


    
    }catch(Exception e){
    }

    //}
  }
  } 
  /*
  * A json parser to parse the input jsonString, if -s genJson is specified
  * 
  * @param String aJsonString is the string in json format that is to be processed and turned into an object
  *
  * @ return HashMap<String,String> that stores paresed result, key is the attribute(or associations) of an object, value is the attribute value or association string
  */ 
  public static HashMap<String,String> fromJsonParser(String jsonString){
    
    HashMap<String,String> parsedResultMap = new HashMap<String,String>();
    try{
      //Below (String, Pattern, Matcher) are the regex strings and their patterns and matcher used to process a jsonString
    
        // topLevelString is the regex representing the topLevel class name
        String topLevelString = "\\{\\\"[A-Z]\\w*\\\":";
        Pattern topLevelPattern = Pattern.compile(topLevelString);
        Matcher topLevelMatcher = topLevelPattern.matcher(jsonString);
        String quotes="\\\"";
        String colon="\\:";
        String colonSquareBracket="\\:\\[";
        
        if(topLevelMatcher.find()){
            //actual string that represent the topLevel className
            String topLevelStringFound=topLevelMatcher.group(0);
            String className=topLevelStringFound.split(quotes)[1];
            parsedResultMap.put("className", className);
            jsonString=jsonString.split(topLevelString,2)[1];
            
            //objIDString is the regex representing umpleObjectID that could be found in jsonString
            String objIDString = "\"umpleObjectID\"\\:\"[0-9]*\",";
            Pattern objIDPattern = Pattern.compile(objIDString);
            Matcher objIDMatcher = objIDPattern.matcher(jsonString);
            if(objIDMatcher.find()){
              String objIDFound=objIDMatcher.group(0);
              parsedResultMap.put("umpleObjectID", objIDFound.split(colon)[1].split(quotes)[1]);
              jsonString=jsonString.replaceFirst(objIDFound,"");
            }
            String timeString="\\\"\\w*\\\"\\:\\\"\\d{2}:\\d{2}\\:\\d{2}\\\"";
            Pattern timeStringPattern=Pattern.compile(timeString);
            Matcher timeStringPatternMatcher=timeStringPattern.matcher(jsonString);
            if(timeStringPatternMatcher.find()){
              String timeStringFound=timeStringPatternMatcher.group(0);
              parsedResultMap.put(timeStringFound.split(colon,2)[0].split(quotes)[1], timeStringFound.split(colon,2)[1].split(quotes)[1]);
          
            }
            // pairString is the regex for an object's attribute and attribute value, the string parsed will be in key-value formate
        String pairString = "(\\\"(?!umpleObjectID)[^\\\"]+)\\\":\\\"((?:\\\\\\\"|[^\\\"])*)";
        Pattern pairPattern=Pattern.compile(pairString);
        Matcher pairMatcher=pairPattern.matcher(jsonString);
        String associationString="(?=\\\"\\w*\\\"\\:\\[\\{)(?:(?=.*?\\[\\{(?!.*?\\1)(.*\\}\\](?!.*\\2).*))(?=.*?\\}\\](?!.*?\\2)(.*)).)+?.*?(?=\\1)[^\\[]*(?=\\2$)";
        Pattern associationPattern=Pattern.compile(associationString);
        String newObjJsonString="(?=\\,\\\"\\w*\\\"\\:\\{)(?:(?=.*?\\{\\\"(?!.*?\\1)(.*\\}(?!.*\\2).*))(?=.*?\\}(?!.*?\\2)(.*)).)+?.*?(?=\\1)[^\\{]*(?=\\2$)";
        Pattern newObjJsonPattern=Pattern.compile(newObjJsonString);
        String quoteColonQuote="\\\"\\:\\\"";
        //Keep on parsing the attribute's key-value pair, 
        //until a List (multi-associations) pattern or a newObject parttern (single association) is found
        while(pairMatcher.find()){
               String pairStringFound=pairMatcher.group(0);
              if(parsedResultMap.get(pairStringFound.split(colon)[0].split(quotes)[1])==null){
                String keyPair=pairStringFound.split(colon)[0].split(quotes)[1];
                String valuePair=pairStringFound.split(quoteColonQuote,2)[1];
                keyPair=keyPair.replace("\\\\","\\").replace("\\\"","\"");
                valuePair=valuePair.replace("\\\\","\\").replace("\\\"","\"");
                parsedResultMap.put(keyPair,valuePair);
                jsonString=jsonString.replaceFirst(pairString, "");
              }
                int lastIndex = 0;
                while (lastIndex<jsonString.length()){
                  String remainingJson=jsonString.substring(lastIndex);
                  Matcher associationMatcher=associationPattern.matcher(jsonString);
                  Matcher newObjJsonMatcher=newObjJsonPattern.matcher(jsonString);
                  
                  boolean assoFound=associationMatcher.find();
                  boolean newObjFound=newObjJsonMatcher.find();
                  
                  if (assoFound&&(!newObjFound||associationMatcher.start()<newObjJsonMatcher.start())){
                    String assoStringFound=associationMatcher.group(0);
                    String associationName=assoStringFound.split(colon,2)[0].split(quotes)[1];;
                    String associationItems=assoStringFound.split(colonSquareBracket,2)[1];
                    parsedResultMap.put(associationName, associationItems);
                    jsonString=jsonString.replaceFirst(associationString, "");
                  }
                  else if (newObjFound){
                    String newObjJsonFound=newObjJsonMatcher.group(0);
                    String newObjName=newObjJsonFound.split(colon,2)[0].split(quotes)[1];
                    String newObjItems=newObjJsonFound.split(colon,2)[1];
                    parsedResultMap.put(newObjName, newObjItems);
                    jsonString=jsonString.replaceFirst(newObjJsonString, "");
                  }else{
                    break;
                  }
                }
        }
        }
        return parsedResultMap;
    }catch(NullPointerException e){
      return parsedResultMap;
    }
  }
   
  public static String fromJsonParserHelper(String jsonString, String regexString){
    String umpleID = "";
    String quo="\\\"";
    try{
      Pattern umpleIDPattern=Pattern.compile(regexString);
      Matcher umpleIDMatcher=umpleIDPattern.matcher(jsonString);
      if(umpleIDMatcher.find()){
        String umpleIDStringFound=umpleIDMatcher.group(0);
        String idString="\\\"\\d*\\\"";
        Pattern idPattern=Pattern.compile(idString);
        Matcher idMatcher=idPattern.matcher(umpleIDStringFound);
        if(idMatcher.find()){
          umpleID=idMatcher.group(0).split(quo)[1];
        }
      }
      return umpleID;
    } catch(NullPointerException e){
      return umpleID;
    }
  }
   
  public static List<String> fromJsonParserList(String objListString){
    List<String> objList=new ArrayList<String>();
    try{
      String objString="(?:(?=.*?\\{(?!.*?\\1)(.*\\}(?!.*\\2).*))(?=.*?\\}(?!.*?\\2)(.*)).)+?.*?(?=\\1)[^\\{]*(?=\\2$)";
      Pattern objStringPattern=Pattern.compile(objString);
      Matcher objStringMatcher=objStringPattern.matcher(objListString);
      while(objStringMatcher.find()){
        objList.add(objStringMatcher.group(0));
      }
      return objList;
   }catch(NullPointerException e){
     return objList;
   }
  }
   
  public static String fromJsonParserClassName(String objNameString){
    String nextName="";
    String quotes="\\\"";
    try{
      String nextNameString="\\{\\\"[A-Z]\\w*\\\":";
      Pattern nextNamePattern=Pattern.compile(nextNameString);
      Matcher nextNameMatcher=nextNamePattern.matcher(objNameString);
      if(nextNameMatcher.find()){
        nextName=nextNameMatcher.group(0).split(quotes)[1];
       
      }
      return nextName;
   }catch(NullPointerException e){
     return nextName;
   }
  }
  
}
/*PLEASE DO NOT EDIT THIS CODE*/
/*This code was generated using the UMPLE 1.34.0.7242.6b8819789 modeling language!*/

package example;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.sql.*;
import java.lang.reflect.Constructor;

// line 4 "../ToJsonComplexTest.ump"
public class University
{

  //------------------------
  // STATIC VARIABLES
  //------------------------

  private static University theInstance = null;

  //------------------------
  // MEMBER VARIABLES
  //------------------------

  //University Attributes
  private String name;
  private float tuition;

  //University Associations
  private List<Course> courses;
  private List<Student> students;

  //------------------------
  // CONSTRUCTOR
  //------------------------

  private University()
  {
    name = null;
    tuition = 0.0f;
    courses = new ArrayList<Course>();
    students = new ArrayList<Student>();
  }

  public static University getInstance()
  {
    if(theInstance == null)
    {
      theInstance = new University();
    }
    return theInstance;
  }

  //------------------------
  // INTERFACE
  //------------------------

  public boolean setName(String aName)
  {
    boolean wasSet = false;
    name = aName;
    wasSet = true;
    return wasSet;
  }

  public boolean setTuition(float aTuition)
  {
    boolean wasSet = false;
    tuition = aTuition;
    wasSet = true;
    return wasSet;
  }

  public String getName()
  {
    return name;
  }

  public float getTuition()
  {
    return tuition;
  }
  /* Code from template association_GetMany */
  public Course getCourse(int index)
  {
    Course aCourse = courses.get(index);
    return aCourse;
  }

  public List<Course> getCourses()
  {
    List<Course> newCourses = Collections.unmodifiableList(courses);
    return newCourses;
  }

  public int numberOfCourses()
  {
    int number = courses.size();
    return number;
  }

  public boolean hasCourses()
  {
    boolean has = courses.size() > 0;
    return has;
  }

  public int indexOfCourse(Course aCourse)
  {
    int index = courses.indexOf(aCourse);
    return index;
  }
  /* Code from template association_GetMany */
  public Student getStudent(int index)
  {
    Student aStudent = students.get(index);
    return aStudent;
  }

  public List<Student> getStudents()
  {
    List<Student> newStudents = Collections.unmodifiableList(students);
    return newStudents;
  }

  public int numberOfStudents()
  {
    int number = students.size();
    return number;
  }

  public boolean hasStudents()
  {
    boolean has = students.size() > 0;
    return has;
  }

  public int indexOfStudent(Student aStudent)
  {
    int index = students.indexOf(aStudent);
    return index;
  }
  /* Code from template association_MinimumNumberOfMethod */
  public static int minimumNumberOfCourses()
  {
    return 0;
  }
  /* Code from template association_AddManyToOne */
  public Course addCourse(String aTitle)
  {
    return new Course(aTitle, this);
  }

  public boolean addCourse(Course aCourse)
  {
    boolean wasAdded = false;
    if (courses.contains(aCourse)) { return false; }
    University existingUniversity = aCourse.getUniversity();
    boolean isNewUniversity = existingUniversity != null && !this.equals(existingUniversity);
    if (isNewUniversity)
    {
      aCourse.setUniversity(this);
    }
    else
    {
      courses.add(aCourse);
    }
    wasAdded = true;
    return wasAdded;
  }

  public boolean removeCourse(Course aCourse)
  {
    boolean wasRemoved = false;
    //Unable to remove aCourse, as it must always have a university
    if (!this.equals(aCourse.getUniversity()))
    {
      courses.remove(aCourse);
      wasRemoved = true;
    }
    return wasRemoved;
  }
  /* Code from template association_AddIndexControlFunctions */
  public boolean addCourseAt(Course aCourse, int index)
  {  
    boolean wasAdded = false;
    if(addCourse(aCourse))
    {
      if(index < 0 ) { index = 0; }
      if(index > numberOfCourses()) { index = numberOfCourses() - 1; }
      courses.remove(aCourse);
      courses.add(index, aCourse);
      wasAdded = true;
    }
    return wasAdded;
  }

  public boolean addOrMoveCourseAt(Course aCourse, int index)
  {
    boolean wasAdded = false;
    if(courses.contains(aCourse))
    {
      if(index < 0 ) { index = 0; }
      if(index > numberOfCourses()) { index = numberOfCourses() - 1; }
      courses.remove(aCourse);
      courses.add(index, aCourse);
      wasAdded = true;
    } 
    else 
    {
      wasAdded = addCourseAt(aCourse, index);
    }
    return wasAdded;
  }
  /* Code from template association_MinimumNumberOfMethod */
  public static int minimumNumberOfStudents()
  {
    return 0;
  }
  /* Code from template association_AddManyToOne */
  public Student addStudent(int aId, String aName, float aTuitionPaid)
  {
    return new Student(aId, aName, aTuitionPaid, this);
  }

  public boolean addStudent(Student aStudent)
  {
    boolean wasAdded = false;
    if (students.contains(aStudent)) { return false; }
    University existingUniversity = aStudent.getUniversity();
    boolean isNewUniversity = existingUniversity != null && !this.equals(existingUniversity);
    if (isNewUniversity)
    {
      aStudent.setUniversity(this);
    }
    else
    {
      students.add(aStudent);
    }
    wasAdded = true;
    return wasAdded;
  }

  public boolean removeStudent(Student aStudent)
  {
    boolean wasRemoved = false;
    //Unable to remove aStudent, as it must always have a university
    if (!this.equals(aStudent.getUniversity()))
    {
      students.remove(aStudent);
      wasRemoved = true;
    }
    return wasRemoved;
  }
  /* Code from template association_AddIndexControlFunctions */
  public boolean addStudentAt(Student aStudent, int index)
  {  
    boolean wasAdded = false;
    if(addStudent(aStudent))
    {
      if(index < 0 ) { index = 0; }
      if(index > numberOfStudents()) { index = numberOfStudents() - 1; }
      students.remove(aStudent);
      students.add(index, aStudent);
      wasAdded = true;
    }
    return wasAdded;
  }

  public boolean addOrMoveStudentAt(Student aStudent, int index)
  {
    boolean wasAdded = false;
    if(students.contains(aStudent))
    {
      if(index < 0 ) { index = 0; }
      if(index > numberOfStudents()) { index = numberOfStudents() - 1; }
      students.remove(aStudent);
      students.add(index, aStudent);
      wasAdded = true;
    } 
    else 
    {
      wasAdded = addStudentAt(aStudent, index);
    }
    return wasAdded;
  }

  public void delete()
  {
    for(int i=courses.size(); i > 0; i--)
    {
      Course aCourse = courses.get(i - 1);
      aCourse.delete();
    }
    for(int i=students.size(); i > 0; i--)
    {
      Student aStudent = students.get(i - 1);
      aStudent.delete();
    }
  }


  public String toString()
  {
    return super.toString() + "["+
            "name" + ":" + getName()+ "," +
            "tuition" + ":" + getTuition()+ "]";
  }
       
  /*
  * Generate Json for this object and connected objects visited objects to enable avoidance of infinite loops
  *
  * @return a string in Json  format of this object
  */ 
  public String toJson()
  {
    HashSet<Object> visitedList = new HashSet<Object>();
    StringBuilder toJsonOutput = new StringBuilder();
    toJsonOutput.append("{\n");
    this.toJsonHelper(toJsonOutput, visitedList,1,true);
    toJsonOutput.append("\n}");
    return(toJsonOutput.toString());
  }
   
  /*
  * Helper function to generate Json for this object and connected objects visited objects to enable avoidance of infinite loops
  *
  * @param toJsonOutput  Output is aded to this as the network of objects is traversed
  * @param visitedList  Every concrete object visited is added so we don't re-outpu
  * @param nestLevel    As we output deeper objects, indent them more
  * @param atConcreteClass false when we are recursing to a superclass
  *     so we get the superclass data
  * @return whether or not anything was output (so we can tell whether we need to output a comma)
  */ 
  public boolean toJsonHelper(StringBuilder toJsonOutput, HashSet<Object> visitedList, int nestLevel, boolean atConcreteClass){
      
      String indent = "  ".repeat(nestLevel);
      boolean alreadyVisited = false;
      boolean haveOutputItem = false;
      
    if(atConcreteClass) {
      // This will not be true in a super call; output header
      toJsonOutput.append(indent+"\""+this.toString().split("@")[0]+ "\" : {\n"+indent+ "  \"umpleObjectID\" : \""+System.identityHashCode(this)+"\"");
      // Check if we have already visited this object. If so we will not output details
      alreadyVisited = visitedList.contains(this);
      if(!alreadyVisited) {
        toJsonOutput.append(",\n");
        visitedList.add(this);
      }
    }
    
    // There is no superclass of this class
    if(alreadyVisited) {
      toJsonOutput.append("\n");
    }
    else {
      // Check if this class has a superclass. If it does, we make a call to output superclass content 
      // This will keep calling super so the topmost attributes and associations appear first
      // When an object has not already been visited, output its details
      if(haveOutputItem){
      //toJsonOutput.append(",\n");  
      }
        
          if(haveOutputItem){
            toJsonOutput.append(",\n");
          }
          toJsonOutput.append(indent);
          toJsonOutput.append("  \"");
          toJsonOutput.append("name");
          toJsonOutput.append("\" : \"");
          String primValue_0=""+getName()+"";
          toJsonOutput.append(primValue_0.replace("\\","\\\\").replace("\"","\\\""));
          toJsonOutput.append("\"");
          haveOutputItem=true;
          if(haveOutputItem){
            toJsonOutput.append(",\n");
          }
          toJsonOutput.append(indent);
          toJsonOutput.append("  \"");
          toJsonOutput.append("tuition");
          toJsonOutput.append("\" : \"");
          String primValue_1=""+getTuition()+"";
          toJsonOutput.append(primValue_1.replace("\\","\\\\").replace("\"","\\\""));
          toJsonOutput.append("\"");
          haveOutputItem=true;
      //haveOutputItem = false;
      //haveOutputItem = false;
         if(haveOutputItem) {
           toJsonOutput.append(",\n");
         }
          toJsonOutput.append(indent);
            toJsonOutput.append("  \"");
            toJsonOutput.append("courses");
            toJsonOutput.append("\"");
            toJsonOutput.append(" : [");
            toJsonOutput.append("\n");
            haveOutputItem = false;
            try{
              for (Course anItem_0 :getCourses()){
              if(haveOutputItem) {
                toJsonOutput.append(",\n");
              }
              toJsonOutput.append(indent+"  {");
              toJsonOutput.append("\n");
              anItem_0.toJsonHelper(toJsonOutput, visitedList,nestLevel+2,true);
              toJsonOutput.append("\n");
              toJsonOutput.append(indent+"  }");
              haveOutputItem=true;
            }
            }catch (NullPointerException e){
            }
            toJsonOutput.append("\n");    
            toJsonOutput.append(indent+"  ]");
            haveOutputItem=true;
         if(haveOutputItem) {
           toJsonOutput.append(",\n");
         }
          toJsonOutput.append(indent);
            toJsonOutput.append("  \"");
            toJsonOutput.append("students");
            toJsonOutput.append("\"");
            toJsonOutput.append(" : [");
            toJsonOutput.append("\n");
            haveOutputItem = false;
            try{
              for (Student anItem_1 :getStudents()){
              if(haveOutputItem) {
                toJsonOutput.append(",\n");
              }
              toJsonOutput.append(indent+"  {");
              toJsonOutput.append("\n");
              anItem_1.toJsonHelper(toJsonOutput, visitedList,nestLevel+2,true);
              toJsonOutput.append("\n");
              toJsonOutput.append(indent+"  }");
              haveOutputItem=true;
            }
            }catch (NullPointerException e){
            }
            toJsonOutput.append("\n");    
            toJsonOutput.append(indent+"  ]");
            haveOutputItem=true;
              
          toJsonOutput.append(indent+"  \n");
    }
    // Finalize the output of the concrete class
    if(atConcreteClass) {
      if(!alreadyVisited) {
        toJsonOutput.append("\n");
      }
      toJsonOutput.append(indent+"}");
    }
    haveOutputItem = true;
    return haveOutputItem;
  }

  
      
  /*
  * Deserialize Json string to instantiate Objects from top-level class
  *
  * @param umpleObjectIDMap<String, Object> mapping parsed objectID (from Json string) with newly instantiated object's objectID
  * 
  * @param String aJsonString is the string in json format that is to be processed and turned into an object
  *
  * @return newly instantiated Object 
  */  

  public static University fromJson(String aJsonString){
    // process the input jsonString so that it can further processed using regex
    aJsonString=aJsonString.replace("\n","").replace(" ","");   
    // a map to store the umpleObjectID present in jsonString
    Map<String, Object> umpleObjectIDMap=new HashMap<>();
    
    // instantiate a new object
University anObject = new University(aJsonString, umpleObjectIDMap);
    return anObject;
  }
   
  /*
  * A new constructor specifically implemented if -s genJson is specified
  * 
  * @param String aJsonString is the string in json format that is to be processed and turned into an object
  *
  * @param umpleObjectIDMap<String, Integer> mapping parsed objectID (from Json string) with newly instantiated object's objectID
  */ 
  @SuppressWarnings("unchecked")
  public University(String aJsonString, Map<String, Object> umpleObjectIDMap){
    // Initialize a HashMap to store the parsed result
    // key is the attribute name present in the jsonString
    // value is the attribute value present in the jsonString
      boolean visitedSuperClass=false;
    
    HashMap<String,String> parsedResult = new HashMap<String,String>();
    parsedResult = fromJsonParser(aJsonString);
    if(!parsedResult.isEmpty()){
    boolean classExist;
    boolean classChildExist;
    String parsedClassName=parsedResult.get("className");
    String childName=this.getClass().getSimpleName();
    classExist="University".equals(parsedClassName);
    classChildExist=childName.equals(parsedClassName);
    // if top-level class does not exist, throw exception
    if(!classExist&&!classChildExist){
      throw new IllegalArgumentException("Top-level class \""+parsedClassName+"\" does not exist, please check the input json string");
    }
    String umpleObjectId=parsedResult.get("umpleObjectID");
    // Check if the object has already been visited and created
    //if((umpleObjectIDMap.get(umpleObjectId)==null)||visitedSuperClass){
      try{
      
    visitedSuperClass=false;
    // map the old objectID (in jsonString) with the newly created object's hashCode in umpleObjectIDMap 
    umpleObjectIDMap.put(umpleObjectId,this);
    
    String jsonKey="";
       jsonKey="name";
       //more types should be considered here
        this.name=parsedResult.get(jsonKey);
       jsonKey="tuition";
       //more types should be considered here
        float valueFloat=Float.parseFloat(parsedResult.get(jsonKey));
        this.tuition=valueFloat;
    
    // below for-loop check the association class of the top level class
       
       jsonKey="courses";
       String newJsonString_0=parsedResult.get(jsonKey);
       String newIDRegex_0="\\\"umpleObjectID\\\"\\:\\\"[0-9]*\\\"";
       String newUmpleID_0=fromJsonParserHelper(newJsonString_0,newIDRegex_0);
       
       //Multiple associations
           List<String> multiAssoObjList_0 = new ArrayList<String>();
           multiAssoObjList_0=fromJsonParserList(newJsonString_0);
courses=new ArrayList<Course>();
           for(String obj: multiAssoObjList_0){
             newUmpleID_0=fromJsonParserHelper(obj,newIDRegex_0);
             
             String newClassName_0=fromJsonParserClassName(obj);
           if(!umpleObjectIDMap.containsKey(newUmpleID_0)){
           
            boolean subClassFound=false;
            Class clazz_0=Class.forName(newClassName_0);
            Constructor constructor_0=clazz_0.getConstructor(String.class, Map.class);
            Object objectNew_0=constructor_0.newInstance(obj,umpleObjectIDMap);
courses.add((Course)objectNew_0);
            }
           else{
courses.add((Course)umpleObjectIDMap.get(newUmpleID_0));
           }
         }

       
       jsonKey="students";
       String newJsonString_1=parsedResult.get(jsonKey);
       String newIDRegex_1="\\\"umpleObjectID\\\"\\:\\\"[0-9]*\\\"";
       String newUmpleID_1=fromJsonParserHelper(newJsonString_1,newIDRegex_1);
       
       //Multiple associations
           List<String> multiAssoObjList_1 = new ArrayList<String>();
           multiAssoObjList_1=fromJsonParserList(newJsonString_1);
students=new ArrayList<Student>();
           for(String obj: multiAssoObjList_1){
             newUmpleID_1=fromJsonParserHelper(obj,newIDRegex_1);
             
             String newClassName_1=fromJsonParserClassName(obj);
           if(!umpleObjectIDMap.containsKey(newUmpleID_1)){
           
            boolean subClassFound=false;
            Class clazz_1=Class.forName(newClassName_1);
            Constructor constructor_1=clazz_1.getConstructor(String.class, Map.class);
            Object objectNew_1=constructor_1.newInstance(obj,umpleObjectIDMap);
students.add((Student)objectNew_1);
            }
           else{
students.add((Student)umpleObjectIDMap.get(newUmpleID_1));
           }
         }


    
    }catch(Exception e){
    }

    //}
  }
  } 
  /*
  * A json parser to parse the input jsonString, if -s genJson is specified
  * 
  * @param String aJsonString is the string in json format that is to be processed and turned into an object
  *
  * @ return HashMap<String,String> that stores paresed result, key is the attribute(or associations) of an object, value is the attribute value or association string
  */ 
  public static HashMap<String,String> fromJsonParser(String jsonString){
    
    HashMap<String,String> parsedResultMap = new HashMap<String,String>();
    try{
      //Below (String, Pattern, Matcher) are the regex strings and their patterns and matcher used to process a jsonString
    
        // topLevelString is the regex representing the topLevel class name
        String topLevelString = "\\{\\\"[A-Z]\\w*\\\":";
        Pattern topLevelPattern = Pattern.compile(topLevelString);
        Matcher topLevelMatcher = topLevelPattern.matcher(jsonString);
        String quotes="\\\"";
        String colon="\\:";
        String colonSquareBracket="\\:\\[";
        
        if(topLevelMatcher.find()){
            //actual string that represent the topLevel className
            String topLevelStringFound=topLevelMatcher.group(0);
            String className=topLevelStringFound.split(quotes)[1];
            parsedResultMap.put("className", className);
            jsonString=jsonString.split(topLevelString,2)[1];
            
            //objIDString is the regex representing umpleObjectID that could be found in jsonString
            String objIDString = "\"umpleObjectID\"\\:\"[0-9]*\",";
            Pattern objIDPattern = Pattern.compile(objIDString);
            Matcher objIDMatcher = objIDPattern.matcher(jsonString);
            if(objIDMatcher.find()){
              String objIDFound=objIDMatcher.group(0);
              parsedResultMap.put("umpleObjectID", objIDFound.split(colon)[1].split(quotes)[1]);
              jsonString=jsonString.replaceFirst(objIDFound,"");
            }
            String timeString="\\\"\\w*\\\"\\:\\\"\\d{2}:\\d{2}\\:\\d{2}\\\"";
            Pattern timeStringPattern=Pattern.compile(timeString);
            Matcher timeStringPatternMatcher=timeStringPattern.matcher(jsonString);
            if(timeStringPatternMatcher.find()){
              String timeStringFound=timeStringPatternMatcher.group(0);
              parsedResultMap.put(timeStringFound.split(colon,2)[0].split(quotes)[1], timeStringFound.split(colon,2)[1].split(quotes)[1]);
          
            }
            // pairString is the regex for an object's attribute and attribute value, the string parsed will be in key-value formate
        String pairString = "(\\\"(?!umpleObjectID)[^\\\"]+)\\\":\\\"((?:\\\\\\\"|[^\\\"])*)";
        Pattern pairPattern=Pattern.compile(pairString);
        Matcher pairMatcher=pairPattern.matcher(jsonString);
        String associationString="(?=\\\"\\w*\\\"\\:\\[\\{)(?:(?=.*?\\[\\{(?!.*?\\1)(.*\\}\\](?!.*\\2).*))(?=.*?\\}\\](?!.*?\\2)(.*)).)+?.*?(?=\\1)[^\\[]*(?=\\2$)";
        Pattern associationPattern=Pattern.compile(associationString);
        String newObjJsonString="(?=\\,\\\"\\w*\\\"\\:\\{)(?:(?=.*?\\{\\\"(?!.*?\\1)(.*\\}(?!.*\\2).*))(?=.*?\\}(?!.*?\\2)(.*)).)+?.*?(?=\\1)[^\\{]*(?=\\2$)";
        Pattern newObjJsonPattern=Pattern.compile(newObjJsonString);
        String quoteColonQuote="\\\"\\:\\\"";
        //Keep on parsing the attribute's key-value pair, 
        //until a List (multi-associations) pattern or a newObject parttern (single association) is found
        while(pairMatcher.find()){
               String pairStringFound=pairMatcher.group(0);
              if(parsedResultMap.get(pairStringFound.split(colon)[0].split(quotes)[1])==null){
                String keyPair=pairStringFound.split(colon)[0].split(quotes)[1];
                String valuePair=pairStringFound.split(quoteColonQuote,2)[1];
                keyPair=keyPair.replace("\\\\","\\").replace("\\\"","\"");
                valuePair=valuePair.replace("\\\\","\\").replace("\\\"","\"");
                parsedResultMap.put(keyPair,valuePair);
                jsonString=jsonString.replaceFirst(pairString, "");
              }
                int lastIndex = 0;
                while (lastIndex<jsonString.length()){
                  String remainingJson=jsonString.substring(lastIndex);
                  Matcher associationMatcher=associationPattern.matcher(jsonString);
                  Matcher newObjJsonMatcher=newObjJsonPattern.matcher(jsonString);
                  
                  boolean assoFound=associationMatcher.find();
                  boolean newObjFound=newObjJsonMatcher.find();
                  
                  if (assoFound&&(!newObjFound||associationMatcher.start()<newObjJsonMatcher.start())){
                    String assoStringFound=associationMatcher.group(0);
                    String associationName=assoStringFound.split(colon,2)[0].split(quotes)[1];;
                    String associationItems=assoStringFound.split(colonSquareBracket,2)[1];
                    parsedResultMap.put(associationName, associationItems);
                    jsonString=jsonString.replaceFirst(associationString, "");
                  }
                  else if (newObjFound){
                    String newObjJsonFound=newObjJsonMatcher.group(0);
                    String newObjName=newObjJsonFound.split(colon,2)[0].split(quotes)[1];
                    String newObjItems=newObjJsonFound.split(colon,2)[1];
                    parsedResultMap.put(newObjName, newObjItems);
                    jsonString=jsonString.replaceFirst(newObjJsonString, "");
                  }else{
                    break;
                  }
                }
        }
        }
        return parsedResultMap;
    }catch(NullPointerException e){
      return parsedResultMap;
    }
  }
   
  public static String fromJsonParserHelper(String jsonString, String regexString){
    String umpleID = "";
    String quo="\\\"";
    try{
      Pattern umpleIDPattern=Pattern.compile(regexString);
      Matcher umpleIDMatcher=umpleIDPattern.matcher(jsonString);
      if(umpleIDMatcher.find()){
        String umpleIDStringFound=umpleIDMatcher.group(0);
        String idString="\\\"\\d*\\\"";
        Pattern idPattern=Pattern.compile(idString);
        Matcher idMatcher=idPattern.matcher(umpleIDStringFound);
        if(idMatcher.find()){
          umpleID=idMatcher.group(0).split(quo)[1];
        }
      }
      return umpleID;
    } catch(NullPointerException e){
      return umpleID;
    }
  }
   
  public static List<String> fromJsonParserList(String objListString){
    List<String> objList=new ArrayList<String>();
    try{
      String objString="(?:(?=.*?\\{(?!.*?\\1)(.*\\}(?!.*\\2).*))(?=.*?\\}(?!.*?\\2)(.*)).)+?.*?(?=\\1)[^\\{]*(?=\\2$)";
      Pattern objStringPattern=Pattern.compile(objString);
      Matcher objStringMatcher=objStringPattern.matcher(objListString);
      while(objStringMatcher.find()){
        objList.add(objStringMatcher.group(0));
      }
      return objList;
   }catch(NullPointerException e){
     return objList;
   }
  }
   
  public static String fromJsonParserClassName(String objNameString){
    String nextName="";
    String quotes="\\\"";
    try{
      String nextNameString="\\{\\\"[A-Z]\\w*\\\":";
      Pattern nextNamePattern=Pattern.compile(nextNameString);
      Matcher nextNameMatcher=nextNamePattern.matcher(objNameString);
      if(nextNameMatcher.find()){
        nextName=nextNameMatcher.group(0).split(quotes)[1];
       
      }
      return nextName;
   }catch(NullPointerException e){
     return nextName;
   }
  }
  
}
/*PLEASE DO NOT EDIT THIS CODE*/
/*This code was generated using the UMPLE 1.34.0.7242.6b8819789 modeling language!*/

package example;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.sql.*;
import java.lang.reflect.Constructor;

// line 26 "../ToJsonComplexTest.ump"
public class Employee extends Person
{

  //------------------------
  // MEMBER VARIABLES
  //------------------------

  //Employee Attributes
  private double salary;
  private String job;

  //Employee Associations
  private List<CourseSection> teaches;

  //------------------------
  // CONSTRUCTOR
  //------------------------

  public Employee(int aId, String aName, double aSalary)
  {
    super(aId, aName);
    salary = aSalary;
    job = null;
    teaches = new ArrayList<CourseSection>();
  }

  //------------------------
  // INTERFACE
  //------------------------

  public boolean setSalary(double aSalary)
  {
    boolean wasSet = false;
    salary = aSalary;
    wasSet = true;
    return wasSet;
  }

  public boolean setJob(String aJob)
  {
    boolean wasSet = false;
    job = aJob;
    wasSet = true;
    return wasSet;
  }

  public double getSalary()
  {
    return salary;
  }

  public String getJob()
  {
    return job;
  }
  /* Code from template association_GetMany */
  public CourseSection getTeache(int index)
  {
    CourseSection aTeache = teaches.get(index);
    return aTeache;
  }

  public List<CourseSection> getTeaches()
  {
    List<CourseSection> newTeaches = Collections.unmodifiableList(teaches);
    return newTeaches;
  }

  public int numberOfTeaches()
  {
    int number = teaches.size();
    return number;
  }

  public boolean hasTeaches()
  {
    boolean has = teaches.size() > 0;
    return has;
  }

  public int indexOfTeache(CourseSection aTeache)
  {
    int index = teaches.indexOf(aTeache);
    return index;
  }
  /* Code from template association_MinimumNumberOfMethod */
  public static int minimumNumberOfTeaches()
  {
    return 0;
  }
  /* Code from template association_AddManyToManyMethod */
  public boolean addTeache(CourseSection aTeache)
  {
    boolean wasAdded = false;
    if (teaches.contains(aTeache)) { return false; }
    teaches.add(aTeache);
    if (aTeache.indexOfEmployee(this) != -1)
    {
      wasAdded = true;
    }
    else
    {
      wasAdded = aTeache.addEmployee(this);
      if (!wasAdded)
      {
        teaches.remove(aTeache);
      }
    }
    return wasAdded;
  }
  /* Code from template association_RemoveMany */
  public boolean removeTeache(CourseSection aTeache)
  {
    boolean wasRemoved = false;
    if (!teaches.contains(aTeache))
    {
      return wasRemoved;
    }

    int oldIndex = teaches.indexOf(aTeache);
    teaches.remove(oldIndex);
    if (aTeache.indexOfEmployee(this) == -1)
    {
      wasRemoved = true;
    }
    else
    {
      wasRemoved = aTeache.removeEmployee(this);
      if (!wasRemoved)
      {
        teaches.add(oldIndex,aTeache);
      }
    }
    return wasRemoved;
  }
  /* Code from template association_AddIndexControlFunctions */
  public boolean addTeacheAt(CourseSection aTeache, int index)
  {  
    boolean wasAdded = false;
    if(addTeache(aTeache))
    {
      if(index < 0 ) { index = 0; }
      if(index > numberOfTeaches()) { index = numberOfTeaches() - 1; }
      teaches.remove(aTeache);
      teaches.add(index, aTeache);
      wasAdded = true;
    }
    return wasAdded;
  }

  public boolean addOrMoveTeacheAt(CourseSection aTeache, int index)
  {
    boolean wasAdded = false;
    if(teaches.contains(aTeache))
    {
      if(index < 0 ) { index = 0; }
      if(index > numberOfTeaches()) { index = numberOfTeaches() - 1; }
      teaches.remove(aTeache);
      teaches.add(index, aTeache);
      wasAdded = true;
    } 
    else 
    {
      wasAdded = addTeacheAt(aTeache, index);
    }
    return wasAdded;
  }

  public void delete()
  {
    ArrayList<CourseSection> copyOfTeaches = new ArrayList<CourseSection>(teaches);
    teaches.clear();
    for(CourseSection aTeache : copyOfTeaches)
    {
      aTeache.removeEmployee(this);
    }
    super.delete();
  }


  public String toString()
  {
    return super.toString() + "["+
            "salary" + ":" + getSalary()+ "," +
            "job" + ":" + getJob()+ "]";
  }
       
  /*
  * Generate Json for this object and connected objects visited objects to enable avoidance of infinite loops
  *
  * @return a string in Json  format of this object
  */ 
  public String toJson()
  {
    HashSet<Object> visitedList = new HashSet<Object>();
    StringBuilder toJsonOutput = new StringBuilder();
    toJsonOutput.append("{\n");
    this.toJsonHelper(toJsonOutput, visitedList,1,true);
    toJsonOutput.append("\n}");
    return(toJsonOutput.toString());
  }
   
  /*
  * Helper function to generate Json for this object and connected objects visited objects to enable avoidance of infinite loops
  *
  * @param toJsonOutput  Output is aded to this as the network of objects is traversed
  * @param visitedList  Every concrete object visited is added so we don't re-outpu
  * @param nestLevel    As we output deeper objects, indent them more
  * @param atConcreteClass false when we are recursing to a superclass
  *     so we get the superclass data
  * @return whether or not anything was output (so we can tell whether we need to output a comma)
  */ 
  public boolean toJsonHelper(StringBuilder toJsonOutput, HashSet<Object> visitedList, int nestLevel, boolean atConcreteClass){
      
      String indent = "  ".repeat(nestLevel);
      boolean alreadyVisited = false;
      boolean haveOutputItem = false;
      
    if(atConcreteClass) {
      // This will not be true in a super call; output header
      toJsonOutput.append(indent+"\""+this.toString().split("@")[0]+ "\" : {\n"+indent+ "  \"umpleObjectID\" : \""+System.identityHashCode(this)+"\"");
      // Check if we have already visited this object. If so we will not output details
      alreadyVisited = visitedList.contains(this);
      if(!alreadyVisited) {
        toJsonOutput.append(",\n");
        visitedList.add(this);
      }
    }
    
    // There is no superclass of this class
    if(alreadyVisited) {
      toJsonOutput.append("\n");
    }
    else {
      // Check if this class has a superclass. If it does, we make a call to output superclass content 
      // This will keep calling super so the topmost attributes and associations appear first
        haveOutputItem = super.toJsonHelper(toJsonOutput, visitedList, nestLevel, false);
      // When an object has not already been visited, output its details
      if(haveOutputItem){
      //toJsonOutput.append(",\n");  
      }
        
          if(haveOutputItem){
            toJsonOutput.append(",\n");
          }
          toJsonOutput.append(indent);
          toJsonOutput.append("  \"");
          toJsonOutput.append("salary");
          toJsonOutput.append("\" : \"");
          String primValue_0=""+getSalary()+"";
          toJsonOutput.append(primValue_0.replace("\\","\\\\").replace("\"","\\\""));
          toJsonOutput.append("\"");
          haveOutputItem=true;
          if(haveOutputItem){
            toJsonOutput.append(",\n");
          }
          toJsonOutput.append(indent);
          toJsonOutput.append("  \"");
          toJsonOutput.append("job");
          toJsonOutput.append("\" : \"");
          String primValue_1=""+getJob()+"";
          toJsonOutput.append(primValue_1.replace("\\","\\\\").replace("\"","\\\""));
          toJsonOutput.append("\"");
          haveOutputItem=true;
      //haveOutputItem = false;
      //haveOutputItem = false;
         if(haveOutputItem) {
           toJsonOutput.append(",\n");
         }
          toJsonOutput.append(indent);
            toJsonOutput.append("  \"");
            toJsonOutput.append("teaches");
            toJsonOutput.append("\"");
            toJsonOutput.append(" : [");
            toJsonOutput.append("\n");
            haveOutputItem = false;
            try{
              for (CourseSection anItem_0 :getTeaches()){
              if(haveOutputItem) {
                toJsonOutput.append(",\n");
              }
              toJsonOutput.append(indent+"  {");
              toJsonOutput.append("\n");
              anItem_0.toJsonHelper(toJsonOutput, visitedList,nestLevel+2,true);
              toJsonOutput.append("\n");
              toJsonOutput.append(indent+"  }");
              haveOutputItem=true;
            }
            }catch (NullPointerException e){
            }
            toJsonOutput.append("\n");    
            toJsonOutput.append(indent+"  ]");
            haveOutputItem=true;
              
          toJsonOutput.append(indent+"  \n");
    }
    // Finalize the output of the concrete class
    if(atConcreteClass) {
      if(!alreadyVisited) {
        toJsonOutput.append("\n");
      }
      toJsonOutput.append(indent+"}");
    }
    haveOutputItem = true;
    return haveOutputItem;
  }

  
      
  /*
  * Deserialize Json string to instantiate Objects from top-level class
  *
  * @param umpleObjectIDMap<String, Object> mapping parsed objectID (from Json string) with newly instantiated object's objectID
  * 
  * @param String aJsonString is the string in json format that is to be processed and turned into an object
  *
  * @return newly instantiated Object 
  */  

  public static Employee fromJson(String aJsonString){
    // process the input jsonString so that it can further processed using regex
    aJsonString=aJsonString.replace("\n","").replace(" ","");   
    // a map to store the umpleObjectID present in jsonString
    Map<String, Object> umpleObjectIDMap=new HashMap<>();
    
    // instantiate a new object
Employee anObject = new Employee(aJsonString, umpleObjectIDMap);
    return anObject;
  }
   
  /*
  * A new constructor specifically implemented if -s genJson is specified
  * 
  * @param String aJsonString is the string in json format that is to be processed and turned into an object
  *
  * @param umpleObjectIDMap<String, Integer> mapping parsed objectID (from Json string) with newly instantiated object's objectID
  */ 
  @SuppressWarnings("unchecked")
  public Employee(String aJsonString, Map<String, Object> umpleObjectIDMap){
    // Initialize a HashMap to store the parsed result
    // key is the attribute name present in the jsonString
    // value is the attribute value present in the jsonString
      super(aJsonString,umpleObjectIDMap);
      boolean visitedSuperClass=true;
    
    HashMap<String,String> parsedResult = new HashMap<String,String>();
    parsedResult = fromJsonParser(aJsonString);
    if(!parsedResult.isEmpty()){
    boolean classExist;
    boolean classChildExist;
    String parsedClassName=parsedResult.get("className");
    String childName=this.getClass().getSimpleName();
    classExist="Employee".equals(parsedClassName);
    classChildExist=childName.equals(parsedClassName);
    // if top-level class does not exist, throw exception
    if(!classExist&&!classChildExist){
      throw new IllegalArgumentException("Top-level class \""+parsedClassName+"\" does not exist, please check the input json string");
    }
    String umpleObjectId=parsedResult.get("umpleObjectID");
    // Check if the object has already been visited and created
    //if((umpleObjectIDMap.get(umpleObjectId)==null)||visitedSuperClass){
      try{
      
    visitedSuperClass=false;
    // map the old objectID (in jsonString) with the newly created object's hashCode in umpleObjectIDMap 
    umpleObjectIDMap.put(umpleObjectId,this);
    
    String jsonKey="";
       jsonKey="salary";
       //more types should be considered here
        double valueDouble =Double.valueOf(parsedResult.get(jsonKey));
        this.salary=valueDouble;
       jsonKey="job";
       //more types should be considered here
        this.job=parsedResult.get(jsonKey);
    
    // below for-loop check the association class of the top level class
       
       jsonKey="teaches";
       String newJsonString_0=parsedResult.get(jsonKey);
       String newIDRegex_0="\\\"umpleObjectID\\\"\\:\\\"[0-9]*\\\"";
       String newUmpleID_0=fromJsonParserHelper(newJsonString_0,newIDRegex_0);
       
       //Multiple associations
           List<String> multiAssoObjList_0 = new ArrayList<String>();
           multiAssoObjList_0=fromJsonParserList(newJsonString_0);
teaches=new ArrayList<CourseSection>();
           for(String obj: multiAssoObjList_0){
             newUmpleID_0=fromJsonParserHelper(obj,newIDRegex_0);
             
             String newClassName_0=fromJsonParserClassName(obj);
           if(!umpleObjectIDMap.containsKey(newUmpleID_0)){
           
            boolean subClassFound=false;
            Class clazz_0=Class.forName(newClassName_0);
            Constructor constructor_0=clazz_0.getConstructor(String.class, Map.class);
            Object objectNew_0=constructor_0.newInstance(obj,umpleObjectIDMap);
teaches.add((CourseSection)objectNew_0);
            }
           else{
teaches.add((CourseSection)umpleObjectIDMap.get(newUmpleID_0));
           }
         }


    
    }catch(Exception e){
    }

    //}
  }
  } 
  /*
  * A json parser to parse the input jsonString, if -s genJson is specified
  * 
  * @param String aJsonString is the string in json format that is to be processed and turned into an object
  *
  * @ return HashMap<String,String> that stores paresed result, key is the attribute(or associations) of an object, value is the attribute value or association string
  */ 
  public static HashMap<String,String> fromJsonParser(String jsonString){
    
    HashMap<String,String> parsedResultMap = new HashMap<String,String>();
    try{
      //Below (String, Pattern, Matcher) are the regex strings and their patterns and matcher used to process a jsonString
    
        // topLevelString is the regex representing the topLevel class name
        String topLevelString = "\\{\\\"[A-Z]\\w*\\\":";
        Pattern topLevelPattern = Pattern.compile(topLevelString);
        Matcher topLevelMatcher = topLevelPattern.matcher(jsonString);
        String quotes="\\\"";
        String colon="\\:";
        String colonSquareBracket="\\:\\[";
        
        if(topLevelMatcher.find()){
            //actual string that represent the topLevel className
            String topLevelStringFound=topLevelMatcher.group(0);
            String className=topLevelStringFound.split(quotes)[1];
            parsedResultMap.put("className", className);
            jsonString=jsonString.split(topLevelString,2)[1];
            
            //objIDString is the regex representing umpleObjectID that could be found in jsonString
            String objIDString = "\"umpleObjectID\"\\:\"[0-9]*\",";
            Pattern objIDPattern = Pattern.compile(objIDString);
            Matcher objIDMatcher = objIDPattern.matcher(jsonString);
            if(objIDMatcher.find()){
              String objIDFound=objIDMatcher.group(0);
              parsedResultMap.put("umpleObjectID", objIDFound.split(colon)[1].split(quotes)[1]);
              jsonString=jsonString.replaceFirst(objIDFound,"");
            }
            String timeString="\\\"\\w*\\\"\\:\\\"\\d{2}:\\d{2}\\:\\d{2}\\\"";
            Pattern timeStringPattern=Pattern.compile(timeString);
            Matcher timeStringPatternMatcher=timeStringPattern.matcher(jsonString);
            if(timeStringPatternMatcher.find()){
              String timeStringFound=timeStringPatternMatcher.group(0);
              parsedResultMap.put(timeStringFound.split(colon,2)[0].split(quotes)[1], timeStringFound.split(colon,2)[1].split(quotes)[1]);
          
            }
            // pairString is the regex for an object's attribute and attribute value, the string parsed will be in key-value formate
        String pairString = "(\\\"(?!umpleObjectID)[^\\\"]+)\\\":\\\"((?:\\\\\\\"|[^\\\"])*)";
        Pattern pairPattern=Pattern.compile(pairString);
        Matcher pairMatcher=pairPattern.matcher(jsonString);
        String associationString="(?=\\\"\\w*\\\"\\:\\[\\{)(?:(?=.*?\\[\\{(?!.*?\\1)(.*\\}\\](?!.*\\2).*))(?=.*?\\}\\](?!.*?\\2)(.*)).)+?.*?(?=\\1)[^\\[]*(?=\\2$)";
        Pattern associationPattern=Pattern.compile(associationString);
        String newObjJsonString="(?=\\,\\\"\\w*\\\"\\:\\{)(?:(?=.*?\\{\\\"(?!.*?\\1)(.*\\}(?!.*\\2).*))(?=.*?\\}(?!.*?\\2)(.*)).)+?.*?(?=\\1)[^\\{]*(?=\\2$)";
        Pattern newObjJsonPattern=Pattern.compile(newObjJsonString);
        String quoteColonQuote="\\\"\\:\\\"";
        //Keep on parsing the attribute's key-value pair, 
        //until a List (multi-associations) pattern or a newObject parttern (single association) is found
        while(pairMatcher.find()){
               String pairStringFound=pairMatcher.group(0);
              if(parsedResultMap.get(pairStringFound.split(colon)[0].split(quotes)[1])==null){
                String keyPair=pairStringFound.split(colon)[0].split(quotes)[1];
                String valuePair=pairStringFound.split(quoteColonQuote,2)[1];
                keyPair=keyPair.replace("\\\\","\\").replace("\\\"","\"");
                valuePair=valuePair.replace("\\\\","\\").replace("\\\"","\"");
                parsedResultMap.put(keyPair,valuePair);
                jsonString=jsonString.replaceFirst(pairString, "");
              }
                int lastIndex = 0;
                while (lastIndex<jsonString.length()){
                  String remainingJson=jsonString.substring(lastIndex);
                  Matcher associationMatcher=associationPattern.matcher(jsonString);
                  Matcher newObjJsonMatcher=newObjJsonPattern.matcher(jsonString);
                  
                  boolean assoFound=associationMatcher.find();
                  boolean newObjFound=newObjJsonMatcher.find();
                  
                  if (assoFound&&(!newObjFound||associationMatcher.start()<newObjJsonMatcher.start())){
                    String assoStringFound=associationMatcher.group(0);
                    String associationName=assoStringFound.split(colon,2)[0].split(quotes)[1];;
                    String associationItems=assoStringFound.split(colonSquareBracket,2)[1];
                    parsedResultMap.put(associationName, associationItems);
                    jsonString=jsonString.replaceFirst(associationString, "");
                  }
                  else if (newObjFound){
                    String newObjJsonFound=newObjJsonMatcher.group(0);
                    String newObjName=newObjJsonFound.split(colon,2)[0].split(quotes)[1];
                    String newObjItems=newObjJsonFound.split(colon,2)[1];
                    parsedResultMap.put(newObjName, newObjItems);
                    jsonString=jsonString.replaceFirst(newObjJsonString, "");
                  }else{
                    break;
                  }
                }
        }
        }
        return parsedResultMap;
    }catch(NullPointerException e){
      return parsedResultMap;
    }
  }
   
  public static String fromJsonParserHelper(String jsonString, String regexString){
    String umpleID = "";
    String quo="\\\"";
    try{
      Pattern umpleIDPattern=Pattern.compile(regexString);
      Matcher umpleIDMatcher=umpleIDPattern.matcher(jsonString);
      if(umpleIDMatcher.find()){
        String umpleIDStringFound=umpleIDMatcher.group(0);
        String idString="\\\"\\d*\\\"";
        Pattern idPattern=Pattern.compile(idString);
        Matcher idMatcher=idPattern.matcher(umpleIDStringFound);
        if(idMatcher.find()){
          umpleID=idMatcher.group(0).split(quo)[1];
        }
      }
      return umpleID;
    } catch(NullPointerException e){
      return umpleID;
    }
  }
   
  public static List<String> fromJsonParserList(String objListString){
    List<String> objList=new ArrayList<String>();
    try{
      String objString="(?:(?=.*?\\{(?!.*?\\1)(.*\\}(?!.*\\2).*))(?=.*?\\}(?!.*?\\2)(.*)).)+?.*?(?=\\1)[^\\{]*(?=\\2$)";
      Pattern objStringPattern=Pattern.compile(objString);
      Matcher objStringMatcher=objStringPattern.matcher(objListString);
      while(objStringMatcher.find()){
        objList.add(objStringMatcher.group(0));
      }
      return objList;
   }catch(NullPointerException e){
     return objList;
   }
  }
   
  public static String fromJsonParserClassName(String objNameString){
    String nextName="";
    String quotes="\\\"";
    try{
      String nextNameString="\\{\\\"[A-Z]\\w*\\\":";
      Pattern nextNamePattern=Pattern.compile(nextNameString);
      Matcher nextNameMatcher=nextNamePattern.matcher(objNameString);
      if(nextNameMatcher.find()){
        nextName=nextNameMatcher.group(0).split(quotes)[1];
       
      }
      return nextName;
   }catch(NullPointerException e){
     return nextName;
   }
  }
  
}
/*PLEASE DO NOT EDIT THIS CODE*/
/*This code was generated using the UMPLE 1.34.0.7242.6b8819789 modeling language!*/

package example;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.sql.*;
import java.lang.reflect.Constructor;

// line 37 "../ToJsonComplexTest.ump"
public class Course
{

  //------------------------
  // MEMBER VARIABLES
  //------------------------

  //Course Attributes
  private String title;

  //Course Associations
  private University university;
  private List<CourseSection> courseSections;

  //------------------------
  // CONSTRUCTOR
  //------------------------

  public Course(String aTitle, University aUniversity)
  {
    title = aTitle;
    boolean didAddUniversity = setUniversity(aUniversity);
    if (!didAddUniversity)
    {
      throw new RuntimeException("Unable to create course due to university. See https://manual.umple.org?RE002ViolationofAssociationMultiplicity.html");
    }
    courseSections = new ArrayList<CourseSection>();
  }

  //------------------------
  // INTERFACE
  //------------------------

  public boolean setTitle(String aTitle)
  {
    boolean wasSet = false;
    title = aTitle;
    wasSet = true;
    return wasSet;
  }

  public String getTitle()
  {
    return title;
  }
  /* Code from template association_GetOne */
  public University getUniversity()
  {
    return university;
  }
  /* Code from template association_GetMany */
  public CourseSection getCourseSection(int index)
  {
    CourseSection aCourseSection = courseSections.get(index);
    return aCourseSection;
  }

  public List<CourseSection> getCourseSections()
  {
    List<CourseSection> newCourseSections = Collections.unmodifiableList(courseSections);
    return newCourseSections;
  }

  public int numberOfCourseSections()
  {
    int number = courseSections.size();
    return number;
  }

  public boolean hasCourseSections()
  {
    boolean has = courseSections.size() > 0;
    return has;
  }

  public int indexOfCourseSection(CourseSection aCourseSection)
  {
    int index = courseSections.indexOf(aCourseSection);
    return index;
  }
  /* Code from template association_SetOneToMany */
  public boolean setUniversity(University aUniversity)
  {
    boolean wasSet = false;
    if (aUniversity == null)
    {
      return wasSet;
    }

    University existingUniversity = university;
    university = aUniversity;
    if (existingUniversity != null && !existingUniversity.equals(aUniversity))
    {
      existingUniversity.removeCourse(this);
    }
    university.addCourse(this);
    wasSet = true;
    return wasSet;
  }
  /* Code from template association_MinimumNumberOfMethod */
  public static int minimumNumberOfCourseSections()
  {
    return 0;
  }
  /* Code from template association_AddManyToOne */
  public CourseSection addCourseSection(String aCode)
  {
    return new CourseSection(aCode, this);
  }

  public boolean addCourseSection(CourseSection aCourseSection)
  {
    boolean wasAdded = false;
    if (courseSections.contains(aCourseSection)) { return false; }
    Course existingCourse = aCourseSection.getCourse();
    boolean isNewCourse = existingCourse != null && !this.equals(existingCourse);
    if (isNewCourse)
    {
      aCourseSection.setCourse(this);
    }
    else
    {
      courseSections.add(aCourseSection);
    }
    wasAdded = true;
    return wasAdded;
  }

  public boolean removeCourseSection(CourseSection aCourseSection)
  {
    boolean wasRemoved = false;
    //Unable to remove aCourseSection, as it must always have a course
    if (!this.equals(aCourseSection.getCourse()))
    {
      courseSections.remove(aCourseSection);
      wasRemoved = true;
    }
    return wasRemoved;
  }
  /* Code from template association_AddIndexControlFunctions */
  public boolean addCourseSectionAt(CourseSection aCourseSection, int index)
  {  
    boolean wasAdded = false;
    if(addCourseSection(aCourseSection))
    {
      if(index < 0 ) { index = 0; }
      if(index > numberOfCourseSections()) { index = numberOfCourseSections() - 1; }
      courseSections.remove(aCourseSection);
      courseSections.add(index, aCourseSection);
      wasAdded = true;
    }
    return wasAdded;
  }

  public boolean addOrMoveCourseSectionAt(CourseSection aCourseSection, int index)
  {
    boolean wasAdded = false;
    if(courseSections.contains(aCourseSection))
    {
      if(index < 0 ) { index = 0; }
      if(index > numberOfCourseSections()) { index = numberOfCourseSections() - 1; }
      courseSections.remove(aCourseSection);
      courseSections.add(index, aCourseSection);
      wasAdded = true;
    } 
    else 
    {
      wasAdded = addCourseSectionAt(aCourseSection, index);
    }
    return wasAdded;
  }

  public void delete()
  {
    University placeholderUniversity = university;
    this.university = null;
    if(placeholderUniversity != null)
    {
      placeholderUniversity.removeCourse(this);
    }
    for(int i=courseSections.size(); i > 0; i--)
    {
      CourseSection aCourseSection = courseSections.get(i - 1);
      aCourseSection.delete();
    }
  }


  public String toString()
  {
    return super.toString() + "["+
            "title" + ":" + getTitle()+ "]" + System.getProperties().getProperty("line.separator") +
            "  " + "university = "+(getUniversity()!=null?Integer.toHexString(System.identityHashCode(getUniversity())):"null");
  }
       
  /*
  * Generate Json for this object and connected objects visited objects to enable avoidance of infinite loops
  *
  * @return a string in Json  format of this object
  */ 
  public String toJson()
  {
    HashSet<Object> visitedList = new HashSet<Object>();
    StringBuilder toJsonOutput = new StringBuilder();
    toJsonOutput.append("{\n");
    this.toJsonHelper(toJsonOutput, visitedList,1,true);
    toJsonOutput.append("\n}");
    return(toJsonOutput.toString());
  }
   
  /*
  * Helper function to generate Json for this object and connected objects visited objects to enable avoidance of infinite loops
  *
  * @param toJsonOutput  Output is aded to this as the network of objects is traversed
  * @param visitedList  Every concrete object visited is added so we don't re-outpu
  * @param nestLevel    As we output deeper objects, indent them more
  * @param atConcreteClass false when we are recursing to a superclass
  *     so we get the superclass data
  * @return whether or not anything was output (so we can tell whether we need to output a comma)
  */ 
  public boolean toJsonHelper(StringBuilder toJsonOutput, HashSet<Object> visitedList, int nestLevel, boolean atConcreteClass){
      
      String indent = "  ".repeat(nestLevel);
      boolean alreadyVisited = false;
      boolean haveOutputItem = false;
      
    if(atConcreteClass) {
      // This will not be true in a super call; output header
      toJsonOutput.append(indent+"\""+this.toString().split("@")[0]+ "\" : {\n"+indent+ "  \"umpleObjectID\" : \""+System.identityHashCode(this)+"\"");
      // Check if we have already visited this object. If so we will not output details
      alreadyVisited = visitedList.contains(this);
      if(!alreadyVisited) {
        toJsonOutput.append(",\n");
        visitedList.add(this);
      }
    }
    
    // There is no superclass of this class
    if(alreadyVisited) {
      toJsonOutput.append("\n");
    }
    else {
      // Check if this class has a superclass. If it does, we make a call to output superclass content 
      // This will keep calling super so the topmost attributes and associations appear first
      // When an object has not already been visited, output its details
      if(haveOutputItem){
      //toJsonOutput.append(",\n");  
      }
        
          if(haveOutputItem){
            toJsonOutput.append(",\n");
          }
          toJsonOutput.append(indent);
          toJsonOutput.append("  \"");
          toJsonOutput.append("title");
          toJsonOutput.append("\" : \"");
          String primValue_0=""+getTitle()+"";
          toJsonOutput.append(primValue_0.replace("\\","\\\\").replace("\"","\\\""));
          toJsonOutput.append("\"");
          haveOutputItem=true;
      //haveOutputItem = false;
      //haveOutputItem = false;
         if(haveOutputItem) {
           toJsonOutput.append(",\n");
         }
          toJsonOutput.append(indent);
            toJsonOutput.append("\n"+indent);
            toJsonOutput.append("  \"");
            toJsonOutput.append("university");
            toJsonOutput.append("\"");
            toJsonOutput.append(" : ");
            toJsonOutput.append("\n");
            toJsonOutput.append(indent+"  {");
            toJsonOutput.append("\n");University anotherItem_0 = getUniversity();
            anotherItem_0.toJsonHelper(toJsonOutput, visitedList, nestLevel+2, true);
            toJsonOutput.append("\n");
            toJsonOutput.append(indent+"  }");
            haveOutputItem=true;
         if(haveOutputItem) {
           toJsonOutput.append(",\n");
         }
          toJsonOutput.append(indent);
            toJsonOutput.append("  \"");
            toJsonOutput.append("courseSections");
            toJsonOutput.append("\"");
            toJsonOutput.append(" : [");
            toJsonOutput.append("\n");
            haveOutputItem = false;
            try{
              for (CourseSection anItem_1 :getCourseSections()){
              if(haveOutputItem) {
                toJsonOutput.append(",\n");
              }
              toJsonOutput.append(indent+"  {");
              toJsonOutput.append("\n");
              anItem_1.toJsonHelper(toJsonOutput, visitedList,nestLevel+2,true);
              toJsonOutput.append("\n");
              toJsonOutput.append(indent+"  }");
              haveOutputItem=true;
            }
            }catch (NullPointerException e){
            }
            toJsonOutput.append("\n");    
            toJsonOutput.append(indent+"  ]");
            haveOutputItem=true;
              
          toJsonOutput.append(indent+"  \n");
    }
    // Finalize the output of the concrete class
    if(atConcreteClass) {
      if(!alreadyVisited) {
        toJsonOutput.append("\n");
      }
      toJsonOutput.append(indent+"}");
    }
    haveOutputItem = true;
    return haveOutputItem;
  }

  
      
  /*
  * Deserialize Json string to instantiate Objects from top-level class
  *
  * @param umpleObjectIDMap<String, Object> mapping parsed objectID (from Json string) with newly instantiated object's objectID
  * 
  * @param String aJsonString is the string in json format that is to be processed and turned into an object
  *
  * @return newly instantiated Object 
  */  

  public static Course fromJson(String aJsonString){
    // process the input jsonString so that it can further processed using regex
    aJsonString=aJsonString.replace("\n","").replace(" ","");   
    // a map to store the umpleObjectID present in jsonString
    Map<String, Object> umpleObjectIDMap=new HashMap<>();
    
    // instantiate a new object
Course anObject = new Course(aJsonString, umpleObjectIDMap);
    return anObject;
  }
   
  /*
  * A new constructor specifically implemented if -s genJson is specified
  * 
  * @param String aJsonString is the string in json format that is to be processed and turned into an object
  *
  * @param umpleObjectIDMap<String, Integer> mapping parsed objectID (from Json string) with newly instantiated object's objectID
  */ 
  @SuppressWarnings("unchecked")
  public Course(String aJsonString, Map<String, Object> umpleObjectIDMap){
    // Initialize a HashMap to store the parsed result
    // key is the attribute name present in the jsonString
    // value is the attribute value present in the jsonString
      boolean visitedSuperClass=false;
    
    HashMap<String,String> parsedResult = new HashMap<String,String>();
    parsedResult = fromJsonParser(aJsonString);
    if(!parsedResult.isEmpty()){
    boolean classExist;
    boolean classChildExist;
    String parsedClassName=parsedResult.get("className");
    String childName=this.getClass().getSimpleName();
    classExist="Course".equals(parsedClassName);
    classChildExist=childName.equals(parsedClassName);
    // if top-level class does not exist, throw exception
    if(!classExist&&!classChildExist){
      throw new IllegalArgumentException("Top-level class \""+parsedClassName+"\" does not exist, please check the input json string");
    }
    String umpleObjectId=parsedResult.get("umpleObjectID");
    // Check if the object has already been visited and created
    //if((umpleObjectIDMap.get(umpleObjectId)==null)||visitedSuperClass){
      try{
      
    visitedSuperClass=false;
    // map the old objectID (in jsonString) with the newly created object's hashCode in umpleObjectIDMap 
    umpleObjectIDMap.put(umpleObjectId,this);
    
    String jsonKey="";
       jsonKey="title";
       //more types should be considered here
        this.title=parsedResult.get(jsonKey);
    
    // below for-loop check the association class of the top level class
       
       jsonKey="university";
       String newJsonString_0=parsedResult.get(jsonKey);
       String newIDRegex_0="\\\"umpleObjectID\\\"\\:\\\"[0-9]*\\\"";
       String newUmpleID_0=fromJsonParserHelper(newJsonString_0,newIDRegex_0);
       
       //Multiple associations
          
          if(!umpleObjectIDMap.containsKey(newUmpleID_0)){
            String newClassNameOne_0=fromJsonParserClassName(newJsonString_0);
            Class clazzOne_0=Class.forName(newClassNameOne_0);
            Constructor constructorOne_0=clazzOne_0.getConstructor(String.class, Map.class);
            Object objectNewOne_0=constructorOne_0.newInstance(newJsonString_0,umpleObjectIDMap);
University oneAssoObj_0=(University)objectNewOne_0;
university=oneAssoObj_0;
          }
          else{
university=(University)umpleObjectIDMap.get(newUmpleID_0);
          }

       
       jsonKey="courseSections";
       String newJsonString_1=parsedResult.get(jsonKey);
       String newIDRegex_1="\\\"umpleObjectID\\\"\\:\\\"[0-9]*\\\"";
       String newUmpleID_1=fromJsonParserHelper(newJsonString_1,newIDRegex_1);
       
       //Multiple associations
           List<String> multiAssoObjList_1 = new ArrayList<String>();
           multiAssoObjList_1=fromJsonParserList(newJsonString_1);
courseSections=new ArrayList<CourseSection>();
           for(String obj: multiAssoObjList_1){
             newUmpleID_1=fromJsonParserHelper(obj,newIDRegex_1);
             
             String newClassName_1=fromJsonParserClassName(obj);
           if(!umpleObjectIDMap.containsKey(newUmpleID_1)){
           
            boolean subClassFound=false;
            Class clazz_1=Class.forName(newClassName_1);
            Constructor constructor_1=clazz_1.getConstructor(String.class, Map.class);
            Object objectNew_1=constructor_1.newInstance(obj,umpleObjectIDMap);
courseSections.add((CourseSection)objectNew_1);
            }
           else{
courseSections.add((CourseSection)umpleObjectIDMap.get(newUmpleID_1));
           }
         }


    
    }catch(Exception e){
    }

    //}
  }
  } 
  /*
  * A json parser to parse the input jsonString, if -s genJson is specified
  * 
  * @param String aJsonString is the string in json format that is to be processed and turned into an object
  *
  * @ return HashMap<String,String> that stores paresed result, key is the attribute(or associations) of an object, value is the attribute value or association string
  */ 
  public static HashMap<String,String> fromJsonParser(String jsonString){
    
    HashMap<String,String> parsedResultMap = new HashMap<String,String>();
    try{
      //Below (String, Pattern, Matcher) are the regex strings and their patterns and matcher used to process a jsonString
    
        // topLevelString is the regex representing the topLevel class name
        String topLevelString = "\\{\\\"[A-Z]\\w*\\\":";
        Pattern topLevelPattern = Pattern.compile(topLevelString);
        Matcher topLevelMatcher = topLevelPattern.matcher(jsonString);
        String quotes="\\\"";
        String colon="\\:";
        String colonSquareBracket="\\:\\[";
        
        if(topLevelMatcher.find()){
            //actual string that represent the topLevel className
            String topLevelStringFound=topLevelMatcher.group(0);
            String className=topLevelStringFound.split(quotes)[1];
            parsedResultMap.put("className", className);
            jsonString=jsonString.split(topLevelString,2)[1];
            
            //objIDString is the regex representing umpleObjectID that could be found in jsonString
            String objIDString = "\"umpleObjectID\"\\:\"[0-9]*\",";
            Pattern objIDPattern = Pattern.compile(objIDString);
            Matcher objIDMatcher = objIDPattern.matcher(jsonString);
            if(objIDMatcher.find()){
              String objIDFound=objIDMatcher.group(0);
              parsedResultMap.put("umpleObjectID", objIDFound.split(colon)[1].split(quotes)[1]);
              jsonString=jsonString.replaceFirst(objIDFound,"");
            }
            String timeString="\\\"\\w*\\\"\\:\\\"\\d{2}:\\d{2}\\:\\d{2}\\\"";
            Pattern timeStringPattern=Pattern.compile(timeString);
            Matcher timeStringPatternMatcher=timeStringPattern.matcher(jsonString);
            if(timeStringPatternMatcher.find()){
              String timeStringFound=timeStringPatternMatcher.group(0);
              parsedResultMap.put(timeStringFound.split(colon,2)[0].split(quotes)[1], timeStringFound.split(colon,2)[1].split(quotes)[1]);
          
            }
            // pairString is the regex for an object's attribute and attribute value, the string parsed will be in key-value formate
        String pairString = "(\\\"(?!umpleObjectID)[^\\\"]+)\\\":\\\"((?:\\\\\\\"|[^\\\"])*)";
        Pattern pairPattern=Pattern.compile(pairString);
        Matcher pairMatcher=pairPattern.matcher(jsonString);
        String associationString="(?=\\\"\\w*\\\"\\:\\[\\{)(?:(?=.*?\\[\\{(?!.*?\\1)(.*\\}\\](?!.*\\2).*))(?=.*?\\}\\](?!.*?\\2)(.*)).)+?.*?(?=\\1)[^\\[]*(?=\\2$)";
        Pattern associationPattern=Pattern.compile(associationString);
        String newObjJsonString="(?=\\,\\\"\\w*\\\"\\:\\{)(?:(?=.*?\\{\\\"(?!.*?\\1)(.*\\}(?!.*\\2).*))(?=.*?\\}(?!.*?\\2)(.*)).)+?.*?(?=\\1)[^\\{]*(?=\\2$)";
        Pattern newObjJsonPattern=Pattern.compile(newObjJsonString);
        String quoteColonQuote="\\\"\\:\\\"";
        //Keep on parsing the attribute's key-value pair, 
        //until a List (multi-associations) pattern or a newObject parttern (single association) is found
        while(pairMatcher.find()){
               String pairStringFound=pairMatcher.group(0);
              if(parsedResultMap.get(pairStringFound.split(colon)[0].split(quotes)[1])==null){
                String keyPair=pairStringFound.split(colon)[0].split(quotes)[1];
                String valuePair=pairStringFound.split(quoteColonQuote,2)[1];
                keyPair=keyPair.replace("\\\\","\\").replace("\\\"","\"");
                valuePair=valuePair.replace("\\\\","\\").replace("\\\"","\"");
                parsedResultMap.put(keyPair,valuePair);
                jsonString=jsonString.replaceFirst(pairString, "");
              }
                int lastIndex = 0;
                while (lastIndex<jsonString.length()){
                  String remainingJson=jsonString.substring(lastIndex);
                  Matcher associationMatcher=associationPattern.matcher(jsonString);
                  Matcher newObjJsonMatcher=newObjJsonPattern.matcher(jsonString);
                  
                  boolean assoFound=associationMatcher.find();
                  boolean newObjFound=newObjJsonMatcher.find();
                  
                  if (assoFound&&(!newObjFound||associationMatcher.start()<newObjJsonMatcher.start())){
                    String assoStringFound=associationMatcher.group(0);
                    String associationName=assoStringFound.split(colon,2)[0].split(quotes)[1];;
                    String associationItems=assoStringFound.split(colonSquareBracket,2)[1];
                    parsedResultMap.put(associationName, associationItems);
                    jsonString=jsonString.replaceFirst(associationString, "");
                  }
                  else if (newObjFound){
                    String newObjJsonFound=newObjJsonMatcher.group(0);
                    String newObjName=newObjJsonFound.split(colon,2)[0].split(quotes)[1];
                    String newObjItems=newObjJsonFound.split(colon,2)[1];
                    parsedResultMap.put(newObjName, newObjItems);
                    jsonString=jsonString.replaceFirst(newObjJsonString, "");
                  }else{
                    break;
                  }
                }
        }
        }
        return parsedResultMap;
    }catch(NullPointerException e){
      return parsedResultMap;
    }
  }
   
  public static String fromJsonParserHelper(String jsonString, String regexString){
    String umpleID = "";
    String quo="\\\"";
    try{
      Pattern umpleIDPattern=Pattern.compile(regexString);
      Matcher umpleIDMatcher=umpleIDPattern.matcher(jsonString);
      if(umpleIDMatcher.find()){
        String umpleIDStringFound=umpleIDMatcher.group(0);
        String idString="\\\"\\d*\\\"";
        Pattern idPattern=Pattern.compile(idString);
        Matcher idMatcher=idPattern.matcher(umpleIDStringFound);
        if(idMatcher.find()){
          umpleID=idMatcher.group(0).split(quo)[1];
        }
      }
      return umpleID;
    } catch(NullPointerException e){
      return umpleID;
    }
  }
   
  public static List<String> fromJsonParserList(String objListString){
    List<String> objList=new ArrayList<String>();
    try{
      String objString="(?:(?=.*?\\{(?!.*?\\1)(.*\\}(?!.*\\2).*))(?=.*?\\}(?!.*?\\2)(.*)).)+?.*?(?=\\1)[^\\{]*(?=\\2$)";
      Pattern objStringPattern=Pattern.compile(objString);
      Matcher objStringMatcher=objStringPattern.matcher(objListString);
      while(objStringMatcher.find()){
        objList.add(objStringMatcher.group(0));
      }
      return objList;
   }catch(NullPointerException e){
     return objList;
   }
  }
   
  public static String fromJsonParserClassName(String objNameString){
    String nextName="";
    String quotes="\\\"";
    try{
      String nextNameString="\\{\\\"[A-Z]\\w*\\\":";
      Pattern nextNamePattern=Pattern.compile(nextNameString);
      Matcher nextNameMatcher=nextNamePattern.matcher(objNameString);
      if(nextNameMatcher.find()){
        nextName=nextNameMatcher.group(0).split(quotes)[1];
       
      }
      return nextName;
   }catch(NullPointerException e){
     return nextName;
   }
  }
  
}
/*PLEASE DO NOT EDIT THIS CODE*/
/*This code was generated using the UMPLE 1.34.0.7242.6b8819789 modeling language!*/

package example;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.sql.*;
import java.lang.reflect.Constructor;

// line 41 "../ToJsonComplexTest.ump"
public class CourseSection
{

  //------------------------
  // MEMBER VARIABLES
  //------------------------

  //CourseSection Attributes
  private String code;

  //CourseSection Associations
  private Course course;
  private List<Employee> employees;
  private List<Registration> registrations;

  //------------------------
  // CONSTRUCTOR
  //------------------------

  public CourseSection(String aCode, Course aCourse)
  {
    code = aCode;
    boolean didAddCourse = setCourse(aCourse);
    if (!didAddCourse)
    {
      throw new RuntimeException("Unable to create courseSection due to course. See https://manual.umple.org?RE002ViolationofAssociationMultiplicity.html");
    }
    employees = new ArrayList<Employee>();
    registrations = new ArrayList<Registration>();
  }

  //------------------------
  // INTERFACE
  //------------------------

  public boolean setCode(String aCode)
  {
    boolean wasSet = false;
    code = aCode;
    wasSet = true;
    return wasSet;
  }

  public String getCode()
  {
    return code;
  }
  /* Code from template association_GetOne */
  public Course getCourse()
  {
    return course;
  }
  /* Code from template association_GetMany */
  public Employee getEmployee(int index)
  {
    Employee aEmployee = employees.get(index);
    return aEmployee;
  }

  public List<Employee> getEmployees()
  {
    List<Employee> newEmployees = Collections.unmodifiableList(employees);
    return newEmployees;
  }

  public int numberOfEmployees()
  {
    int number = employees.size();
    return number;
  }

  public boolean hasEmployees()
  {
    boolean has = employees.size() > 0;
    return has;
  }

  public int indexOfEmployee(Employee aEmployee)
  {
    int index = employees.indexOf(aEmployee);
    return index;
  }
  /* Code from template association_GetMany */
  public Registration getRegistration(int index)
  {
    Registration aRegistration = registrations.get(index);
    return aRegistration;
  }

  public List<Registration> getRegistrations()
  {
    List<Registration> newRegistrations = Collections.unmodifiableList(registrations);
    return newRegistrations;
  }

  public int numberOfRegistrations()
  {
    int number = registrations.size();
    return number;
  }

  public boolean hasRegistrations()
  {
    boolean has = registrations.size() > 0;
    return has;
  }

  public int indexOfRegistration(Registration aRegistration)
  {
    int index = registrations.indexOf(aRegistration);
    return index;
  }
  /* Code from template association_SetOneToMany */
  public boolean setCourse(Course aCourse)
  {
    boolean wasSet = false;
    if (aCourse == null)
    {
      return wasSet;
    }

    Course existingCourse = course;
    course = aCourse;
    if (existingCourse != null && !existingCourse.equals(aCourse))
    {
      existingCourse.removeCourseSection(this);
    }
    course.addCourseSection(this);
    wasSet = true;
    return wasSet;
  }
  /* Code from template association_MinimumNumberOfMethod */
  public static int minimumNumberOfEmployees()
  {
    return 0;
  }
  /* Code from template association_AddManyToManyMethod */
  public boolean addEmployee(Employee aEmployee)
  {
    boolean wasAdded = false;
    if (employees.contains(aEmployee)) { return false; }
    employees.add(aEmployee);
    if (aEmployee.indexOfTeache(this) != -1)
    {
      wasAdded = true;
    }
    else
    {
      wasAdded = aEmployee.addTeache(this);
      if (!wasAdded)
      {
        employees.remove(aEmployee);
      }
    }
    return wasAdded;
  }
  /* Code from template association_RemoveMany */
  public boolean removeEmployee(Employee aEmployee)
  {
    boolean wasRemoved = false;
    if (!employees.contains(aEmployee))
    {
      return wasRemoved;
    }

    int oldIndex = employees.indexOf(aEmployee);
    employees.remove(oldIndex);
    if (aEmployee.indexOfTeache(this) == -1)
    {
      wasRemoved = true;
    }
    else
    {
      wasRemoved = aEmployee.removeTeache(this);
      if (!wasRemoved)
      {
        employees.add(oldIndex,aEmployee);
      }
    }
    return wasRemoved;
  }
  /* Code from template association_AddIndexControlFunctions */
  public boolean addEmployeeAt(Employee aEmployee, int index)
  {  
    boolean wasAdded = false;
    if(addEmployee(aEmployee))
    {
      if(index < 0 ) { index = 0; }
      if(index > numberOfEmployees()) { index = numberOfEmployees() - 1; }
      employees.remove(aEmployee);
      employees.add(index, aEmployee);
      wasAdded = true;
    }
    return wasAdded;
  }

  public boolean addOrMoveEmployeeAt(Employee aEmployee, int index)
  {
    boolean wasAdded = false;
    if(employees.contains(aEmployee))
    {
      if(index < 0 ) { index = 0; }
      if(index > numberOfEmployees()) { index = numberOfEmployees() - 1; }
      employees.remove(aEmployee);
      employees.add(index, aEmployee);
      wasAdded = true;
    } 
    else 
    {
      wasAdded = addEmployeeAt(aEmployee, index);
    }
    return wasAdded;
  }
  /* Code from template association_MinimumNumberOfMethod */
  public static int minimumNumberOfRegistrations()
  {
    return 0;
  }
  /* Code from template association_AddManyToOne */
  public Registration addRegistration(Student aStudent)
  {
    return new Registration(aStudent, this);
  }

  public boolean addRegistration(Registration aRegistration)
  {
    boolean wasAdded = false;
    if (registrations.contains(aRegistration)) { return false; }
    CourseSection existingCourseSection = aRegistration.getCourseSection();
    boolean isNewCourseSection = existingCourseSection != null && !this.equals(existingCourseSection);
    if (isNewCourseSection)
    {
      aRegistration.setCourseSection(this);
    }
    else
    {
      registrations.add(aRegistration);
    }
    wasAdded = true;
    return wasAdded;
  }

  public boolean removeRegistration(Registration aRegistration)
  {
    boolean wasRemoved = false;
    //Unable to remove aRegistration, as it must always have a courseSection
    if (!this.equals(aRegistration.getCourseSection()))
    {
      registrations.remove(aRegistration);
      wasRemoved = true;
    }
    return wasRemoved;
  }
  /* Code from template association_AddIndexControlFunctions */
  public boolean addRegistrationAt(Registration aRegistration, int index)
  {  
    boolean wasAdded = false;
    if(addRegistration(aRegistration))
    {
      if(index < 0 ) { index = 0; }
      if(index > numberOfRegistrations()) { index = numberOfRegistrations() - 1; }
      registrations.remove(aRegistration);
      registrations.add(index, aRegistration);
      wasAdded = true;
    }
    return wasAdded;
  }

  public boolean addOrMoveRegistrationAt(Registration aRegistration, int index)
  {
    boolean wasAdded = false;
    if(registrations.contains(aRegistration))
    {
      if(index < 0 ) { index = 0; }
      if(index > numberOfRegistrations()) { index = numberOfRegistrations() - 1; }
      registrations.remove(aRegistration);
      registrations.add(index, aRegistration);
      wasAdded = true;
    } 
    else 
    {
      wasAdded = addRegistrationAt(aRegistration, index);
    }
    return wasAdded;
  }

  public void delete()
  {
    Course placeholderCourse = course;
    this.course = null;
    if(placeholderCourse != null)
    {
      placeholderCourse.removeCourseSection(this);
    }
    ArrayList<Employee> copyOfEmployees = new ArrayList<Employee>(employees);
    employees.clear();
    for(Employee aEmployee : copyOfEmployees)
    {
      aEmployee.removeTeache(this);
    }
    for(int i=registrations.size(); i > 0; i--)
    {
      Registration aRegistration = registrations.get(i - 1);
      aRegistration.delete();
    }
  }


  public String toString()
  {
    return super.toString() + "["+
            "code" + ":" + getCode()+ "]" + System.getProperties().getProperty("line.separator") +
            "  " + "course = "+(getCourse()!=null?Integer.toHexString(System.identityHashCode(getCourse())):"null");
  }
       
  /*
  * Generate Json for this object and connected objects visited objects to enable avoidance of infinite loops
  *
  * @return a string in Json  format of this object
  */ 
  public String toJson()
  {
    HashSet<Object> visitedList = new HashSet<Object>();
    StringBuilder toJsonOutput = new StringBuilder();
    toJsonOutput.append("{\n");
    this.toJsonHelper(toJsonOutput, visitedList,1,true);
    toJsonOutput.append("\n}");
    return(toJsonOutput.toString());
  }
   
  /*
  * Helper function to generate Json for this object and connected objects visited objects to enable avoidance of infinite loops
  *
  * @param toJsonOutput  Output is aded to this as the network of objects is traversed
  * @param visitedList  Every concrete object visited is added so we don't re-outpu
  * @param nestLevel    As we output deeper objects, indent them more
  * @param atConcreteClass false when we are recursing to a superclass
  *     so we get the superclass data
  * @return whether or not anything was output (so we can tell whether we need to output a comma)
  */ 
  public boolean toJsonHelper(StringBuilder toJsonOutput, HashSet<Object> visitedList, int nestLevel, boolean atConcreteClass){
      
      String indent = "  ".repeat(nestLevel);
      boolean alreadyVisited = false;
      boolean haveOutputItem = false;
      
    if(atConcreteClass) {
      // This will not be true in a super call; output header
      toJsonOutput.append(indent+"\""+this.toString().split("@")[0]+ "\" : {\n"+indent+ "  \"umpleObjectID\" : \""+System.identityHashCode(this)+"\"");
      // Check if we have already visited this object. If so we will not output details
      alreadyVisited = visitedList.contains(this);
      if(!alreadyVisited) {
        toJsonOutput.append(",\n");
        visitedList.add(this);
      }
    }
    
    // There is no superclass of this class
    if(alreadyVisited) {
      toJsonOutput.append("\n");
    }
    else {
      // Check if this class has a superclass. If it does, we make a call to output superclass content 
      // This will keep calling super so the topmost attributes and associations appear first
      // When an object has not already been visited, output its details
      if(haveOutputItem){
      //toJsonOutput.append(",\n");  
      }
        
          if(haveOutputItem){
            toJsonOutput.append(",\n");
          }
          toJsonOutput.append(indent);
          toJsonOutput.append("  \"");
          toJsonOutput.append("code");
          toJsonOutput.append("\" : \"");
          String primValue_0=""+getCode()+"";
          toJsonOutput.append(primValue_0.replace("\\","\\\\").replace("\"","\\\""));
          toJsonOutput.append("\"");
          haveOutputItem=true;
      //haveOutputItem = false;
      //haveOutputItem = false;
         if(haveOutputItem) {
           toJsonOutput.append(",\n");
         }
          toJsonOutput.append(indent);
            toJsonOutput.append("\n"+indent);
            toJsonOutput.append("  \"");
            toJsonOutput.append("course");
            toJsonOutput.append("\"");
            toJsonOutput.append(" : ");
            toJsonOutput.append("\n");
            toJsonOutput.append(indent+"  {");
            toJsonOutput.append("\n");Course anotherItem_0 = getCourse();
            anotherItem_0.toJsonHelper(toJsonOutput, visitedList, nestLevel+2, true);
            toJsonOutput.append("\n");
            toJsonOutput.append(indent+"  }");
            haveOutputItem=true;
         if(haveOutputItem) {
           toJsonOutput.append(",\n");
         }
          toJsonOutput.append(indent);
            toJsonOutput.append("  \"");
            toJsonOutput.append("employees");
            toJsonOutput.append("\"");
            toJsonOutput.append(" : [");
            toJsonOutput.append("\n");
            haveOutputItem = false;
            try{
              for (Employee anItem_1 :getEmployees()){
              if(haveOutputItem) {
                toJsonOutput.append(",\n");
              }
              toJsonOutput.append(indent+"  {");
              toJsonOutput.append("\n");
              anItem_1.toJsonHelper(toJsonOutput, visitedList,nestLevel+2,true);
              toJsonOutput.append("\n");
              toJsonOutput.append(indent+"  }");
              haveOutputItem=true;
            }
            }catch (NullPointerException e){
            }
            toJsonOutput.append("\n");    
            toJsonOutput.append(indent+"  ]");
            haveOutputItem=true;
         if(haveOutputItem) {
           toJsonOutput.append(",\n");
         }
          toJsonOutput.append(indent);
            toJsonOutput.append("  \"");
            toJsonOutput.append("registrations");
            toJsonOutput.append("\"");
            toJsonOutput.append(" : [");
            toJsonOutput.append("\n");
            haveOutputItem = false;
            try{
              for (Registration anItem_2 :getRegistrations()){
              if(haveOutputItem) {
                toJsonOutput.append(",\n");
              }
              toJsonOutput.append(indent+"  {");
              toJsonOutput.append("\n");
              anItem_2.toJsonHelper(toJsonOutput, visitedList,nestLevel+2,true);
              toJsonOutput.append("\n");
              toJsonOutput.append(indent+"  }");
              haveOutputItem=true;
            }
            }catch (NullPointerException e){
            }
            toJsonOutput.append("\n");    
            toJsonOutput.append(indent+"  ]");
            haveOutputItem=true;
              
          toJsonOutput.append(indent+"  \n");
    }
    // Finalize the output of the concrete class
    if(atConcreteClass) {
      if(!alreadyVisited) {
        toJsonOutput.append("\n");
      }
      toJsonOutput.append(indent+"}");
    }
    haveOutputItem = true;
    return haveOutputItem;
  }

  
      
  /*
  * Deserialize Json string to instantiate Objects from top-level class
  *
  * @param umpleObjectIDMap<String, Object> mapping parsed objectID (from Json string) with newly instantiated object's objectID
  * 
  * @param String aJsonString is the string in json format that is to be processed and turned into an object
  *
  * @return newly instantiated Object 
  */  

  public static CourseSection fromJson(String aJsonString){
    // process the input jsonString so that it can further processed using regex
    aJsonString=aJsonString.replace("\n","").replace(" ","");   
    // a map to store the umpleObjectID present in jsonString
    Map<String, Object> umpleObjectIDMap=new HashMap<>();
    
    // instantiate a new object
CourseSection anObject = new CourseSection(aJsonString, umpleObjectIDMap);
    return anObject;
  }
   
  /*
  * A new constructor specifically implemented if -s genJson is specified
  * 
  * @param String aJsonString is the string in json format that is to be processed and turned into an object
  *
  * @param umpleObjectIDMap<String, Integer> mapping parsed objectID (from Json string) with newly instantiated object's objectID
  */ 
  @SuppressWarnings("unchecked")
  public CourseSection(String aJsonString, Map<String, Object> umpleObjectIDMap){
    // Initialize a HashMap to store the parsed result
    // key is the attribute name present in the jsonString
    // value is the attribute value present in the jsonString
      boolean visitedSuperClass=false;
    
    HashMap<String,String> parsedResult = new HashMap<String,String>();
    parsedResult = fromJsonParser(aJsonString);
    if(!parsedResult.isEmpty()){
    boolean classExist;
    boolean classChildExist;
    String parsedClassName=parsedResult.get("className");
    String childName=this.getClass().getSimpleName();
    classExist="CourseSection".equals(parsedClassName);
    classChildExist=childName.equals(parsedClassName);
    // if top-level class does not exist, throw exception
    if(!classExist&&!classChildExist){
      throw new IllegalArgumentException("Top-level class \""+parsedClassName+"\" does not exist, please check the input json string");
    }
    String umpleObjectId=parsedResult.get("umpleObjectID");
    // Check if the object has already been visited and created
    //if((umpleObjectIDMap.get(umpleObjectId)==null)||visitedSuperClass){
      try{
      
    visitedSuperClass=false;
    // map the old objectID (in jsonString) with the newly created object's hashCode in umpleObjectIDMap 
    umpleObjectIDMap.put(umpleObjectId,this);
    
    String jsonKey="";
       jsonKey="code";
       //more types should be considered here
        this.code=parsedResult.get(jsonKey);
    
    // below for-loop check the association class of the top level class
       
       jsonKey="course";
       String newJsonString_0=parsedResult.get(jsonKey);
       String newIDRegex_0="\\\"umpleObjectID\\\"\\:\\\"[0-9]*\\\"";
       String newUmpleID_0=fromJsonParserHelper(newJsonString_0,newIDRegex_0);
       
       //Multiple associations
          
          if(!umpleObjectIDMap.containsKey(newUmpleID_0)){
            String newClassNameOne_0=fromJsonParserClassName(newJsonString_0);
            Class clazzOne_0=Class.forName(newClassNameOne_0);
            Constructor constructorOne_0=clazzOne_0.getConstructor(String.class, Map.class);
            Object objectNewOne_0=constructorOne_0.newInstance(newJsonString_0,umpleObjectIDMap);
Course oneAssoObj_0=(Course)objectNewOne_0;
course=oneAssoObj_0;
          }
          else{
course=(Course)umpleObjectIDMap.get(newUmpleID_0);
          }

       
       jsonKey="employees";
       String newJsonString_1=parsedResult.get(jsonKey);
       String newIDRegex_1="\\\"umpleObjectID\\\"\\:\\\"[0-9]*\\\"";
       String newUmpleID_1=fromJsonParserHelper(newJsonString_1,newIDRegex_1);
       
       //Multiple associations
           List<String> multiAssoObjList_1 = new ArrayList<String>();
           multiAssoObjList_1=fromJsonParserList(newJsonString_1);
employees=new ArrayList<Employee>();
           for(String obj: multiAssoObjList_1){
             newUmpleID_1=fromJsonParserHelper(obj,newIDRegex_1);
             
             String newClassName_1=fromJsonParserClassName(obj);
           if(!umpleObjectIDMap.containsKey(newUmpleID_1)){
           
            boolean subClassFound=false;
            Class clazz_1=Class.forName(newClassName_1);
            Constructor constructor_1=clazz_1.getConstructor(String.class, Map.class);
            Object objectNew_1=constructor_1.newInstance(obj,umpleObjectIDMap);
employees.add((Employee)objectNew_1);
            }
           else{
employees.add((Employee)umpleObjectIDMap.get(newUmpleID_1));
           }
         }

       
       jsonKey="registrations";
       String newJsonString_2=parsedResult.get(jsonKey);
       String newIDRegex_2="\\\"umpleObjectID\\\"\\:\\\"[0-9]*\\\"";
       String newUmpleID_2=fromJsonParserHelper(newJsonString_2,newIDRegex_2);
       
       //Multiple associations
           List<String> multiAssoObjList_2 = new ArrayList<String>();
           multiAssoObjList_2=fromJsonParserList(newJsonString_2);
registrations=new ArrayList<Registration>();
           for(String obj: multiAssoObjList_2){
             newUmpleID_2=fromJsonParserHelper(obj,newIDRegex_2);
             
             String newClassName_2=fromJsonParserClassName(obj);
           if(!umpleObjectIDMap.containsKey(newUmpleID_2)){
           
            boolean subClassFound=false;
            Class clazz_2=Class.forName(newClassName_2);
            Constructor constructor_2=clazz_2.getConstructor(String.class, Map.class);
            Object objectNew_2=constructor_2.newInstance(obj,umpleObjectIDMap);
registrations.add((Registration)objectNew_2);
            }
           else{
registrations.add((Registration)umpleObjectIDMap.get(newUmpleID_2));
           }
         }


    
    }catch(Exception e){
    }

    //}
  }
  } 
  /*
  * A json parser to parse the input jsonString, if -s genJson is specified
  * 
  * @param String aJsonString is the string in json format that is to be processed and turned into an object
  *
  * @ return HashMap<String,String> that stores paresed result, key is the attribute(or associations) of an object, value is the attribute value or association string
  */ 
  public static HashMap<String,String> fromJsonParser(String jsonString){
    
    HashMap<String,String> parsedResultMap = new HashMap<String,String>();
    try{
      //Below (String, Pattern, Matcher) are the regex strings and their patterns and matcher used to process a jsonString
    
        // topLevelString is the regex representing the topLevel class name
        String topLevelString = "\\{\\\"[A-Z]\\w*\\\":";
        Pattern topLevelPattern = Pattern.compile(topLevelString);
        Matcher topLevelMatcher = topLevelPattern.matcher(jsonString);
        String quotes="\\\"";
        String colon="\\:";
        String colonSquareBracket="\\:\\[";
        
        if(topLevelMatcher.find()){
            //actual string that represent the topLevel className
            String topLevelStringFound=topLevelMatcher.group(0);
            String className=topLevelStringFound.split(quotes)[1];
            parsedResultMap.put("className", className);
            jsonString=jsonString.split(topLevelString,2)[1];
            
            //objIDString is the regex representing umpleObjectID that could be found in jsonString
            String objIDString = "\"umpleObjectID\"\\:\"[0-9]*\",";
            Pattern objIDPattern = Pattern.compile(objIDString);
            Matcher objIDMatcher = objIDPattern.matcher(jsonString);
            if(objIDMatcher.find()){
              String objIDFound=objIDMatcher.group(0);
              parsedResultMap.put("umpleObjectID", objIDFound.split(colon)[1].split(quotes)[1]);
              jsonString=jsonString.replaceFirst(objIDFound,"");
            }
            String timeString="\\\"\\w*\\\"\\:\\\"\\d{2}:\\d{2}\\:\\d{2}\\\"";
            Pattern timeStringPattern=Pattern.compile(timeString);
            Matcher timeStringPatternMatcher=timeStringPattern.matcher(jsonString);
            if(timeStringPatternMatcher.find()){
              String timeStringFound=timeStringPatternMatcher.group(0);
              parsedResultMap.put(timeStringFound.split(colon,2)[0].split(quotes)[1], timeStringFound.split(colon,2)[1].split(quotes)[1]);
          
            }
            // pairString is the regex for an object's attribute and attribute value, the string parsed will be in key-value formate
        String pairString = "(\\\"(?!umpleObjectID)[^\\\"]+)\\\":\\\"((?:\\\\\\\"|[^\\\"])*)";
        Pattern pairPattern=Pattern.compile(pairString);
        Matcher pairMatcher=pairPattern.matcher(jsonString);
        String associationString="(?=\\\"\\w*\\\"\\:\\[\\{)(?:(?=.*?\\[\\{(?!.*?\\1)(.*\\}\\](?!.*\\2).*))(?=.*?\\}\\](?!.*?\\2)(.*)).)+?.*?(?=\\1)[^\\[]*(?=\\2$)";
        Pattern associationPattern=Pattern.compile(associationString);
        String newObjJsonString="(?=\\,\\\"\\w*\\\"\\:\\{)(?:(?=.*?\\{\\\"(?!.*?\\1)(.*\\}(?!.*\\2).*))(?=.*?\\}(?!.*?\\2)(.*)).)+?.*?(?=\\1)[^\\{]*(?=\\2$)";
        Pattern newObjJsonPattern=Pattern.compile(newObjJsonString);
        String quoteColonQuote="\\\"\\:\\\"";
        //Keep on parsing the attribute's key-value pair, 
        //until a List (multi-associations) pattern or a newObject parttern (single association) is found
        while(pairMatcher.find()){
               String pairStringFound=pairMatcher.group(0);
              if(parsedResultMap.get(pairStringFound.split(colon)[0].split(quotes)[1])==null){
                String keyPair=pairStringFound.split(colon)[0].split(quotes)[1];
                String valuePair=pairStringFound.split(quoteColonQuote,2)[1];
                keyPair=keyPair.replace("\\\\","\\").replace("\\\"","\"");
                valuePair=valuePair.replace("\\\\","\\").replace("\\\"","\"");
                parsedResultMap.put(keyPair,valuePair);
                jsonString=jsonString.replaceFirst(pairString, "");
              }
                int lastIndex = 0;
                while (lastIndex<jsonString.length()){
                  String remainingJson=jsonString.substring(lastIndex);
                  Matcher associationMatcher=associationPattern.matcher(jsonString);
                  Matcher newObjJsonMatcher=newObjJsonPattern.matcher(jsonString);
                  
                  boolean assoFound=associationMatcher.find();
                  boolean newObjFound=newObjJsonMatcher.find();
                  
                  if (assoFound&&(!newObjFound||associationMatcher.start()<newObjJsonMatcher.start())){
                    String assoStringFound=associationMatcher.group(0);
                    String associationName=assoStringFound.split(colon,2)[0].split(quotes)[1];;
                    String associationItems=assoStringFound.split(colonSquareBracket,2)[1];
                    parsedResultMap.put(associationName, associationItems);
                    jsonString=jsonString.replaceFirst(associationString, "");
                  }
                  else if (newObjFound){
                    String newObjJsonFound=newObjJsonMatcher.group(0);
                    String newObjName=newObjJsonFound.split(colon,2)[0].split(quotes)[1];
                    String newObjItems=newObjJsonFound.split(colon,2)[1];
                    parsedResultMap.put(newObjName, newObjItems);
                    jsonString=jsonString.replaceFirst(newObjJsonString, "");
                  }else{
                    break;
                  }
                }
        }
        }
        return parsedResultMap;
    }catch(NullPointerException e){
      return parsedResultMap;
    }
  }
   
  public static String fromJsonParserHelper(String jsonString, String regexString){
    String umpleID = "";
    String quo="\\\"";
    try{
      Pattern umpleIDPattern=Pattern.compile(regexString);
      Matcher umpleIDMatcher=umpleIDPattern.matcher(jsonString);
      if(umpleIDMatcher.find()){
        String umpleIDStringFound=umpleIDMatcher.group(0);
        String idString="\\\"\\d*\\\"";
        Pattern idPattern=Pattern.compile(idString);
        Matcher idMatcher=idPattern.matcher(umpleIDStringFound);
        if(idMatcher.find()){
          umpleID=idMatcher.group(0).split(quo)[1];
        }
      }
      return umpleID;
    } catch(NullPointerException e){
      return umpleID;
    }
  }
   
  public static List<String> fromJsonParserList(String objListString){
    List<String> objList=new ArrayList<String>();
    try{
      String objString="(?:(?=.*?\\{(?!.*?\\1)(.*\\}(?!.*\\2).*))(?=.*?\\}(?!.*?\\2)(.*)).)+?.*?(?=\\1)[^\\{]*(?=\\2$)";
      Pattern objStringPattern=Pattern.compile(objString);
      Matcher objStringMatcher=objStringPattern.matcher(objListString);
      while(objStringMatcher.find()){
        objList.add(objStringMatcher.group(0));
      }
      return objList;
   }catch(NullPointerException e){
     return objList;
   }
  }
   
  public static String fromJsonParserClassName(String objNameString){
    String nextName="";
    String quotes="\\\"";
    try{
      String nextNameString="\\{\\\"[A-Z]\\w*\\\":";
      Pattern nextNamePattern=Pattern.compile(nextNameString);
      Matcher nextNameMatcher=nextNamePattern.matcher(objNameString);
      if(nextNameMatcher.find()){
        nextName=nextNameMatcher.group(0).split(quotes)[1];
       
      }
      return nextName;
   }catch(NullPointerException e){
     return nextName;
   }
  }
  
}
/*PLEASE DO NOT EDIT THIS CODE*/
/*This code was generated using the UMPLE 1.34.0.7242.6b8819789 modeling language!*/

package example;
import java.util.HashSet;
import java.util.Map;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.ArrayList;
import java.util.List;
import java.sql.*;
import java.lang.reflect.Constructor;

// line 46 "../ToJsonComplexTest.ump"
public class Registration
{

  //------------------------
  // MEMBER VARIABLES
  //------------------------

  //Registration Attributes
  private String grade;

  //Registration Associations
  private Student student;
  private CourseSection courseSection;

  //Helper Variables
  private int cachedHashCode;
  private boolean canSetStudent;
  private boolean canSetCourseSection;

  //------------------------
  // CONSTRUCTOR
  //------------------------

  public Registration(Student aStudent, CourseSection aCourseSection)
  {
    cachedHashCode = -1;
    canSetStudent = true;
    canSetCourseSection = true;
    grade = null;
    boolean didAddStudent = setStudent(aStudent);
    if (!didAddStudent)
    {
      throw new RuntimeException("Unable to create registration due to student. See https://manual.umple.org?RE002ViolationofAssociationMultiplicity.html");
    }
    boolean didAddCourseSection = setCourseSection(aCourseSection);
    if (!didAddCourseSection)
    {
      throw new RuntimeException("Unable to create registration due to courseSection. See https://manual.umple.org?RE002ViolationofAssociationMultiplicity.html");
    }
  }

  //------------------------
  // INTERFACE
  //------------------------

  public boolean setGrade(String aGrade)
  {
    boolean wasSet = false;
    grade = aGrade;
    wasSet = true;
    return wasSet;
  }

  public String getGrade()
  {
    return grade;
  }
  /* Code from template association_GetOne */
  public Student getStudent()
  {
    return student;
  }
  /* Code from template association_GetOne */
  public CourseSection getCourseSection()
  {
    return courseSection;
  }
  /* Code from template association_SetOneToManyAssociationClass */
  public boolean setStudent(Student aStudent)
  {
    boolean wasSet = false;
    if (!canSetStudent) { return false; }
    if (aStudent == null)
    {
      return wasSet;
    }

    Student existingStudent = student;
    student = aStudent;
    if (existingStudent != null && !existingStudent.equals(aStudent))
    {
      existingStudent.removeRegistration(this);
    }
    if (!student.addRegistration(this))
    {
      student = existingStudent;
      wasSet = false;
    }
    else
    {
      wasSet = true;
    }
    return wasSet;
  }
  /* Code from template association_SetOneToManyAssociationClass */
  public boolean setCourseSection(CourseSection aCourseSection)
  {
    boolean wasSet = false;
    if (!canSetCourseSection) { return false; }
    if (aCourseSection == null)
    {
      return wasSet;
    }

    CourseSection existingCourseSection = courseSection;
    courseSection = aCourseSection;
    if (existingCourseSection != null && !existingCourseSection.equals(aCourseSection))
    {
      existingCourseSection.removeRegistration(this);
    }
    if (!courseSection.addRegistration(this))
    {
      courseSection = existingCourseSection;
      wasSet = false;
    }
    else
    {
      wasSet = true;
    }
    return wasSet;
  }

  public boolean equals(Object obj)
  {
    if (obj == null) { return false; }
    if (!getClass().equals(obj.getClass())) { return false; }

    Registration compareTo = (Registration)obj;
  
    if (getStudent() == null && compareTo.getStudent() != null)
    {
      return false;
    }
    else if (getStudent() != null && !getStudent().equals(compareTo.getStudent()))
    {
      return false;
    }

    if (getCourseSection() == null && compareTo.getCourseSection() != null)
    {
      return false;
    }
    else if (getCourseSection() != null && !getCourseSection().equals(compareTo.getCourseSection()))
    {
      return false;
    }

    return true;
  }

  public int hashCode()
  {
    if (cachedHashCode != -1)
    {
      return cachedHashCode;
    }
    cachedHashCode = 17;
    if (getStudent() != null)
    {
      cachedHashCode = cachedHashCode * 23 + getStudent().hashCode();
    }
    else
    {
      cachedHashCode = cachedHashCode * 23;
    }
    if (getCourseSection() != null)
    {
      cachedHashCode = cachedHashCode * 23 + getCourseSection().hashCode();
    }
    else
    {
      cachedHashCode = cachedHashCode * 23;
    }

    canSetStudent = false;
    canSetCourseSection = false;
    return cachedHashCode;
  }

  public void delete()
  {
    Student placeholderStudent = student;
    this.student = null;
    if(placeholderStudent != null)
    {
      placeholderStudent.removeRegistration(this);
    }
    CourseSection placeholderCourseSection = courseSection;
    this.courseSection = null;
    if(placeholderCourseSection != null)
    {
      placeholderCourseSection.removeRegistration(this);
    }
  }


  public String toString()
  {
    return super.toString() + "["+
            "grade" + ":" + getGrade()+ "]" + System.getProperties().getProperty("line.separator") +
            "  " + "student = "+(getStudent()!=null?Integer.toHexString(System.identityHashCode(getStudent())):"null") + System.getProperties().getProperty("line.separator") +
            "  " + "courseSection = "+(getCourseSection()!=null?Integer.toHexString(System.identityHashCode(getCourseSection())):"null");
  }
       
  /*
  * Generate Json for this object and connected objects visited objects to enable avoidance of infinite loops
  *
  * @return a string in Json  format of this object
  */ 
  public String toJson()
  {
    HashSet<Object> visitedList = new HashSet<Object>();
    StringBuilder toJsonOutput = new StringBuilder();
    toJsonOutput.append("{\n");
    this.toJsonHelper(toJsonOutput, visitedList,1,true);
    toJsonOutput.append("\n}");
    return(toJsonOutput.toString());
  }
   
  /*
  * Helper function to generate Json for this object and connected objects visited objects to enable avoidance of infinite loops
  *
  * @param toJsonOutput  Output is aded to this as the network of objects is traversed
  * @param visitedList  Every concrete object visited is added so we don't re-outpu
  * @param nestLevel    As we output deeper objects, indent them more
  * @param atConcreteClass false when we are recursing to a superclass
  *     so we get the superclass data
  * @return whether or not anything was output (so we can tell whether we need to output a comma)
  */ 
  public boolean toJsonHelper(StringBuilder toJsonOutput, HashSet<Object> visitedList, int nestLevel, boolean atConcreteClass){
      
      String indent = "  ".repeat(nestLevel);
      boolean alreadyVisited = false;
      boolean haveOutputItem = false;
      
    if(atConcreteClass) {
      // This will not be true in a super call; output header
      toJsonOutput.append(indent+"\""+this.toString().split("@")[0]+ "\" : {\n"+indent+ "  \"umpleObjectID\" : \""+System.identityHashCode(this)+"\"");
      // Check if we have already visited this object. If so we will not output details
      alreadyVisited = visitedList.contains(this);
      if(!alreadyVisited) {
        toJsonOutput.append(",\n");
        visitedList.add(this);
      }
    }
    
    // There is no superclass of this class
    if(alreadyVisited) {
      toJsonOutput.append("\n");
    }
    else {
      // Check if this class has a superclass. If it does, we make a call to output superclass content 
      // This will keep calling super so the topmost attributes and associations appear first
      // When an object has not already been visited, output its details
      if(haveOutputItem){
      //toJsonOutput.append(",\n");  
      }
        
          if(haveOutputItem){
            toJsonOutput.append(",\n");
          }
          toJsonOutput.append(indent);
          toJsonOutput.append("  \"");
          toJsonOutput.append("grade");
          toJsonOutput.append("\" : \"");
          String primValue_0=""+getGrade()+"";
          toJsonOutput.append(primValue_0.replace("\\","\\\\").replace("\"","\\\""));
          toJsonOutput.append("\"");
          haveOutputItem=true;
      //haveOutputItem = false;
      //haveOutputItem = false;
         if(haveOutputItem) {
           toJsonOutput.append(",\n");
         }
          toJsonOutput.append(indent);
            toJsonOutput.append("\n"+indent);
            toJsonOutput.append("  \"");
            toJsonOutput.append("student");
            toJsonOutput.append("\"");
            toJsonOutput.append(" : ");
            toJsonOutput.append("\n");
            toJsonOutput.append(indent+"  {");
            toJsonOutput.append("\n");Student anotherItem_0 = getStudent();
            anotherItem_0.toJsonHelper(toJsonOutput, visitedList, nestLevel+2, true);
            toJsonOutput.append("\n");
            toJsonOutput.append(indent+"  }");
            haveOutputItem=true;
         if(haveOutputItem) {
           toJsonOutput.append(",\n");
         }
          toJsonOutput.append(indent);
            toJsonOutput.append("\n"+indent);
            toJsonOutput.append("  \"");
            toJsonOutput.append("courseSection");
            toJsonOutput.append("\"");
            toJsonOutput.append(" : ");
            toJsonOutput.append("\n");
            toJsonOutput.append(indent+"  {");
            toJsonOutput.append("\n");CourseSection anotherItem_1 = getCourseSection();
            anotherItem_1.toJsonHelper(toJsonOutput, visitedList, nestLevel+2, true);
            toJsonOutput.append("\n");
            toJsonOutput.append(indent+"  }");
            haveOutputItem=true;
              
          toJsonOutput.append(indent+"  \n");
    }
    // Finalize the output of the concrete class
    if(atConcreteClass) {
      if(!alreadyVisited) {
        toJsonOutput.append("\n");
      }
      toJsonOutput.append(indent+"}");
    }
    haveOutputItem = true;
    return haveOutputItem;
  }

  
      
  /*
  * Deserialize Json string to instantiate Objects from top-level class
  *
  * @param umpleObjectIDMap<String, Object> mapping parsed objectID (from Json string) with newly instantiated object's objectID
  * 
  * @param String aJsonString is the string in json format that is to be processed and turned into an object
  *
  * @return newly instantiated Object 
  */  

  public static Registration fromJson(String aJsonString){
    // process the input jsonString so that it can further processed using regex
    aJsonString=aJsonString.replace("\n","").replace(" ","");   
    // a map to store the umpleObjectID present in jsonString
    Map<String, Object> umpleObjectIDMap=new HashMap<>();
    
    // instantiate a new object
Registration anObject = new Registration(aJsonString, umpleObjectIDMap);
    return anObject;
  }
   
  /*
  * A new constructor specifically implemented if -s genJson is specified
  * 
  * @param String aJsonString is the string in json format that is to be processed and turned into an object
  *
  * @param umpleObjectIDMap<String, Integer> mapping parsed objectID (from Json string) with newly instantiated object's objectID
  */ 
  @SuppressWarnings("unchecked")
  public Registration(String aJsonString, Map<String, Object> umpleObjectIDMap){
    // Initialize a HashMap to store the parsed result
    // key is the attribute name present in the jsonString
    // value is the attribute value present in the jsonString
      boolean visitedSuperClass=false;
    
    HashMap<String,String> parsedResult = new HashMap<String,String>();
    parsedResult = fromJsonParser(aJsonString);
    if(!parsedResult.isEmpty()){
    boolean classExist;
    boolean classChildExist;
    String parsedClassName=parsedResult.get("className");
    String childName=this.getClass().getSimpleName();
    classExist="Registration".equals(parsedClassName);
    classChildExist=childName.equals(parsedClassName);
    // if top-level class does not exist, throw exception
    if(!classExist&&!classChildExist){
      throw new IllegalArgumentException("Top-level class \""+parsedClassName+"\" does not exist, please check the input json string");
    }
    String umpleObjectId=parsedResult.get("umpleObjectID");
    // Check if the object has already been visited and created
    //if((umpleObjectIDMap.get(umpleObjectId)==null)||visitedSuperClass){
      try{
      
    visitedSuperClass=false;
    // map the old objectID (in jsonString) with the newly created object's hashCode in umpleObjectIDMap 
    umpleObjectIDMap.put(umpleObjectId,this);
    
    String jsonKey="";
       jsonKey="grade";
       //more types should be considered here
        this.grade=parsedResult.get(jsonKey);
    
    // below for-loop check the association class of the top level class
       
       jsonKey="student";
       String newJsonString_0=parsedResult.get(jsonKey);
       String newIDRegex_0="\\\"umpleObjectID\\\"\\:\\\"[0-9]*\\\"";
       String newUmpleID_0=fromJsonParserHelper(newJsonString_0,newIDRegex_0);
       
          cachedHashCode=-1;
       //Multiple associations
          
          if(!umpleObjectIDMap.containsKey(newUmpleID_0)){
            String newClassNameOne_0=fromJsonParserClassName(newJsonString_0);
            Class clazzOne_0=Class.forName(newClassNameOne_0);
            Constructor constructorOne_0=clazzOne_0.getConstructor(String.class, Map.class);
            Object objectNewOne_0=constructorOne_0.newInstance(newJsonString_0,umpleObjectIDMap);
Student oneAssoObj_0=(Student)objectNewOne_0;
student=oneAssoObj_0;
          }
          else{
student=(Student)umpleObjectIDMap.get(newUmpleID_0);
          }

       
       jsonKey="courseSection";
       String newJsonString_1=parsedResult.get(jsonKey);
       String newIDRegex_1="\\\"umpleObjectID\\\"\\:\\\"[0-9]*\\\"";
       String newUmpleID_1=fromJsonParserHelper(newJsonString_1,newIDRegex_1);
       
          cachedHashCode=-1;
       //Multiple associations
          
          if(!umpleObjectIDMap.containsKey(newUmpleID_1)){
            String newClassNameOne_1=fromJsonParserClassName(newJsonString_1);
            Class clazzOne_1=Class.forName(newClassNameOne_1);
            Constructor constructorOne_1=clazzOne_1.getConstructor(String.class, Map.class);
            Object objectNewOne_1=constructorOne_1.newInstance(newJsonString_1,umpleObjectIDMap);
CourseSection oneAssoObj_1=(CourseSection)objectNewOne_1;
courseSection=oneAssoObj_1;
          }
          else{
courseSection=(CourseSection)umpleObjectIDMap.get(newUmpleID_1);
          }


    
    }catch(Exception e){
    }

    //}
  }
  } 
  /*
  * A json parser to parse the input jsonString, if -s genJson is specified
  * 
  * @param String aJsonString is the string in json format that is to be processed and turned into an object
  *
  * @ return HashMap<String,String> that stores paresed result, key is the attribute(or associations) of an object, value is the attribute value or association string
  */ 
  public static HashMap<String,String> fromJsonParser(String jsonString){
    
    HashMap<String,String> parsedResultMap = new HashMap<String,String>();
    try{
      //Below (String, Pattern, Matcher) are the regex strings and their patterns and matcher used to process a jsonString
    
        // topLevelString is the regex representing the topLevel class name
        String topLevelString = "\\{\\\"[A-Z]\\w*\\\":";
        Pattern topLevelPattern = Pattern.compile(topLevelString);
        Matcher topLevelMatcher = topLevelPattern.matcher(jsonString);
        String quotes="\\\"";
        String colon="\\:";
        String colonSquareBracket="\\:\\[";
        
        if(topLevelMatcher.find()){
            //actual string that represent the topLevel className
            String topLevelStringFound=topLevelMatcher.group(0);
            String className=topLevelStringFound.split(quotes)[1];
            parsedResultMap.put("className", className);
            jsonString=jsonString.split(topLevelString,2)[1];
            
            //objIDString is the regex representing umpleObjectID that could be found in jsonString
            String objIDString = "\"umpleObjectID\"\\:\"[0-9]*\",";
            Pattern objIDPattern = Pattern.compile(objIDString);
            Matcher objIDMatcher = objIDPattern.matcher(jsonString);
            if(objIDMatcher.find()){
              String objIDFound=objIDMatcher.group(0);
              parsedResultMap.put("umpleObjectID", objIDFound.split(colon)[1].split(quotes)[1]);
              jsonString=jsonString.replaceFirst(objIDFound,"");
            }
            String timeString="\\\"\\w*\\\"\\:\\\"\\d{2}:\\d{2}\\:\\d{2}\\\"";
            Pattern timeStringPattern=Pattern.compile(timeString);
            Matcher timeStringPatternMatcher=timeStringPattern.matcher(jsonString);
            if(timeStringPatternMatcher.find()){
              String timeStringFound=timeStringPatternMatcher.group(0);
              parsedResultMap.put(timeStringFound.split(colon,2)[0].split(quotes)[1], timeStringFound.split(colon,2)[1].split(quotes)[1]);
          
            }
            // pairString is the regex for an object's attribute and attribute value, the string parsed will be in key-value formate
        String pairString = "(\\\"(?!umpleObjectID)[^\\\"]+)\\\":\\\"((?:\\\\\\\"|[^\\\"])*)";
        Pattern pairPattern=Pattern.compile(pairString);
        Matcher pairMatcher=pairPattern.matcher(jsonString);
        String associationString="(?=\\\"\\w*\\\"\\:\\[\\{)(?:(?=.*?\\[\\{(?!.*?\\1)(.*\\}\\](?!.*\\2).*))(?=.*?\\}\\](?!.*?\\2)(.*)).)+?.*?(?=\\1)[^\\[]*(?=\\2$)";
        Pattern associationPattern=Pattern.compile(associationString);
        String newObjJsonString="(?=\\,\\\"\\w*\\\"\\:\\{)(?:(?=.*?\\{\\\"(?!.*?\\1)(.*\\}(?!.*\\2).*))(?=.*?\\}(?!.*?\\2)(.*)).)+?.*?(?=\\1)[^\\{]*(?=\\2$)";
        Pattern newObjJsonPattern=Pattern.compile(newObjJsonString);
        String quoteColonQuote="\\\"\\:\\\"";
        //Keep on parsing the attribute's key-value pair, 
        //until a List (multi-associations) pattern or a newObject parttern (single association) is found
        while(pairMatcher.find()){
               String pairStringFound=pairMatcher.group(0);
              if(parsedResultMap.get(pairStringFound.split(colon)[0].split(quotes)[1])==null){
                String keyPair=pairStringFound.split(colon)[0].split(quotes)[1];
                String valuePair=pairStringFound.split(quoteColonQuote,2)[1];
                keyPair=keyPair.replace("\\\\","\\").replace("\\\"","\"");
                valuePair=valuePair.replace("\\\\","\\").replace("\\\"","\"");
                parsedResultMap.put(keyPair,valuePair);
                jsonString=jsonString.replaceFirst(pairString, "");
              }
                int lastIndex = 0;
                while (lastIndex<jsonString.length()){
                  String remainingJson=jsonString.substring(lastIndex);
                  Matcher associationMatcher=associationPattern.matcher(jsonString);
                  Matcher newObjJsonMatcher=newObjJsonPattern.matcher(jsonString);
                  
                  boolean assoFound=associationMatcher.find();
                  boolean newObjFound=newObjJsonMatcher.find();
                  
                  if (assoFound&&(!newObjFound||associationMatcher.start()<newObjJsonMatcher.start())){
                    String assoStringFound=associationMatcher.group(0);
                    String associationName=assoStringFound.split(colon,2)[0].split(quotes)[1];;
                    String associationItems=assoStringFound.split(colonSquareBracket,2)[1];
                    parsedResultMap.put(associationName, associationItems);
                    jsonString=jsonString.replaceFirst(associationString, "");
                  }
                  else if (newObjFound){
                    String newObjJsonFound=newObjJsonMatcher.group(0);
                    String newObjName=newObjJsonFound.split(colon,2)[0].split(quotes)[1];
                    String newObjItems=newObjJsonFound.split(colon,2)[1];
                    parsedResultMap.put(newObjName, newObjItems);
                    jsonString=jsonString.replaceFirst(newObjJsonString, "");
                  }else{
                    break;
                  }
                }
        }
        }
        return parsedResultMap;
    }catch(NullPointerException e){
      return parsedResultMap;
    }
  }
   
  public static String fromJsonParserHelper(String jsonString, String regexString){
    String umpleID = "";
    String quo="\\\"";
    try{
      Pattern umpleIDPattern=Pattern.compile(regexString);
      Matcher umpleIDMatcher=umpleIDPattern.matcher(jsonString);
      if(umpleIDMatcher.find()){
        String umpleIDStringFound=umpleIDMatcher.group(0);
        String idString="\\\"\\d*\\\"";
        Pattern idPattern=Pattern.compile(idString);
        Matcher idMatcher=idPattern.matcher(umpleIDStringFound);
        if(idMatcher.find()){
          umpleID=idMatcher.group(0).split(quo)[1];
        }
      }
      return umpleID;
    } catch(NullPointerException e){
      return umpleID;
    }
  }
   
  public static List<String> fromJsonParserList(String objListString){
    List<String> objList=new ArrayList<String>();
    try{
      String objString="(?:(?=.*?\\{(?!.*?\\1)(.*\\}(?!.*\\2).*))(?=.*?\\}(?!.*?\\2)(.*)).)+?.*?(?=\\1)[^\\{]*(?=\\2$)";
      Pattern objStringPattern=Pattern.compile(objString);
      Matcher objStringMatcher=objStringPattern.matcher(objListString);
      while(objStringMatcher.find()){
        objList.add(objStringMatcher.group(0));
      }
      return objList;
   }catch(NullPointerException e){
     return objList;
   }
  }
   
  public static String fromJsonParserClassName(String objNameString){
    String nextName="";
    String quotes="\\\"";
    try{
      String nextNameString="\\{\\\"[A-Z]\\w*\\\":";
      Pattern nextNamePattern=Pattern.compile(nextNameString);
      Matcher nextNameMatcher=nextNamePattern.matcher(objNameString);
      if(nextNameMatcher.find()){
        nextName=nextNameMatcher.group(0).split(quotes)[1];
       
      }
      return nextName;
   }catch(NullPointerException e){
     return nextName;
   }
  }
  
}
/*PLEASE DO NOT EDIT THIS CODE*/
/*This code was generated using the UMPLE 1.34.0.7242.6b8819789 modeling language!*/

package example;
import java.util.HashSet;
import java.util.Map;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.ArrayList;
import java.util.List;
import java.sql.*;
import java.lang.reflect.Constructor;

// line 11 "../ToJsonComplexTest.ump"
public class Person
{

  //------------------------
  // MEMBER VARIABLES
  //------------------------

  //Person Attributes
  private int id;
  private String name;

  //------------------------
  // CONSTRUCTOR
  //------------------------

  public Person(int aId, String aName)
  {
    id = aId;
    name = aName;
  }

  //------------------------
  // INTERFACE
  //------------------------

  public boolean setId(int aId)
  {
    boolean wasSet = false;
    id = aId;
    wasSet = true;
    return wasSet;
  }

  public boolean setName(String aName)
  {
    boolean wasSet = false;
    name = aName;
    wasSet = true;
    return wasSet;
  }

  public int getId()
  {
    return id;
  }

  public String getName()
  {
    return name;
  }

  public void delete()
  {}


  public String toString()
  {
    return super.toString() + "["+
            "id" + ":" + getId()+ "," +
            "name" + ":" + getName()+ "]";
  }
       
  /*
  * Generate Json for this object and connected objects visited objects to enable avoidance of infinite loops
  *
  * @return a string in Json  format of this object
  */ 
  public String toJson()
  {
    HashSet<Object> visitedList = new HashSet<Object>();
    StringBuilder toJsonOutput = new StringBuilder();
    toJsonOutput.append("{\n");
    this.toJsonHelper(toJsonOutput, visitedList,1,true);
    toJsonOutput.append("\n}");
    return(toJsonOutput.toString());
  }
   
  /*
  * Helper function to generate Json for this object and connected objects visited objects to enable avoidance of infinite loops
  *
  * @param toJsonOutput  Output is aded to this as the network of objects is traversed
  * @param visitedList  Every concrete object visited is added so we don't re-outpu
  * @param nestLevel    As we output deeper objects, indent them more
  * @param atConcreteClass false when we are recursing to a superclass
  *     so we get the superclass data
  * @return whether or not anything was output (so we can tell whether we need to output a comma)
  */ 
  public boolean toJsonHelper(StringBuilder toJsonOutput, HashSet<Object> visitedList, int nestLevel, boolean atConcreteClass){
      
      String indent = "  ".repeat(nestLevel);
      boolean alreadyVisited = false;
      boolean haveOutputItem = false;
      
    if(atConcreteClass) {
      // This will not be true in a super call; output header
      toJsonOutput.append(indent+"\""+this.toString().split("@")[0]+ "\" : {\n"+indent+ "  \"umpleObjectID\" : \""+System.identityHashCode(this)+"\"");
      // Check if we have already visited this object. If so we will not output details
      alreadyVisited = visitedList.contains(this);
      if(!alreadyVisited) {
        toJsonOutput.append(",\n");
        visitedList.add(this);
      }
    }
    
    // There is no superclass of this class
    if(alreadyVisited) {
      toJsonOutput.append("\n");
    }
    else {
      // Check if this class has a superclass. If it does, we make a call to output superclass content 
      // This will keep calling super so the topmost attributes and associations appear first
      // When an object has not already been visited, output its details
      if(haveOutputItem){
      //toJsonOutput.append(",\n");  
      }
        
          if(haveOutputItem){
            toJsonOutput.append(",\n");
          }
          toJsonOutput.append(indent);
          toJsonOutput.append("  \"");
          toJsonOutput.append("id");
          toJsonOutput.append("\" : \"");
          String primValue_0=""+getId()+"";
          toJsonOutput.append(primValue_0.replace("\\","\\\\").replace("\"","\\\""));
          toJsonOutput.append("\"");
          haveOutputItem=true;
          if(haveOutputItem){
            toJsonOutput.append(",\n");
          }
          toJsonOutput.append(indent);
          toJsonOutput.append("  \"");
          toJsonOutput.append("name");
          toJsonOutput.append("\" : \"");
          String primValue_1=""+getName()+"";
          toJsonOutput.append(primValue_1.replace("\\","\\\\").replace("\"","\\\""));
          toJsonOutput.append("\"");
          haveOutputItem=true;
      //haveOutputItem = false;
      //haveOutputItem = false;
              
          toJsonOutput.append(indent+"  \n");
    }
    // Finalize the output of the concrete class
    if(atConcreteClass) {
      if(!alreadyVisited) {
        toJsonOutput.append("\n");
      }
      toJsonOutput.append(indent+"}");
    }
    haveOutputItem = true;
    return haveOutputItem;
  }

  
      
  /*
  * Deserialize Json string to instantiate Objects from top-level class
  *
  * @param umpleObjectIDMap<String, Object> mapping parsed objectID (from Json string) with newly instantiated object's objectID
  * 
  * @param String aJsonString is the string in json format that is to be processed and turned into an object
  *
  * @return newly instantiated Object 
  */  

  public static Person fromJson(String aJsonString){
    // process the input jsonString so that it can further processed using regex
    aJsonString=aJsonString.replace("\n","").replace(" ","");   
    // a map to store the umpleObjectID present in jsonString
    Map<String, Object> umpleObjectIDMap=new HashMap<>();
    
    // instantiate a new object
Person anObject = new Person(aJsonString, umpleObjectIDMap);
    return anObject;
  }
   
  /*
  * A new constructor specifically implemented if -s genJson is specified
  * 
  * @param String aJsonString is the string in json format that is to be processed and turned into an object
  *
  * @param umpleObjectIDMap<String, Integer> mapping parsed objectID (from Json string) with newly instantiated object's objectID
  */ 
  @SuppressWarnings("unchecked")
  public Person(String aJsonString, Map<String, Object> umpleObjectIDMap){
    // Initialize a HashMap to store the parsed result
    // key is the attribute name present in the jsonString
    // value is the attribute value present in the jsonString
      boolean visitedSuperClass=false;
    
    HashMap<String,String> parsedResult = new HashMap<String,String>();
    parsedResult = fromJsonParser(aJsonString);
    if(!parsedResult.isEmpty()){
    boolean classExist;
    boolean classChildExist;
    String parsedClassName=parsedResult.get("className");
    String childName=this.getClass().getSimpleName();
    classExist="Person".equals(parsedClassName);
    classChildExist=childName.equals(parsedClassName);
    // if top-level class does not exist, throw exception
    if(!classExist&&!classChildExist){
      throw new IllegalArgumentException("Top-level class \""+parsedClassName+"\" does not exist, please check the input json string");
    }
    String umpleObjectId=parsedResult.get("umpleObjectID");
    // Check if the object has already been visited and created
    //if((umpleObjectIDMap.get(umpleObjectId)==null)||visitedSuperClass){
      try{
      
    visitedSuperClass=false;
    // map the old objectID (in jsonString) with the newly created object's hashCode in umpleObjectIDMap 
    umpleObjectIDMap.put(umpleObjectId,this);
    
    String jsonKey="";
       jsonKey="id";
       //more types should be considered here
       int valueInt = Integer.valueOf(parsedResult.get(jsonKey));
       this.id=valueInt;
       jsonKey="name";
       //more types should be considered here
        this.name=parsedResult.get(jsonKey);
    
    // below for-loop check the association class of the top level class

    
    }catch(Exception e){
    }

    //}
  }
  } 
  /*
  * A json parser to parse the input jsonString, if -s genJson is specified
  * 
  * @param String aJsonString is the string in json format that is to be processed and turned into an object
  *
  * @ return HashMap<String,String> that stores paresed result, key is the attribute(or associations) of an object, value is the attribute value or association string
  */ 
  public static HashMap<String,String> fromJsonParser(String jsonString){
    
    HashMap<String,String> parsedResultMap = new HashMap<String,String>();
    try{
      //Below (String, Pattern, Matcher) are the regex strings and their patterns and matcher used to process a jsonString
    
        // topLevelString is the regex representing the topLevel class name
        String topLevelString = "\\{\\\"[A-Z]\\w*\\\":";
        Pattern topLevelPattern = Pattern.compile(topLevelString);
        Matcher topLevelMatcher = topLevelPattern.matcher(jsonString);
        String quotes="\\\"";
        String colon="\\:";
        String colonSquareBracket="\\:\\[";
        
        if(topLevelMatcher.find()){
            //actual string that represent the topLevel className
            String topLevelStringFound=topLevelMatcher.group(0);
            String className=topLevelStringFound.split(quotes)[1];
            parsedResultMap.put("className", className);
            jsonString=jsonString.split(topLevelString,2)[1];
            
            //objIDString is the regex representing umpleObjectID that could be found in jsonString
            String objIDString = "\"umpleObjectID\"\\:\"[0-9]*\",";
            Pattern objIDPattern = Pattern.compile(objIDString);
            Matcher objIDMatcher = objIDPattern.matcher(jsonString);
            if(objIDMatcher.find()){
              String objIDFound=objIDMatcher.group(0);
              parsedResultMap.put("umpleObjectID", objIDFound.split(colon)[1].split(quotes)[1]);
              jsonString=jsonString.replaceFirst(objIDFound,"");
            }
            String timeString="\\\"\\w*\\\"\\:\\\"\\d{2}:\\d{2}\\:\\d{2}\\\"";
            Pattern timeStringPattern=Pattern.compile(timeString);
            Matcher timeStringPatternMatcher=timeStringPattern.matcher(jsonString);
            if(timeStringPatternMatcher.find()){
              String timeStringFound=timeStringPatternMatcher.group(0);
              parsedResultMap.put(timeStringFound.split(colon,2)[0].split(quotes)[1], timeStringFound.split(colon,2)[1].split(quotes)[1]);
          
            }
            // pairString is the regex for an object's attribute and attribute value, the string parsed will be in key-value formate
        String pairString = "(\\\"(?!umpleObjectID)[^\\\"]+)\\\":\\\"((?:\\\\\\\"|[^\\\"])*)";
        Pattern pairPattern=Pattern.compile(pairString);
        Matcher pairMatcher=pairPattern.matcher(jsonString);
        String associationString="(?=\\\"\\w*\\\"\\:\\[\\{)(?:(?=.*?\\[\\{(?!.*?\\1)(.*\\}\\](?!.*\\2).*))(?=.*?\\}\\](?!.*?\\2)(.*)).)+?.*?(?=\\1)[^\\[]*(?=\\2$)";
        Pattern associationPattern=Pattern.compile(associationString);
        String newObjJsonString="(?=\\,\\\"\\w*\\\"\\:\\{)(?:(?=.*?\\{\\\"(?!.*?\\1)(.*\\}(?!.*\\2).*))(?=.*?\\}(?!.*?\\2)(.*)).)+?.*?(?=\\1)[^\\{]*(?=\\2$)";
        Pattern newObjJsonPattern=Pattern.compile(newObjJsonString);
        String quoteColonQuote="\\\"\\:\\\"";
        //Keep on parsing the attribute's key-value pair, 
        //until a List (multi-associations) pattern or a newObject parttern (single association) is found
        while(pairMatcher.find()){
               String pairStringFound=pairMatcher.group(0);
              if(parsedResultMap.get(pairStringFound.split(colon)[0].split(quotes)[1])==null){
                String keyPair=pairStringFound.split(colon)[0].split(quotes)[1];
                String valuePair=pairStringFound.split(quoteColonQuote,2)[1];
                keyPair=keyPair.replace("\\\\","\\").replace("\\\"","\"");
                valuePair=valuePair.replace("\\\\","\\").replace("\\\"","\"");
                parsedResultMap.put(keyPair,valuePair);
                jsonString=jsonString.replaceFirst(pairString, "");
              }
                int lastIndex = 0;
                while (lastIndex<jsonString.length()){
                  String remainingJson=jsonString.substring(lastIndex);
                  Matcher associationMatcher=associationPattern.matcher(jsonString);
                  Matcher newObjJsonMatcher=newObjJsonPattern.matcher(jsonString);
                  
                  boolean assoFound=associationMatcher.find();
                  boolean newObjFound=newObjJsonMatcher.find();
                  
                  if (assoFound&&(!newObjFound||associationMatcher.start()<newObjJsonMatcher.start())){
                    String assoStringFound=associationMatcher.group(0);
                    String associationName=assoStringFound.split(colon,2)[0].split(quotes)[1];;
                    String associationItems=assoStringFound.split(colonSquareBracket,2)[1];
                    parsedResultMap.put(associationName, associationItems);
                    jsonString=jsonString.replaceFirst(associationString, "");
                  }
                  else if (newObjFound){
                    String newObjJsonFound=newObjJsonMatcher.group(0);
                    String newObjName=newObjJsonFound.split(colon,2)[0].split(quotes)[1];
                    String newObjItems=newObjJsonFound.split(colon,2)[1];
                    parsedResultMap.put(newObjName, newObjItems);
                    jsonString=jsonString.replaceFirst(newObjJsonString, "");
                  }else{
                    break;
                  }
                }
        }
        }
        return parsedResultMap;
    }catch(NullPointerException e){
      return parsedResultMap;
    }
  }
   
  public static String fromJsonParserHelper(String jsonString, String regexString){
    String umpleID = "";
    String quo="\\\"";
    try{
      Pattern umpleIDPattern=Pattern.compile(regexString);
      Matcher umpleIDMatcher=umpleIDPattern.matcher(jsonString);
      if(umpleIDMatcher.find()){
        String umpleIDStringFound=umpleIDMatcher.group(0);
        String idString="\\\"\\d*\\\"";
        Pattern idPattern=Pattern.compile(idString);
        Matcher idMatcher=idPattern.matcher(umpleIDStringFound);
        if(idMatcher.find()){
          umpleID=idMatcher.group(0).split(quo)[1];
        }
      }
      return umpleID;
    } catch(NullPointerException e){
      return umpleID;
    }
  }
   
  public static List<String> fromJsonParserList(String objListString){
    List<String> objList=new ArrayList<String>();
    try{
      String objString="(?:(?=.*?\\{(?!.*?\\1)(.*\\}(?!.*\\2).*))(?=.*?\\}(?!.*?\\2)(.*)).)+?.*?(?=\\1)[^\\{]*(?=\\2$)";
      Pattern objStringPattern=Pattern.compile(objString);
      Matcher objStringMatcher=objStringPattern.matcher(objListString);
      while(objStringMatcher.find()){
        objList.add(objStringMatcher.group(0));
      }
      return objList;
   }catch(NullPointerException e){
     return objList;
   }
  }
   
  public static String fromJsonParserClassName(String objNameString){
    String nextName="";
    String quotes="\\\"";
    try{
      String nextNameString="\\{\\\"[A-Z]\\w*\\\":";
      Pattern nextNamePattern=Pattern.compile(nextNameString);
      Matcher nextNameMatcher=nextNamePattern.matcher(objNameString);
      if(nextNameMatcher.find()){
        nextName=nextNameMatcher.group(0).split(quotes)[1];
       
      }
      return nextName;
   }catch(NullPointerException e){
     return nextName;
   }
  }
  
}
/*PLEASE DO NOT EDIT THIS CODE*/
/*This code was generated using the UMPLE 1.34.0.7242.6b8819789 modeling language!*/

package example;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.sql.*;
import java.lang.reflect.Constructor;

// line 21 "../ToJsonComplexTest.ump"
public class PartTimeStudent extends Student
{

  //------------------------
  // MEMBER VARIABLES
  //------------------------

  //PartTimeStudent Attributes
  private boolean isExemptFromFees;

  //------------------------
  // CONSTRUCTOR
  //------------------------

  public PartTimeStudent(int aId, String aName, float aTuitionPaid, University aUniversity, boolean aIsExemptFromFees)
  {
    super(aId, aName, aTuitionPaid, aUniversity);
    isExemptFromFees = aIsExemptFromFees;
  }

  //------------------------
  // INTERFACE
  //------------------------

  public boolean setIsExemptFromFees(boolean aIsExemptFromFees)
  {
    boolean wasSet = false;
    isExemptFromFees = aIsExemptFromFees;
    wasSet = true;
    return wasSet;
  }

  public boolean getIsExemptFromFees()
  {
    return isExemptFromFees;
  }
  /* Code from template attribute_IsBoolean */
  public boolean isIsExemptFromFees()
  {
    return isExemptFromFees;
  }

  public void delete()
  {
    super.delete();
  }


  public String toString()
  {
    return super.toString() + "["+
            "isExemptFromFees" + ":" + getIsExemptFromFees()+ "]";
  }
       
  /*
  * Generate Json for this object and connected objects visited objects to enable avoidance of infinite loops
  *
  * @return a string in Json  format of this object
  */ 
  public String toJson()
  {
    HashSet<Object> visitedList = new HashSet<Object>();
    StringBuilder toJsonOutput = new StringBuilder();
    toJsonOutput.append("{\n");
    this.toJsonHelper(toJsonOutput, visitedList,1,true);
    toJsonOutput.append("\n}");
    return(toJsonOutput.toString());
  }
   
  /*
  * Helper function to generate Json for this object and connected objects visited objects to enable avoidance of infinite loops
  *
  * @param toJsonOutput  Output is aded to this as the network of objects is traversed
  * @param visitedList  Every concrete object visited is added so we don't re-outpu
  * @param nestLevel    As we output deeper objects, indent them more
  * @param atConcreteClass false when we are recursing to a superclass
  *     so we get the superclass data
  * @return whether or not anything was output (so we can tell whether we need to output a comma)
  */ 
  public boolean toJsonHelper(StringBuilder toJsonOutput, HashSet<Object> visitedList, int nestLevel, boolean atConcreteClass){
      
      String indent = "  ".repeat(nestLevel);
      boolean alreadyVisited = false;
      boolean haveOutputItem = false;
      
    if(atConcreteClass) {
      // This will not be true in a super call; output header
      toJsonOutput.append(indent+"\""+this.toString().split("@")[0]+ "\" : {\n"+indent+ "  \"umpleObjectID\" : \""+System.identityHashCode(this)+"\"");
      // Check if we have already visited this object. If so we will not output details
      alreadyVisited = visitedList.contains(this);
      if(!alreadyVisited) {
        toJsonOutput.append(",\n");
        visitedList.add(this);
      }
    }
    
    // There is no superclass of this class
    if(alreadyVisited) {
      toJsonOutput.append("\n");
    }
    else {
      // Check if this class has a superclass. If it does, we make a call to output superclass content 
      // This will keep calling super so the topmost attributes and associations appear first
        haveOutputItem = super.toJsonHelper(toJsonOutput, visitedList, nestLevel, false);
      // When an object has not already been visited, output its details
      if(haveOutputItem){
      //toJsonOutput.append(",\n");  
      }
        
          if(haveOutputItem){
            toJsonOutput.append(",\n");
          }
          toJsonOutput.append(indent);
          toJsonOutput.append("  \"");
          toJsonOutput.append("isExemptFromFees");
          toJsonOutput.append("\" : \"");
          String primValue_0=""+getIsExemptFromFees()+"";
          toJsonOutput.append(primValue_0.replace("\\","\\\\").replace("\"","\\\""));
          toJsonOutput.append("\"");
          haveOutputItem=true;
      //haveOutputItem = false;
      //haveOutputItem = false;
              
          toJsonOutput.append(indent+"  \n");
    }
    // Finalize the output of the concrete class
    if(atConcreteClass) {
      if(!alreadyVisited) {
        toJsonOutput.append("\n");
      }
      toJsonOutput.append(indent+"}");
    }
    haveOutputItem = true;
    return haveOutputItem;
  }

  
      
  /*
  * Deserialize Json string to instantiate Objects from top-level class
  *
  * @param umpleObjectIDMap<String, Object> mapping parsed objectID (from Json string) with newly instantiated object's objectID
  * 
  * @param String aJsonString is the string in json format that is to be processed and turned into an object
  *
  * @return newly instantiated Object 
  */  

  public static PartTimeStudent fromJson(String aJsonString){
    // process the input jsonString so that it can further processed using regex
    aJsonString=aJsonString.replace("\n","").replace(" ","");   
    // a map to store the umpleObjectID present in jsonString
    Map<String, Object> umpleObjectIDMap=new HashMap<>();
    
    // instantiate a new object
PartTimeStudent anObject = new PartTimeStudent(aJsonString, umpleObjectIDMap);
    return anObject;
  }
   
  /*
  * A new constructor specifically implemented if -s genJson is specified
  * 
  * @param String aJsonString is the string in json format that is to be processed and turned into an object
  *
  * @param umpleObjectIDMap<String, Integer> mapping parsed objectID (from Json string) with newly instantiated object's objectID
  */ 
  @SuppressWarnings("unchecked")
  public PartTimeStudent(String aJsonString, Map<String, Object> umpleObjectIDMap){
    // Initialize a HashMap to store the parsed result
    // key is the attribute name present in the jsonString
    // value is the attribute value present in the jsonString
      super(aJsonString,umpleObjectIDMap);
      boolean visitedSuperClass=true;
    
    HashMap<String,String> parsedResult = new HashMap<String,String>();
    parsedResult = fromJsonParser(aJsonString);
    if(!parsedResult.isEmpty()){
    boolean classExist;
    boolean classChildExist;
    String parsedClassName=parsedResult.get("className");
    String childName=this.getClass().getSimpleName();
    classExist="PartTimeStudent".equals(parsedClassName);
    classChildExist=childName.equals(parsedClassName);
    // if top-level class does not exist, throw exception
    if(!classExist&&!classChildExist){
      throw new IllegalArgumentException("Top-level class \""+parsedClassName+"\" does not exist, please check the input json string");
    }
    String umpleObjectId=parsedResult.get("umpleObjectID");
    // Check if the object has already been visited and created
    //if((umpleObjectIDMap.get(umpleObjectId)==null)||visitedSuperClass){
      try{
      
    visitedSuperClass=false;
    // map the old objectID (in jsonString) with the newly created object's hashCode in umpleObjectIDMap 
    umpleObjectIDMap.put(umpleObjectId,this);
    
    String jsonKey="";
       jsonKey="isExemptFromFees";
       //more types should be considered here
        boolean valueBool=Boolean.parseBoolean(parsedResult.get(jsonKey));
        this.isExemptFromFees=valueBool;
    
    // below for-loop check the association class of the top level class

    
    }catch(Exception e){
    }

    //}
  }
  } 
  /*
  * A json parser to parse the input jsonString, if -s genJson is specified
  * 
  * @param String aJsonString is the string in json format that is to be processed and turned into an object
  *
  * @ return HashMap<String,String> that stores paresed result, key is the attribute(or associations) of an object, value is the attribute value or association string
  */ 
  public static HashMap<String,String> fromJsonParser(String jsonString){
    
    HashMap<String,String> parsedResultMap = new HashMap<String,String>();
    try{
      //Below (String, Pattern, Matcher) are the regex strings and their patterns and matcher used to process a jsonString
    
        // topLevelString is the regex representing the topLevel class name
        String topLevelString = "\\{\\\"[A-Z]\\w*\\\":";
        Pattern topLevelPattern = Pattern.compile(topLevelString);
        Matcher topLevelMatcher = topLevelPattern.matcher(jsonString);
        String quotes="\\\"";
        String colon="\\:";
        String colonSquareBracket="\\:\\[";
        
        if(topLevelMatcher.find()){
            //actual string that represent the topLevel className
            String topLevelStringFound=topLevelMatcher.group(0);
            String className=topLevelStringFound.split(quotes)[1];
            parsedResultMap.put("className", className);
            jsonString=jsonString.split(topLevelString,2)[1];
            
            //objIDString is the regex representing umpleObjectID that could be found in jsonString
            String objIDString = "\"umpleObjectID\"\\:\"[0-9]*\",";
            Pattern objIDPattern = Pattern.compile(objIDString);
            Matcher objIDMatcher = objIDPattern.matcher(jsonString);
            if(objIDMatcher.find()){
              String objIDFound=objIDMatcher.group(0);
              parsedResultMap.put("umpleObjectID", objIDFound.split(colon)[1].split(quotes)[1]);
              jsonString=jsonString.replaceFirst(objIDFound,"");
            }
            String timeString="\\\"\\w*\\\"\\:\\\"\\d{2}:\\d{2}\\:\\d{2}\\\"";
            Pattern timeStringPattern=Pattern.compile(timeString);
            Matcher timeStringPatternMatcher=timeStringPattern.matcher(jsonString);
            if(timeStringPatternMatcher.find()){
              String timeStringFound=timeStringPatternMatcher.group(0);
              parsedResultMap.put(timeStringFound.split(colon,2)[0].split(quotes)[1], timeStringFound.split(colon,2)[1].split(quotes)[1]);
          
            }
            // pairString is the regex for an object's attribute and attribute value, the string parsed will be in key-value formate
        String pairString = "(\\\"(?!umpleObjectID)[^\\\"]+)\\\":\\\"((?:\\\\\\\"|[^\\\"])*)";
        Pattern pairPattern=Pattern.compile(pairString);
        Matcher pairMatcher=pairPattern.matcher(jsonString);
        String associationString="(?=\\\"\\w*\\\"\\:\\[\\{)(?:(?=.*?\\[\\{(?!.*?\\1)(.*\\}\\](?!.*\\2).*))(?=.*?\\}\\](?!.*?\\2)(.*)).)+?.*?(?=\\1)[^\\[]*(?=\\2$)";
        Pattern associationPattern=Pattern.compile(associationString);
        String newObjJsonString="(?=\\,\\\"\\w*\\\"\\:\\{)(?:(?=.*?\\{\\\"(?!.*?\\1)(.*\\}(?!.*\\2).*))(?=.*?\\}(?!.*?\\2)(.*)).)+?.*?(?=\\1)[^\\{]*(?=\\2$)";
        Pattern newObjJsonPattern=Pattern.compile(newObjJsonString);
        String quoteColonQuote="\\\"\\:\\\"";
        //Keep on parsing the attribute's key-value pair, 
        //until a List (multi-associations) pattern or a newObject parttern (single association) is found
        while(pairMatcher.find()){
               String pairStringFound=pairMatcher.group(0);
              if(parsedResultMap.get(pairStringFound.split(colon)[0].split(quotes)[1])==null){
                String keyPair=pairStringFound.split(colon)[0].split(quotes)[1];
                String valuePair=pairStringFound.split(quoteColonQuote,2)[1];
                keyPair=keyPair.replace("\\\\","\\").replace("\\\"","\"");
                valuePair=valuePair.replace("\\\\","\\").replace("\\\"","\"");
                parsedResultMap.put(keyPair,valuePair);
                jsonString=jsonString.replaceFirst(pairString, "");
              }
                int lastIndex = 0;
                while (lastIndex<jsonString.length()){
                  String remainingJson=jsonString.substring(lastIndex);
                  Matcher associationMatcher=associationPattern.matcher(jsonString);
                  Matcher newObjJsonMatcher=newObjJsonPattern.matcher(jsonString);
                  
                  boolean assoFound=associationMatcher.find();
                  boolean newObjFound=newObjJsonMatcher.find();
                  
                  if (assoFound&&(!newObjFound||associationMatcher.start()<newObjJsonMatcher.start())){
                    String assoStringFound=associationMatcher.group(0);
                    String associationName=assoStringFound.split(colon,2)[0].split(quotes)[1];;
                    String associationItems=assoStringFound.split(colonSquareBracket,2)[1];
                    parsedResultMap.put(associationName, associationItems);
                    jsonString=jsonString.replaceFirst(associationString, "");
                  }
                  else if (newObjFound){
                    String newObjJsonFound=newObjJsonMatcher.group(0);
                    String newObjName=newObjJsonFound.split(colon,2)[0].split(quotes)[1];
                    String newObjItems=newObjJsonFound.split(colon,2)[1];
                    parsedResultMap.put(newObjName, newObjItems);
                    jsonString=jsonString.replaceFirst(newObjJsonString, "");
                  }else{
                    break;
                  }
                }
        }
        }
        return parsedResultMap;
    }catch(NullPointerException e){
      return parsedResultMap;
    }
  }
   
  public static String fromJsonParserHelper(String jsonString, String regexString){
    String umpleID = "";
    String quo="\\\"";
    try{
      Pattern umpleIDPattern=Pattern.compile(regexString);
      Matcher umpleIDMatcher=umpleIDPattern.matcher(jsonString);
      if(umpleIDMatcher.find()){
        String umpleIDStringFound=umpleIDMatcher.group(0);
        String idString="\\\"\\d*\\\"";
        Pattern idPattern=Pattern.compile(idString);
        Matcher idMatcher=idPattern.matcher(umpleIDStringFound);
        if(idMatcher.find()){
          umpleID=idMatcher.group(0).split(quo)[1];
        }
      }
      return umpleID;
    } catch(NullPointerException e){
      return umpleID;
    }
  }
   
  public static List<String> fromJsonParserList(String objListString){
    List<String> objList=new ArrayList<String>();
    try{
      String objString="(?:(?=.*?\\{(?!.*?\\1)(.*\\}(?!.*\\2).*))(?=.*?\\}(?!.*?\\2)(.*)).)+?.*?(?=\\1)[^\\{]*(?=\\2$)";
      Pattern objStringPattern=Pattern.compile(objString);
      Matcher objStringMatcher=objStringPattern.matcher(objListString);
      while(objStringMatcher.find()){
        objList.add(objStringMatcher.group(0));
      }
      return objList;
   }catch(NullPointerException e){
     return objList;
   }
  }
   
  public static String fromJsonParserClassName(String objNameString){
    String nextName="";
    String quotes="\\\"";
    try{
      String nextNameString="\\{\\\"[A-Z]\\w*\\\":";
      Pattern nextNamePattern=Pattern.compile(nextNameString);
      Matcher nextNameMatcher=nextNamePattern.matcher(objNameString);
      if(nextNameMatcher.find()){
        nextName=nextNameMatcher.group(0).split(quotes)[1];
       
      }
      return nextName;
   }catch(NullPointerException e){
     return nextName;
   }
  }
  
}