PBCST 304 Object Oriented Programming Model Question Paper and Answers

 



1.You compile MyApp.java on Windows into MyApp.class, then copy that same MyApp.class file to both a Linux machine and a macOS system. Without recompiling, you run:
java MyApp
on each machine, and it executes successfully. What is the name of the compiled file format that makes this possible?

When you compile a Java source file (MyApp.java) using the Java compiler (javac), it does not produce machine code specific to Windows, Linux, or macOS.
Instead, it produces platform-independent bytecode, which is stored in the file:

MyApp.class

This file contains instructions for the Java Virtual Machine (JVM), not for any specific hardware or operating system

 Why it runs everywhere

Each platform (Windows, Linux, macOS) has its own JVM implementation.
When you run:

java MyApp

The JVM on that platform reads and executes the same bytecode instructions — making Java platform-independent.


2.What will be the value of a after the execution of the following code segment in Java.

int a = -1;

a = a >> 4;


🧠 Step 1: Represent a = -1 in binary (32-bit signed integer)

In Java, int is 32 bits, and negative numbers are represented in two’s complement form.

-1 in binary (32 bits) is:

11111111 11111111 11111111 11111111

🧠 Step 2: Right shift by 4 bits → a >> 4

The operator >> is the arithmetic right shift operator.

It preserves the sign bit (the leftmost bit).

Since a is negative (sign bit = 1), the leftmost bits filled during the shift are all 1s.

So, shifting right by 4 bits:

11111111 11111111 11111111 11111111  (original)

>> 4

11111111 11111111 11111111 11111111  (after shifting)

Essentially, it stays the same — still all 1s.

🧮 Step 3: Result in decimal

11111111 11111111 11111111 11111111 = -1

✅ Final Answer:

a = -1;


3.You’re given this Java code:

class Vehicle {
protected String type = "Generic Vehicle";
Vehicle() {
System.out.println("Vehicle created");
}
}

class Car extends Vehicle {
protected String type = "Car";
Car() {

// **INSERT STATEMENT A HERE**
System.out.println("Type: " + type);
}

void printParentType() {
System.out.println("Parent Type: " +super.type);
}
}

public class TestSuper {
public static void main(String[] args) {
Car c = new Car();
c.printParentType();
}
}

a. What exact statement must replace // **INSERT STATEMENT A HERE** so that when you run TestSuper, you see:

Vehicle created
Type: Car
Parent Type: Generic Vehicle

b. In one sentence each, explain:

(i) What the statement you inserted does here.
(ii) Why super.type prints "Generic Vehicle" while type prints "Car".

The correct statement to insert

super();

✅ Full corrected Car constructor

Car() { super(); // Statement A System.out.println("Type: " + type); }

What happens when executed

Output:

Vehicle created Type: Car Parent Type: Generic Vehicle

🅱️ Explanations

(i) What super(); does here

👉 It calls the constructor of the parent class (Vehicle) before executing the body of the Car constructor, ensuring that the parent class is properly initialized first.


(ii) Why super.type prints "Generic Vehicle" while type prints "Car"

👉 Because each class has its own type field, and super.type explicitly refers to the parent class variable in Vehicle, while type (without super) refers to the child class variable in Car.


Final Answers:

PartAnswer
(a)                                    super();
(b)(i)It calls the parent class constructor before executing the subclass constructor.
(b)(ii)super.type accesses the parent’s variable, while type accesses the child’s variable.

4.Illustrate inheritance in Java.

Inheritance in Java is a mechanism where one class (called the subclass or child class) acquires the properties and behaviors (fields and methods) of another class (called the superclass or parent class).
It promotes code reusability and method overriding.

Example:

class Vehicle { void start() { System.out.println("Vehicle starts"); } } class Car extends Vehicle { void drive() { System.out.println("Car drives"); } } public class Test { public static void main(String[] args) { Car c = new Car(); c.start(); // inherited from Vehicle c.drive(); // defined in Car } }


Output:
Vehicle starts Car drives

5.Using proper examples, give the difference between interfaces and abstract classes in Java.

🧩 1. Definition

FeatureAbstract ClassInterface
Purpose                       Used when classes share a common base with                            some   shared implementation.Used to define a contract that classes must follow.
Keyword            abstractinterface

🧠 2. Example of Abstract Class

abstract class Animal { abstract void sound(); // abstract method void eat() { // concrete method System.out.println("This animal eats food."); } } class Dog extends Animal { void sound() { System.out.println("Dog barks"); } } public class TestAbstract { public static void main(String[] args) { Dog d = new Dog(); d.sound(); d.eat(); } }

Output:

Dog barks This animal eats food.

Key Point: Abstract classes can have both abstract and concrete methods.


⚙️ 3. Example of Interface

interface Vehicle { void start(); // abstract method (implicitly public and abstract) } class Car implements Vehicle { public void start() { System.out.println("Car starts with a key"); } } public class TestInterface { public static void main(String[] args) { Car c = new Car(); c.start(); } }

Output:

Car starts with a key

Key Point: Interfaces contain only abstract methods (till Java 7), but from Java 8 onward, they can include default and static methods.


📘 4. Summary Table

FeatureAbstract ClassInterface
MethodsCan have abstract and concrete methodsCan have only abstract (and default/static) methods
VariablesCan have instance variablesVariables are implicitly public static final (constants)
InheritanceClass can extend only one abstract classClass can implement multiple interfaces
ConstructorCan have constructorsCannot have constructors
Use CaseWhen classes share common behaviorWhen classes share common capabilities

💡 In Short:

  • Use abstract class when you want to share code among related classes.

  • Use interface when you want to define a common contract for unrelated classes.


6.You’re given this Java class:
1 import java.io.*;
2 public class ExceptionDemo {
3     public static int divide(int a, int b) {
4     return a / b;
5         }
6     public static void readFile(String path) throws    IOException {
7     FileInputStream fis = new FileInputStream(path);
8     fis.close();
9     }
10 public static void main(String[] args) {
11        String filePath = args[0];
12     int x = Integer.parseInt(args[1]);
13     int y = Integer.parseInt(args[2]);
14     try {
15     readFile(filePath);
16     System.out.println("Result: " + divide(x,y));
17     } catch (Exception e) {
18     e.printStackTrace();
19     }
20     }
21     }
(i) At which lines in this code might a checked exception be thrown?
(ii) At which lines might an unchecked exception occur?
(iii) For each case, name the exception class and explain briefly why it’s checked or unchecked.

Line(s)Exception ClassTypeReason
7FileNotFoundExceptionChecked    File may not exist; compiler forces handling
8IOExceptionChecked    Closing file may fail; compiler forces handling
4ArithmeticExceptionUnchecked    Division by zero occurs at runtime
11ArrayIndexOutOfBoundsExceptionUnchecked    Missing command-line argument at runtime
12-13NumberFormatExceptionUnchecked    Invalid integer parsing; runtime error

FeatureChecked ExceptionUnchecked Exception
DefinitionExceptions checked by the compiler at compile-time.Exceptions not checked by the compiler; occur at runtime.
HandlingMust be handled using try-catch or declared using throws.Handling is optional; compiler does not force it.
InheritanceSubclass of Exception (but not RuntimeException).Subclass of RuntimeException.
ExamplesIOException, FileNotFoundException, SQLExceptionArithmeticException, NullPointerException, ArrayIndexOutOfBoundsException
When occursOften due to external factors beyond the program’s control (e.g., file I/O, network).Often due to programming errors (e.g., division by zero, invalid array access).
Compile-time vs RuntimeDetected at compile-time.Detected at runtime.

Key Points

  1. Checked exceptions → Force you to write robust code for recoverable conditions.

  2. Unchecked exceptions → Usually indicate bugs in the code that should be fixed.


Quick Memory Tip:

Checked → Compiler checks;
Unchecked → Unnoticed by compiler.


 7.Give the differences between AWT and Swing in Java.

AWT: Heavyweight, platform-dependent GUI toolkit with basic components.

Swing: Lightweight, platform-independent GUI toolkit with rich, customizable components.

Here’s a concise table comparing AWT and Swing in Java:


FeatureAWT (Abstract Window Toolkit)Swing
LibraryPart of java.awt packagePart of javax.swing package
ComponentsHeavyweight (depends on native OS GUI)Lightweight (pure Java components)
Look and FeelDepends on OSConsistent across platforms; supports pluggable look and feel
FlexibilityLess flexibleMore flexible and customizable
PerformanceFaster for simple appsSlightly slower due to additional features        
Components ExamplesButton, Label, TextFieldJButton, JLabel, JTextField
Event HandlingUses older event delegationUses newer event delegation model
Use CaseSimple GUI applicationsRich and complex GUI applications

8.List the main steps to establish a JDBC connection.What is a PreparedStatement, and why is it preferred over a Statement?

Main Steps to Establish a JDBC Connection

  1. Load the JDBC Driver

Class.forName("com.mysql.cj.jdbc.Driver");
  1. Establish a Connection

Connection con = DriverManager.getConnection(url, username, password);
  1. Create a Statement or PreparedStatement

Statement stmt = con.createStatement();
PreparedStatement pstmt = con.prepareStatement(sql);
  1. Execute SQL Queries

ResultSet rs = stmt.executeQuery("SELECT * FROM table");
  1. Process the ResultSet

while(rs.next()) { System.out.println(rs.getString("column_name")); }
  1. Close Resources

rs.close(); stmt.close(); con.close();

2️⃣ PreparedStatement vs Statement

FeatureStatementPreparedStatement
DefinitionUsed to execute static SQL queriesUsed to execute parameterized SQL queries
SQL InjectionVulnerable to SQL injectionPrevents SQL injection
PerformanceCompiles query every timePrecompiled once; faster for repeated queries
Parameter BindingNot supportedSupports dynamic parameter binding using ?
Examplestmt.executeUpdate("INSERT INTO student VALUES(1,'John')");pstmt.setInt(1,1); pstmt.setString(2,"John"); pstmt.executeUpdate();

Key Points

  • Use PreparedStatement for security, efficiency, and reusability.

  • Use Statement only for simple, one-time SQL queries


9a.Write a Java program that uses command line arguments to calculate area:
 If the user enters one argument, the program should treat it as the side of a square and print the area of the square.
 If the user enters two arguments, the program should treat them as the length and breadth of a rectangle and print the area of the rectangle.
 If the number of arguments is not 1 or 2, display an appropriate error message.

public class AreaCalculator {
    public static void main(String[] args) {
        // Check number of arguments
        if (args.length == 1) {
            // Single argument → Square
            try {
                double side = Double.parseDouble(args[0]);
                double area = side * side;
                System.out.println("Area of Square: " + area);
            } catch (NumberFormatException e) {
                System.out.println("Invalid input! Please enter a numeric value.");
            }

        } else if (args.length == 2) {
            // Two arguments → Rectangle
            try {
                double length = Double.parseDouble(args[0]);
                double breadth = Double.parseDouble(args[1]);
                double area = length * breadth;
                System.out.println("Area of Rectangle: " + area);
            } catch (NumberFormatException e) {
                System.out.println("Invalid input! Please enter numeric values.");
            }

        } else {
            // Invalid number of arguments
            System.out.println("Error: Enter either 1 argument (square) or 2 arguments (rectangle).");
        }
    }
}

9b. Illustrate the use of this keyword in Java.

this in Java?

  • this is a reference variable in Java that refers to the current object of a class.

  • It is commonly used to:

    1. Refer to instance variables when local variables shadow them.

    2. Invoke the current class constructor (constructor chaining).

    3. Pass the current object as a parameter to methods or constructors.


2️⃣ Examples

(a) Using this to refer to instance variables

class Student { String name; int age; Student(String name, int age) { this.name = name; // 'this.name' refers to instance variable this.age = age; } void display() { System.out.println("Name: " + this.name + ", Age: " + this.age); } } public class TestThis { public static void main(String[] args) { Student s = new Student("Alice", 20); s.display(); } }

Output:

Name: Alice, Age: 20

Explanation: this.name differentiates the instance variable name from the constructor parameter name.


(b) Using this() to call another constructor

class Student { String name; int age; Student() { this("Unknown", 18); // calls parameterized constructor } Student(String name, int age) { this.name = name; this.age = age; } void display() { System.out.println("Name: " + name + ", Age: " + age); } } public class TestThisConstructor { public static void main(String[] args) { Student s = new Student(); // calls default constructor s.display(); } }

Output:

Name: Unknown, Age: 18

Explanation: this() is used to reuse another constructor in the same class.


(c) Using this to pass current object

class Printer { void print(Student s) { System.out.println("Student name: " + s.name); } } class Student { String name; Student(String name) { this.name = name; } void show(Printer p) { p.print(this); // passes current object } } public class TestThisObject { public static void main(String[] args) { Student s = new Student("Bob"); Printer p = new Printer(); s.show(p); } }

Output:

Student name: Bob

Explanation: this is used to pass the current object to another method or class.


3️⃣ Key Points

  1. this always refers to the current object.

  2. Helps resolve name conflicts between instance variables and parameters.

  3. Can be used for constructor chaining (this()).

  4. Can be used to pass the current object as an argument.


10a.Design a Java class Book with the following attributes: title, author, and price.
 Write a parameterized constructor to initialize these values.
 Also write a default constructor that sets default values.
 Create a display() method to print the book details.
 In the main method, create two objects — one using the default constructor and another using the parameterized constructor — and display their details.

// Book.java
class Book {
    // Attributes
    String title;
    String author;
    double price;

    // Default constructor
    Book() {
        this.title = "Unknown Title";
        this.author = "Unknown Author";
        this.price = 0.0;
    }

    // Parameterized constructor
    Book(String title, String author, double price) {
        this.title = title;
        this.author = author;
        this.price = price;
    }

    // Method to display book details
    void display() {
        System.out.println("Title: " + title);
        System.out.println("Author: " + author);
        System.out.println("Price: $" + price);
        System.out.println("-----------------------");
    }

    // Main method
    public static void main(String[] args) {
        // Object using default constructor
        Book defaultBook = new Book();
        System.out.println("Default Book Details:");
        defaultBook.display();

        // Object using parameterized constructor
        Book paramBook = new Book("Java Programming", "John Doe", 499.99);
        System.out.println("Parameterized Book Details:");
        paramBook.display();
    }
}
Sample Output:
yaml
Copy code
Default Book Details:
Title: Unknown Title
Author: Unknown Author
Price: $0.0
-----------------------
Parameterized Book Details:
Title: Java Programming
Author: John Doe
Price: $499.99
-----------------------

10b.Refactor the Book class so that (i) data validation and (ii) input/output each live in their own classes. Which SOLID principle are you applying, and why?

1️⃣ Principle Applied

SOLID Principle: Single Responsibility Principle (SRP)

A class should have only one reason to change.

Why:

  • The original Book class handled data storage, validation, and display all in one class.

  • Refactoring separates concerns:

    1. Book → stores book data only.

    2. BookValidator → validates book data.

    3. BookPrinter → handles display/output.


2️⃣ Refactored Code

Book.java (Data class only)

class Book { String title; String author; double price; // Default constructor Book() { this.title = "Unknown Title"; this.author = "Unknown Author"; this.price = 0.0; } // Parameterized constructor Book(String title, String author, double price) { this.title = title; this.author = author; this.price = price; } }

BookValidator.java (Validation responsibility)

class BookValidator { // Validate book data public static boolean validate(Book book) { if (book.title == null || book.title.isEmpty()) { System.out.println("Invalid title"); return false; } if (book.author == null || book.author.isEmpty()) { System.out.println("Invalid author"); return false; } if (book.price < 0) { System.out.println("Price cannot be negative"); return false; } return true; } }

BookPrinter.java (Display/Output responsibility)

class BookPrinter { // Display book details public static void display(Book book) { System.out.println("Title: " + book.title); System.out.println("Author: " + book.author); System.out.println("Price: $" + book.price); System.out.println("-----------------------"); } }

TestBook.java (Main method)

public class TestBook { public static void main(String[] args) { Book defaultBook = new Book(); Book paramBook = new Book("Java Programming", "John Doe", 499.99); // Validate before displaying if (BookValidator.validate(defaultBook)) { System.out.println("Default Book Details:"); BookPrinter.display(defaultBook); } if (BookValidator.validate(paramBook)) { System.out.println("Parameterized Book Details:"); BookPrinter.display(paramBook); } } }

3️⃣ Benefits

  1. Single Responsibility: Each class has one reason to change.

  2. Maintainable: Validation rules or display formats can change independently.

  3. Reusable: BookPrinter and BookValidator can be reused in other projects.

11a.Create a Java class Calculator that demonstrates method overloading by implementing the add() method in the following ways:
 add(int a, int b) — returns the sum of two integers.
 add(double a, double b) — returns the sum of two double values.
 add(int a, int b, int c) — returns the sum of three integers.
In the main method, create an object of Calculator and call all the overloaded add() methods with appropriate arguments. Display the results.

// Calculator.java
class Calculator {

    // Method 1: Sum of two integers
    int add(int a, int b) {
        return a + b;
    }

    // Method 2: Sum of two double values
    double add(double a, double b) {
        return a + b;
    }

    // Method 3: Sum of three integers
    int add(int a, int b, int c) {
        return a + b + c;
    }

    public static void main(String[] args) {
        // Create an object of Calculator
        Calculator calc = new Calculator();

        // Call overloaded methods
        int sum1 = calc.add(5, 10);              // two integers
        double sum2 = calc.add(3.5, 4.7);        // two doubles
        int sum3 = calc.add(2, 4, 6);            // three integers

        // Display results
        System.out.println("Sum of 2 integers: " + sum1);
        System.out.println("Sum of 2 doubles: " + sum2);
        System.out.println("Sum of 3 integers: " + sum3);
    }
}
Sample Output:

Sum of 2 integers: 15
Sum of 2 doubles: 8.2
Sum of 3 integers: 12
✅ Key Points About Method Overloading
  • Same method name but different parameter lists (number or type of parameters).
  • Return type can be different but is not sufficient alone to overload a method.
  • Compile-time polymorphism is achieved using method overloading.
11b.Create a Java class Counter that has a static variable count to keep track of the number of objects created. Increment count in the constructor. In the main method, create three objects of the Counter class and display the total number of objects created using the static variable.

// Counter.java
class Counter {
    // Static variable to keep track of object count
    static int count = 0;

    // Constructor
    Counter() {
        count++;  // Increment count whenever a new object is created
    }

    public static void main(String[] args) {
        // Create three objects
        Counter c1 = new Counter();
        Counter c2 = new Counter();
        Counter c3 = new Counter();

        // Display the total number of objects created
        System.out.println("Total objects created: " + Counter.count);
    }
}
Sample Output:
Total objects created: 3

Key Points

  • Static variable (count) is shared by all objects of the class.
  • Incrementing count in the constructor ensures every new object is counted.
  • Can access the static variable using ClassName.variableName (Counter.count).
12.Define a Java base class Animal with a method makeSound() that prints a generic sound. Then, create two subclasses Dog and Cat that override the makeSound() method to print "Bark" and "Meow" respectively. In the main method, create objects of Dog and Cat and call the makeSound() method to show runtime polymorphism.

// AnimalDemo.java

// Base class
class Animal {
    // Method to be overridden
    void makeSound() {
        System.out.println("Some generic sound");
    }
}

// Subclass Dog
class Dog extends Animal {
    @Override
    void makeSound() {
        System.out.println("Bark");
    }
}

// Subclass Cat
class Cat extends Animal {
    @Override
    void makeSound() {
        System.out.println("Meow");
    }
}

// Main class
public class AnimalDemo {
    public static void main(String[] args) {
        // Runtime polymorphism
        Animal a1 = new Dog(); // Reference of type Animal, object of Dog
        Animal a2 = new Cat(); // Reference of type Animal, object of Cat

        a1.makeSound();  // Calls Dog's makeSound()
        a2.makeSound();  // Calls Cat's makeSound()
    }
}
Sample Output:
Bark
Meow

Key Points

  • Method overriding occurs when a subclass provides a specific implementation of a method defined in the parent class.
  • Runtime polymorphism: The method that gets executed is determined at runtime based on the actual object, not the reference type.
  • The @Override annotation is optional but recommended for clarity and compile-time checking.

13,You have a third-party class AnalyticsService with method sendEvent(String). Write an Adapter so that it conforms to your Logger interface (log(String)). Show both class definitions and the adapter code.

1️⃣ Logger Interface

// Logger.java public interface Logger { void log(String message); }

2️⃣ Third-Party AnalyticsService

// AnalyticsService.java public class AnalyticsService { public void sendEvent(String event) { System.out.println("Analytics event sent: " + event); } }

3️⃣ Adapter Class

// AnalyticsLoggerAdapter.java public class AnalyticsLoggerAdapter implements Logger { private AnalyticsService analyticsService; // Constructor public AnalyticsLoggerAdapter(AnalyticsService analyticsService) { this.analyticsService = analyticsService; } // Implement Logger interface @Override public void log(String message) { // Adapt the log() call to sendEvent() analyticsService.sendEvent(message); } }

4️⃣ Demo / Main Class

// AdapterDemo.java public class AdapterDemo { public static void main(String[] args) { // Third-party service AnalyticsService analytics = new AnalyticsService(); // Adapter wraps the third-party service Logger logger = new AnalyticsLoggerAdapter(analytics); // Use Logger interface logger.log("User clicked the button"); logger.log("User logged in"); } }

Sample Output:

Analytics event sent: User clicked the button Analytics event sent: User logged in

✅ Key Points

  1. Adapter Design Pattern: Converts one interface (AnalyticsService) to another (Logger) that the client expects.

  2. AnalyticsLoggerAdapter implements the target interface (Logger) and internally uses the adaptee (AnalyticsService).

  3. This allows your code to work with the third-party class without modifying it.

14.Implement the Singleton pattern for a Logger class that writes log entries to a file. Show your code and explain how it ensures a single instance.

1️⃣ Logger Singleton Class

import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; public class Logger { // 1. Private static instance of the same class private static Logger instance; // 2. Private constructor to prevent external instantiation private Logger() { // Initialize resources if needed } // 3. Public method to provide access to the single instance public static Logger getInstance() { if (instance == null) { instance = new Logger(); // Create instance if it doesn't exist } return instance; } // Method to write log messages to a file public void log(String message) { try (FileWriter fw = new FileWriter("log.txt", true); PrintWriter pw = new PrintWriter(fw)) { pw.println(message); } catch (IOException e) { e.printStackTrace(); } } }

2️⃣ Main Class to Test Logger

public class SingletonDemo { public static void main(String[] args) { // Get the single Logger instance Logger logger1 = Logger.getInstance(); Logger logger2 = Logger.getInstance(); // Test logging logger1.log("Application started"); logger2.log("User clicked a button"); // Verify both references point to the same instance if (logger1 == logger2) { System.out.println("Both references are the same instance!"); } } }

Explanation of Singleton Mechanism

  1. Private static variable:
    private static Logger instance; ensures only one instance can exist.

  2. Private constructor:
    private Logger() prevents creating instances from outside the class.

  3. Public static method:
    getInstance() provides controlled access to the single instance.

    • If the instance doesn’t exist, it is created.

    • If it already exists, the same instance is returned.

  4. Ensures single instance:

    • logger1 and logger2 point to the same object, guaranteeing only one logger writes to the file.


Sample Output:

Both references are the same instance! 

log.txt content:
Application started 
User clicked a button

15. Design a simple Java Swing GUI application with the following features:
 A window with two buttons labeled “Greet” and “Clear”.
 A text field where the user can enter their name.
 When the “Greet” button is clicked, display “Hello, [Name]!” in a label.
 When the “Clear” button is clicked, clear the text field and the label.
Use appropriate event handling by implementing ActionListener and demonstrate how to register and handle events in Java Swing.
In your Swing GUI, the user enters a name and clicks ‘Save’. Write the JDBC code to insert that name into table greetings(name VARCHAR),handling exceptions appropriately.
Write the complete code for this application.

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.sql.*;

public class GreetingApp extends JFrame implements ActionListener {

    // Swing components
    private JTextField nameField;
    private JLabel messageLabel;
    private JButton greetButton, clearButton, saveButton;

    // JDBC variables
    private Connection con;
    private PreparedStatement pstmt;

    public GreetingApp() {
        // Window title
        setTitle("Greeting Application");
        setSize(400, 200);
        setLayout(new FlowLayout());
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // Components
        JLabel nameLabel = new JLabel("Enter your name:");
        nameField = new JTextField(20);
        messageLabel = new JLabel("");

        greetButton = new JButton("Greet");
        clearButton = new JButton("Clear");
        saveButton = new JButton("Save");

        // Add components to frame
        add(nameLabel);
        add(nameField);
        add(greetButton);
        add(clearButton);
        add(saveButton);
        add(messageLabel);

        // Register event listeners
        greetButton.addActionListener(this);
        clearButton.addActionListener(this);
        saveButton.addActionListener(this);

        // Initialize JDBC connection
        try {
            // Load MySQL JDBC Driver
            Class.forName("com.mysql.cj.jdbc.Driver");
            // Connect to database (adjust URL, username, password)
            con = DriverManager.getConnection("jdbc:mysql://localhost:3306/testdb", "root", "password");
            pstmt = con.prepareStatement("INSERT INTO greetings(name) VALUES(?)");
        } catch (ClassNotFoundException | SQLException e) {
            JOptionPane.showMessageDialog(this, "Database connection error: " + e.getMessage());
            e.printStackTrace();
        }

        setVisible(true);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        String name = nameField.getText().trim();

        if (e.getSource() == greetButton) {
            if (!name.isEmpty()) {
                messageLabel.setText("Hello, " + name + "!");
            } else {
                messageLabel.setText("Please enter your name.");
            }

        } else if (e.getSource() == clearButton) {
            nameField.setText("");
            messageLabel.setText("");

        } else if (e.getSource() == saveButton) {
            if (!name.isEmpty()) {
                try {
                    pstmt.setString(1, name);
                    int rows = pstmt.executeUpdate();
                    if (rows > 0) {
                        JOptionPane.showMessageDialog(this, "Name saved successfully!");
                    }
                } catch (SQLException ex) {
                    JOptionPane.showMessageDialog(this, "Error saving to database: " + ex.getMessage());
                    ex.printStackTrace();
                }
            } else {
                JOptionPane.showMessageDialog(this, "Please enter a name before saving.");
            }
        }
    }

    // Close JDBC resources when closing the application
    @Override
    public void dispose() {
        super.dispose();
        try {
            if (pstmt != null) pstmt.close();
            if (con != null) con.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new GreetingApp());
    }
}

Features Implemented

  1. Swing GUI

    • Text field for entering name.

    • Buttons: Greet, Clear, Save.

    • Label to display greeting messages.

  2. Event Handling

    • Implements ActionListener.

    • Uses addActionListener() to register buttons.

    • Handles click events inside actionPerformed().

  3. JDBC Integration

    • Connects to MySQL database (testdb).

    • Uses PreparedStatement to safely insert name into greetings table.

    • Handles exceptions using try-catch and displays messages via JOptionPane.


16a.Draw an MVC diagram for this Swing+JDBC app.

                      ┌───────────────┐
                      │    View                              
                      │ (GreetingApp)                   
                      │---------------                      
                      │ - JTextField                      
                      │ - JLabel                            
                      │ - JButton                            
                      └───────┬───────┘
                              │
                              │ User input / Button click
                              ▼
                      ┌───────────────┐
                      │   Controller                       
                      │ actionPerformed               
                      │---------------                       
                      │ Handles events                  
                      │ Validates input                  
                      │ Calls Model                      
                      └───────┬───────┘
                              │
                              │ Calls methods
                              ▼
                      ┌───────────────┐
                      │    Model                               
                      │   Database                         
                      │---------------                       
                      │ JDBC Connection             
                      │ PreparedStatement            
                      │ Inserts data                        
                      │ Retrieves data                   
                      └───────────────┘

Explanation

  1. View (GreetingApp)

    • Swing components: text field, label, buttons.

    • Displays messages and gets user input.

  2. Controller (actionPerformed)

    • Handles button clicks.

    • Validates input.

    • Calls the Model to save data or update the View.

  3. Model (Database / JDBC)

    • Manages data storage and retrieval.

    • Uses JDBC to insert names into the greetings table.


Key Idea:

  • View → displays interface

  • Controller → handles events / logic

  • Model → manages data

This structure separates GUI, logic, and data, following the MVC design pattern

16b.Describe how you’d apply Dependency Inversion so the Controller can be unit-tested without a real database.

Making the Controller Testable with Dependency Inversion

Problem:
Right now, the Controller talks directly to the database.

  • This makes testing hard because you need a real database.

Solution:

  • Make the Controller talk to an interface instead of the real database.

  • This way, we can give it a fake database (mock) during testing.


Step 1: Create an interface

// Any data storage class should implement this public interface GreetingRepository { void saveName(String name); }

Step 2: Make the real database implement it

import java.sql.*; public class JdbcGreetingRepository implements GreetingRepository { private PreparedStatement pstmt; public JdbcGreetingRepository(Connection con) throws SQLException { pstmt = con.prepareStatement("INSERT INTO greetings(name) VALUES(?)"); } @Override public void saveName(String name) throws SQLException { pstmt.setString(1, name); pstmt.executeUpdate(); } }

Step 3: Controller depends on the interface

public class GreetingController { private GreetingRepository repo; public GreetingController(GreetingRepository repo) { this.repo = repo; // depends on abstraction } public String handleSave(String name) { if (name.isEmpty()) return "Name cannot be empty"; repo.saveName(name); return "Saved successfully!"; } }

Step 4: Use a mock repository for testing

import java.util.ArrayList; import java.util.List; public class MockRepository implements GreetingRepository { List<String> saved = new ArrayList<>(); @Override public void saveName(String name) { saved.add(name); // just store in memory } }
public class TestController { public static void main(String[] args) { MockRepository mock = new MockRepository(); GreetingController controller = new GreetingController(mock); controller.handleSave("Alice"); System.out.println(mock.saved); // prints: [Alice] } }

Key Idea (Simple Version)

  1. Controller doesn’t care about the database—it only talks to GreetingRepository.

  2. For testing, we replace the real database with a fake one.

  3. This is Dependency Inversion: depend on abstraction, not concrete classes.



Comments

Popular posts from this blog

Object Oriented Programming PBCST304 KTU BTech CS Semester 3 2024 Scheme - Dr Binu V P

Introduction to Java Programming

Inheritance and Polymorphism