Search code examples
javaaopaspectj

Saving to a File using a AspectJ


I'm an inexperienced developer that is learning Java. I'm working on this AddressBook, where I'm implementing AspectJ to one of my functions (Update Contact). Before updating the contact, obviously the user needs to add a Contact, and my saveContact code looks like this:

public class Contacts { //class to manage the contacts information

    public String name;
    public String street;
    public String city;
    public String state;
    public int zip;
    public long phoneNumber;
    public Scanner input;

    public void saveContact()
    {//code to add and save a contact to the book
        input = new Scanner(System.in);

        System.out.println("Plase enter contact Name and Lastname: ");
        name = input.nextLine();

        System.out.println("\nPlase enter Street of contact: ");
        street = input.nextLine();

        System.out.println("\nPlase enter City of the contact: ");
        city = input.nextLine();

        System.out.println("\nPlase enter State of the contact: ");
        state = input.nextLine();

        System.out.println("\nPlase enter the Zipcode of the contact: ");
        zip = input.nextInt();

        System.out.println("\nPlase enter the contact Phone number (Ex 1115550000): ");
        phoneNumber = input.nextLong();

        System.out.println("Done! Contact Saved");
}

I have more options like Update Contact, Find Contact and Delete Contac. before the Update Contact function executes, I want to run an Aspect that saves the values that the user entered to the variables(name, city, state, etc) in a file.txt, before assigning the new values in the Update Contact code. My issue is that when the Aspect advise executes, my .txt file comes with null instead of the values assigned by the user in the Add Contact code.

My Aspect looks like this:

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

public aspect AspectUpdateContact { //code to save the old information of the contact to the file before updating the contact

    pointcut aspectCallUpdateFile() : call (void updateContact()) && within (Menu);
    before() : aspectCallUpdateFile() 
        {
/*******Code is running and saving to the file but not bringing the values of the variables, saving null values*/
        Contacts ct = new Contacts();
        try {

        PrintWriter pwrite = new PrintWriter(new FileWriter("UpdatesLog.txt", true));//to append the write to the end of the file

        pwrite.println("Record Updated->" + ct.name +":"+ ct.street +":"+ ct.city +":"+ ct.state +":"+ ct.zip +":"+ ct.phoneNumber);

        pwrite.close();//close the Print Writer

            }
            catch (IOException e) {
                System.out.println(e.getMessage());
            }

    }// end of code for pointcut

}//end of aspect

My final output in the txt file is: Record Updated:null:null:null:null:0:0


Solution

  • I refactored your code a bit (no more plural in class name, renamed methods, private fields, toString() method, convenience constructor, try with resources in aspect) and also fixed the aspect by using target() with argument binding in the aspect:

    Contact data class:

    package de.scrum_master.app;
    
    import java.util.Scanner;
    
    public class Contact {
      private String name;
      private String street;
      private String city;
      private String state;
      private int zip;
      private long phoneNumber;
    
      private Scanner input;
    
      public Contact() {}
    
      public Contact(String name, String street, String city, String state, int zip, long phoneNumber) {
        this.name = name;
        this.street = street;
        this.city = city;
        this.state = state;
        this.zip = zip;
        this.phoneNumber = phoneNumber;
      }
    
      @Override
      public String toString() {
        return "Contact[name=" + name + ", street=" + street + ", city=" + city + ", state=" + state +
          ", zip=" + zip + ", phoneNumber=" + phoneNumber + "]";
      }
    
      public void updateContact() {
        input = new Scanner(System.in);
    
        System.out.println("Please enter contact Name and Lastname: ");
        name = input.nextLine();
        System.out.println("\nPlease enter Street of contact: ");
        street = input.nextLine();
        System.out.println("\nPlease enter City of the contact: ");
        city = input.nextLine();
        System.out.println("\nPlease enter State of the contact: ");
        state = input.nextLine();
        System.out.println("\nPlease enter the Zipcode of the contact: ");
        zip = input.nextInt();
        System.out.println("\nPlease enter the contact Phone number (Ex 1115550000): ");
        phoneNumber = input.nextLong();
    
        System.out.println("Done! Contact updated.\n");
      }
    }
    

    Dummy menu class with main method:

    package de.scrum_master.app;
    
    public class Menu {
      public void updateContact(Contact contact) {
        contact.updateContact();
      }
    
      public static void main(String[] args) {
        Menu menu = new Menu();
        Contact contact = new Contact("Albert Einstein", "101 Main St", "Middle of Nowhere", "Utah", 12345, 11223344);
        menu.updateContact(contact);
        menu.updateContact(contact);
      }
    }
    

    As you can see, I am creating an initial contact object and then update it twice in order to create two lines of log output.

    Logging aspect:

    package de.scrum_master.aspect;
    
    import java.io.FileWriter;
    import java.io.IOException;
    import java.io.PrintWriter;
    
    import de.scrum_master.app.Contact;
    import de.scrum_master.app.Menu;
    
    public aspect UpdateContactAspect {
      pointcut callUpdateContact(Contact contact) :
        call(void updateContact()) && within(Menu) && target(contact);
    
      before(Contact contact) : callUpdateContact(contact) {
        try (PrintWriter writer = new PrintWriter(new FileWriter("UpdatesLog.txt", true))) {
          writer.println("Record updated -> " + contact);
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
    

    Console log for sample run:

    Please enter contact Name and Lastname: 
    John Doe
    
    Please enter Street of contact: 
    321 Broadway
    
    Please enter City of the contact: 
    New York City
    
    Please enter State of the contact: 
    New York
    
    Please enter the Zipcode of the contact: 
    54321
    
    Please enter the contact Phone number (Ex 1115550000): 
    0123456789
    Done! Contact updated.
    
    Please enter contact Name and Lastname: 
    Donald Duck
    
    Please enter Street of contact: 
    33 Wherever
    
    Please enter City of the contact: 
    Quacktown
    
    Please enter State of the contact: 
    Duckstate
    
    Please enter the Zipcode of the contact: 
    88099
    
    Please enter the contact Phone number (Ex 1115550000): 
    999333111
    Done! Contact updated.
    

    Log file content after sample run:

    Record updated -> Contact[name=Albert Einstein, street=101 Main St, city=Middle of Nowhere, state=Utah, zip=12345, phoneNumber=11223344]
    Record updated -> Contact[name=John Doe, street=321 Broadway, city=New York City, state=New York, zip=54321, phoneNumber=123456789]
    

    There are more things which need refactoring, but I am stopping here.