Skip to main content

Command Palette

Search for a command to run...

Access Modifiers explained

Updated
5 min read

The BaseService code

Here is the code we will use throughout:

public class BaseService {
    private final static String BASEURL = "www.google.com";
    private RequestSpecification requestSpecification;

    static {
        RestAssured.filters(new LogginFilter());
    }

    public BaseService() {
        requestSpecification = RestAssured.given().baseUri(BASEURL);
    }

    protected Response postRequest(Object payload, String endpoint) {
        return requestSpecification
                .contentType(ContentType.JSON)
                .body(payload)
                .post(endpoint);
    }
}

Think of BaseService as a toolbox for making HTTP calls with Rest Assured. Inside this toolbox are tools and labels, and access modifiers decide who is allowed to touch which tool.

public – the open main door

In code:

public class BaseService {
    ...
}

public on the class means:

  • Any other class in any package can see and use BaseService (as long as the package is imported).

  • You can write new BaseService() from anywhere in your project or other modules that depend on it.​

Example usage from another class, say EmployeeService:

public class EmployeeService {

    public void createEmployee(Object employeePayload) {
        BaseService baseService = new BaseService();   // allowed, class is public
        Response response = baseService.postRequest(employeePayload, "/employees");
        // handle response
    }
}

Because the class is public, it is like a shop with a big front door open to the street: any customer (other class) can walk in and use it.​

private – secret stuff inside the toolbox

You use private twice:

private final static String BASEURL = "www.google.com";
private RequestSpecification requestSpecification;

private means:

  • Only code inside BaseService itself can see or modify these members.

  • No other class can directly access BASEURL or requestSpecification (even subclasses cannot).​

So this is not allowed in EmployeeService:

public void test() {
    BaseService baseService = new BaseService();
    // String url = BaseService.BASEURL; // ❌ not allowed, BASEURL is private
}

Why use private here?

  • BASEURL is an internal detail; other classes only need to know that BaseService calls some base URL, not what it is or how it’s stored.

  • requestSpecification is also an implementation detail; outside code should not directly modify or rely on it.​

Conceptually, private turns fields into a locked drawer inside the toolbox: you can use the drawer from inside, but outsiders only see the tools you deliberately expose as methods.

static and final – class-level and unchangeable

For BASEURL:

private final static String BASEURL = "www.google.com";

Two extra modifiers appear:

  • static – belongs to the class, not to each object.

    • There is exactly one BASEURL shared by all BaseService instances.

    • Even if you create 100 BaseService objects, they all refer to the same URL value.​

  • final – value cannot be changed after it is assigned.

    • No code can later do BASEURL = "www.bing.com"; inside BaseService.

    • This turns it into a constant; commonly named in upper case for readability.​

Conceptually:

  • static = a label on the class itself (like a signboard on the toolbox brand).

  • final = once written, the label text can’t be edited.

This combination is great for constants like URLs, Port numbers, or configuration keys.

The static block – class-level setup

Your static block:

static {
    RestAssured.filters(new LogginFilter());
}
  • Runs once when BaseService (or its members) is first loaded.

  • Here, you are globally configuring Rest Assured to use LogginFilter for all requests, which is a typical use of static initialization when integrating with libraries.​

This is like saying: “As soon as this toolbox type exists in the workshop, install a common logger in the building.” It is not strictly an access modifier, but it works together with static to set shared behavior.

public constructor – how others build the toolbox

public BaseService() {
    requestSpecification = RestAssured.given().baseUri(BASEURL);
}

public on the constructor means:

  • Any other class that can see BaseService is allowed to create an instance with new BaseService().

  • Inside the constructor, you set up requestSpecification using the private BASEURL.​

This enforces a nice pattern:

  • Outside code can create the toolbox.

  • But it has no control over how the toolbox wires Rest Assured or which base URL it uses; that remains an internal decision.

protected – shared with “family” and package

Finally:

protected Response postRequest(Object payload, String endpoint) {
    return requestSpecification
            .contentType(ContentType.JSON)
            .body(payload)
            .post(endpoint);
}

protected means:

  • BaseService itself can call postRequest.

  • Any subclass of BaseService (even in other packages) can call it.

  • Any class in the same package as BaseService can call it.​

But classes in other packages that do not extend BaseService cannot call it.

Example: subclass allowed to use it

public class EmployeeService extends BaseService {

    public Response createEmployee(Object employeePayload) {
        // allowed: EmployeeService extends BaseService
        return postRequest(employeePayload, "/employees");
    }
}

If you changed it to public:

public Response postRequest(Object payload, String endpoint) { ... }

Then any class anywhere could do:

BaseService baseService = new BaseService();
Response response = baseService.postRequest(payload, "/employees");

With protected, you are saying:

  • “This is a powerful but low-level method; I only want my children (subclasses) or same-package helpers to use it, not random callers.”​

This is a common pattern when building a base service layer:

  • BaseService exposes low-level HTTP methods as protected.

  • Each specific service class (like EmployeeService, OrderService) extends BaseService and exposes clean, public domain methods on top.

Summary table of access modifiers in this example

MemberModifiersWho can access it?
BaseService (class)publicAny class in any package.
BASEURLprivate static finalOnly code inside BaseService.
requestSpecificationprivateOnly code inside BaseService.
Constructor BaseService()publicAny class that can see BaseService.
Method postRequest(...)protectedBaseService, its subclasses, and classes in the same package.

These choices give you encapsulation: you hide implementation details (BASEURL, requestSpecification), expose only what other code truly needs (BaseService() and higher-level service methods), and control who can touch internal plumbing like postRequest.