Tutorial 3: Patient DTO & Mapper¶
Pages: 2
📖 Page 1: Patient DTO¶
What is DTO?¶
DTO = Data Transfer Object = Simple Java object for moving data
Why? Since FHIR resources are complex with many nested fields, we use DTOs to extract only the data we need for our UI or API responses
Create PatientDTO¶
Create src/main/java/com/healthcare/pms/dto/PatientDTO.java:
package com.healthcare.pms.dto;
import jakarta.validation.constraints.*;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDate;
@Data
public class PatientDTO {
private String id;
@NotBlank(message = "First name required")
private String firstName;
@NotBlank(message = "Last name required")
private String lastName;
@NotNull @Past
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate birthDate;
@NotBlank
private String gender;
@Email
private String email;
private String phone;
private String addressLine;
private String city;
private String state;
private String postalCode;
private String country;
private String bloodGroup;
private Boolean active = true;
public String getFullName() {
return firstName + " " + lastName;
}
}
That's it! Simple patient data with validation.
📖 Page 2: Patient Mapper¶
What is Mapper?¶
Mapper = Translator between DTO ↔ FHIR
Create PatientMapper¶
Create src/main/java/com/healthcare/pms/mapper/PatientMapper.java:
package com.healthcare.pms.mapper;
import com.healthcare.pms.dto.PatientDTO;
import org.hl7.fhir.r4.model.*;
import org.springframework.stereotype.Component;
import java.time.ZoneId;
import java.util.Date;
@Component
public class PatientMapper {
// DTO → FHIR
public Patient toFhirResource(PatientDTO dto) {
Patient patient = new Patient();
if (dto.getId() != null) patient.setId(dto.getId());
// Name
HumanName name = new HumanName();
name.setFamily(dto.getLastName());
name.addGiven(dto.getFirstName());
patient.addName(name);
// Gender
if (dto.getGender() != null) {
patient.setGender(Enumerations.AdministrativeGender.valueOf(
dto.getGender().toUpperCase()
));
}
// Birth Date
if (dto.getBirthDate() != null) {
patient.setBirthDate(Date.from(
dto.getBirthDate().atStartOfDay(ZoneId.systemDefault()).toInstant()
));
}
// Email
if (dto.getEmail() != null) {
ContactPoint email = new ContactPoint();
email.setSystem(ContactPoint.ContactPointSystem.EMAIL);
email.setValue(dto.getEmail());
patient.addTelecom(email);
}
// Phone
if (dto.getPhone() != null) {
ContactPoint phone = new ContactPoint();
phone.setSystem(ContactPoint.ContactPointSystem.PHONE);
phone.setValue(dto.getPhone());
patient.addTelecom(phone);
}
// Address
if (dto.getAddressLine() != null) {
Address address = new Address();
address.addLine(dto.getAddressLine());
address.setCity(dto.getCity());
address.setState(dto.getState());
address.setPostalCode(dto.getPostalCode());
address.setCountry(dto.getCountry());
patient.addAddress(address);
}
// Blood Group (Extension)
if (dto.getBloodGroup() != null) {
Extension ext = new Extension();
ext.setUrl("http://example.org/blood-group");
ext.setValue(new StringType(dto.getBloodGroup()));
patient.addExtension(ext);
}
patient.setActive(dto.getActive());
return patient;
}
// FHIR → DTO
public PatientDTO toDTO(Patient patient) {
PatientDTO dto = new PatientDTO();
dto.setId(patient.getIdElement().getIdPart());
// Name
if (patient.hasName()) {
HumanName name = patient.getNameFirstRep();
dto.setLastName(name.getFamily());
dto.setFirstName(name.getGivenAsSingleString());
}
// Gender
if (patient.hasGender()) {
dto.setGender(patient.getGender().toCode());
}
// Birth Date
if (patient.hasBirthDate()) {
dto.setBirthDate(patient.getBirthDate().toInstant()
.atZone(ZoneId.systemDefault()).toLocalDate());
}
// Telecom
for (ContactPoint cp : patient.getTelecom()) {
if (cp.getSystem() == ContactPoint.ContactPointSystem.EMAIL) {
dto.setEmail(cp.getValue());
} else if (cp.getSystem() == ContactPoint.ContactPointSystem.PHONE) {
dto.setPhone(cp.getValue());
}
}
// Address
if (patient.hasAddress()) {
Address addr = patient.getAddressFirstRep();
dto.setAddressLine(addr.getLine().isEmpty() ? null :
addr.getLine().get(0).getValue());
dto.setCity(addr.getCity());
dto.setState(addr.getState());
dto.setPostalCode(addr.getPostalCode());
dto.setCountry(addr.getCountry());
}
// Blood Group
for (Extension ext : patient.getExtension()) {
if (ext.getUrl().contains("blood-group")) {
dto.setBloodGroup(ext.getValue().toString());
}
}
dto.setActive(patient.getActive());
return dto;
}
}
✅ You Now Have¶
- PatientDTO with all fields and validation
- PatientMapper for DTO ↔ FHIR conversion
- Two-way conversion supported: FHIR to DTO and DTO back to FHIR
🚀 Next¶
Data structures ready! Now let's create CRUD operations.
→ Tutorial 4: Patient CRUD Operations
💡 Quick Tips¶
Lombok Magic
@Data auto-generates getters, setters, toString, equals, hashCode
Validation
@NotBlank, @Email, @Past validate on form submission
Extensions
Use Extensions for custom FHIR fields (like blood group)