Unit 08 · lesson
Java Interfaces and ROS 2 Interfaces: Same Word, Different Contract
The word interface appears in both Java and ROS 2, but it means something different in each system.
That shared vocabulary can be confusing because both ideas involve contracts. A Java interface defines behavior that Java classes agree to provide. A ROS 2 interface defines the structure of data or requests that ROS participants exchange.
The similarity is useful. The difference is essential.
Start with the Java interface you already know
Earlier this week you created:
interface RangeSource {
String getId();
double getRangeMeters();
}
This is a Java type contract.
A class can promise to implement it:
class FixedRangeSource implements RangeSource {
private final String id;
private final double rangeMeters;
FixedRangeSource(String id, double rangeMeters) {
this.id = id;
this.rangeMeters = rangeMeters;
}
@Override
public String getId() {
return id;
}
@Override
public double getRangeMeters() {
return rangeMeters;
}
}
The compiler checks whether the class provides the methods required by RangeSource.
That contract exists inside the Java type system.
ROS 2 interfaces describe communication data
ROS 2 uses interfaces to describe the data that nodes exchange.
The three main interface categories are:
- messages, used by topics;
- services, used for request/response communication;
- actions, used for longer-running goals that may provide feedback and support cancellation.
For this lesson, focus on a message interface.
Open the official ROS 2 Jazzy Interfaces documentation.
A common sensor message type is:
sensor_msgs/msg/Range
The controlled Robotnix terminal can show its declared fields:
ros2 interface show sensor_msgs/msg/Range
The simulator reports fields including:
std_msgs/Header header
uint8 radiation_type
float32 field_of_view
float32 min_range
float32 max_range
float32 range
Those declarations describe the shape of a ROS message.
For example, the range field is a float32. The message also contains declared minimum and maximum range values and header information.
This is very different from a Java interface method such as:
double getRangeMeters();
The ROS interface defines data that can cross a ROS communication boundary. The Java interface defines methods that Java code can call on an object.
Compare the contracts directly
| Question | Java RangeSource | ROS 2 sensor_msgs/msg/Range |
|---|---|---|
| What does it define? | methods Java implementations must provide | fields a ROS message contains |
| Who checks/uses it? | Java compiler and Java code | ROS 2 type support, publishers, subscribers, tools |
| Does it create a running component? | no | no |
| Can it describe a range value? | yes, through a method | yes, through the range field |
| Is it automatically connected to the other contract? | no | no |
The last row matters most. Similar concepts do not create an integration automatically.
A Java object does not publish a ROS message by existing
Suppose your program creates:
RangeSource source =
new FixedRangeSource("front", 0.42);
The object can return:
source.getRangeMeters();
with the value:
0.42
That does not mean a ROS 2 message has been published.
For ROS communication to occur, some integration layer must take data from one runtime and produce the appropriate ROS message through a supported ROS implementation.
The course deliberately keeps that boundary visible. A plain Java interface is not a shortcut around the ROS runtime.
Similar data still needs a translation decision
Imagine an integration component receives this Java result:
source.getRangeMeters(); // 0.42
and needs to produce a ROS Range message.
It would need to decide how Java-side information maps to ROS fields such as:
header
radiation_type
field_of_view
min_range
max_range
range
The Java interface currently provides only:
id
rangeMeters
That is not enough information to populate every ROS message field correctly.
This exposes an architecture question instead of hiding it:
What information does the boundary need, and which component owns that information?
The answer might require a richer Java model, configuration, another interface, or a separate adapter. The important point is that the mapping must be designed explicitly.
Inspect one controlled ROS message
Use the controlled terminal and run:
source /opt/ros/jazzy/setup.bash
ros2 interface show sensor_msgs/msg/Range
ros2 topic echo /range --once
The simulated message contains values such as:
header: {stamp: {sec: 42}, frame_id: front_sensor}
min_range: 0.10
max_range: 2.00
range: 0.42
Now separate two observations.
The Java object example contains a stored value of 0.42 meters.
The controlled ROS message example also contains a range field of 0.42.
The matching number does not prove one produced the other. The two examples were intentionally constructed to make comparison easy.
A real integration claim would need evidence of the actual bridge or publisher path.
Message fields carry meaning beyond the number
The ROS message is useful because the range value is not the only information available.
For example:
frame_id: front_sensor
provides frame-related context.
The declared limits:
min_range: 0.10
max_range: 2.00
provide information about the measurement interval represented by the message.
This is why an interface is more than a bag of primitive values. Field names, types, units, and semantics form part of the communication contract.
The same lesson applies to Java interfaces. Method names and return types should communicate what callers may rely on.
Do not confuse a ROS message with a ROS node
Another vocabulary trap is assuming that because a message interface exists, a node using it must also exist.
This command:
ros2 interface show sensor_msgs/msg/Range
shows the definition of an installed interface type.
It does not prove that any current node is publishing a topic of that type.
Similarly, a Java interface can exist in source code even if no object currently implements or uses it at runtime.
Definitions and runtime participation are different questions.
Worked classification
Classify each example by what kind of contract it represents.
Example A
interface MotorCommand {
void stop();
void setPercent(double percent);
}
This is a Java interface. It defines methods implementing Java classes must provide.
Example B
geometry_msgs/msg/Twist
This is a ROS 2 message interface type. It defines a message structure used in ROS communication.
Example C
ros2 node list
This is neither kind of interface. It is a runtime graph inspection command.
Example D
class DriveSubsystem extends SubsystemBase
This is a Java class participating in WPILib's subsystem architecture. The class declaration is not a ROS interface.
Keeping the labels precise prevents architecture from collapsing into vocabulary soup.
Practice: design a boundary table
Use your RangeSource interface and the sensor_msgs/msg/Range fields.
Create a table with these columns:
- Java-side information;
- possible ROS field;
- direct mapping, derived value, or missing information;
- who should own the translation decision.
At minimum, analyze:
getRangeMeters()
getId()
range
frame_id
min_range
max_range
field_of_view
Do not invent values for information your Java contract does not provide. Mark it as missing and explain what additional source would be needed.
In the final lesson, you will use this distinction to review a complete component boundary: what callers can ask in Java, how implementations respond to invalid requests, and what information would still be required before the component could participate in a ROS 2 communication path.