Access Modifiers explained
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
BaseServiceitself can see or modify these members.No other class can directly access
BASEURLorrequestSpecification(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?
BASEURLis an internal detail; other classes only need to know thatBaseServicecalls some base URL, not what it is or how it’s stored.requestSpecificationis 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
BASEURLshared by allBaseServiceinstances.Even if you create 100
BaseServiceobjects, 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";insideBaseService.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
LogginFilterfor 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
BaseServiceis allowed to create an instance withnew BaseService().Inside the constructor, you set up
requestSpecificationusing the privateBASEURL.
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:
BaseServiceitself can callpostRequest.Any subclass of
BaseService(even in other packages) can call it.Any class in the same package as
BaseServicecan 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:
BaseServiceexposes low-level HTTP methods asprotected.Each specific service class (like
EmployeeService,OrderService) extendsBaseServiceand exposes clean, public domain methods on top.
Summary table of access modifiers in this example
| Member | Modifiers | Who can access it? |
BaseService (class) | public | Any class in any package. |
BASEURL | private static final | Only code inside BaseService. |
requestSpecification | private | Only code inside BaseService. |
Constructor BaseService() | public | Any class that can see BaseService. |
Method postRequest(...) | protected | BaseService, 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.