• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

openmrs / openmrs-core / 36452308112

28 Sep 2026 04:36PM UTC coverage: 65.574% (+0.1%) from 65.446%
36452308112

push

github

ibacher
Fix-up: Remove non-null annotation

23802 of 36298 relevant lines covered (65.57%)

0.66 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.15
/api/src/main/java/org/openmrs/Person.java
1
/**
2
 * This Source Code Form is subject to the terms of the Mozilla Public License,
3
 * v. 2.0. If a copy of the MPL was not distributed with this file, You can
4
 * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under
5
 * the terms of the Healthcare Disclaimer located at http://openmrs.org/license.
6
 *
7
 * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS
8
 * graphic logo is a trademark of OpenMRS Inc.
9
 */
10
package org.openmrs;
11

12
import java.text.ParseException;
13
import java.text.SimpleDateFormat;
14
import java.time.LocalDate;
15
import java.time.temporal.ChronoUnit;
16
import java.util.ArrayList;
17
import java.util.Calendar;
18
import java.util.Date;
19
import java.util.HashMap;
20
import java.util.List;
21
import java.util.Map;
22
import java.util.Set;
23
import java.util.TreeSet;
24

25
import javax.persistence.Transient;
26
import org.codehaus.jackson.annotate.JsonIgnore;
27
import org.hibernate.envers.Audited;
28
import org.hibernate.envers.NotAudited;
29
import org.hibernate.search.annotations.Analyze;
30
import org.hibernate.search.annotations.ContainedIn;
31
import org.hibernate.search.annotations.DateBridge;
32
import org.hibernate.search.annotations.DocumentId;
33
import org.hibernate.search.annotations.EncodingType;
34
import org.hibernate.search.annotations.Field;
35
import org.hibernate.search.annotations.Resolution;
36
import org.openmrs.util.OpenmrsUtil;
37
import org.slf4j.Logger;
38
import org.slf4j.LoggerFactory;
39
import org.springframework.util.StringUtils;
40

41
/**
42
 * A Person in the system. This can be either a small person stub, or indicative of an actual
43
 * Patient in the system. This class holds the generic person things that both the stubs and
44
 * patients share. Things like birthdate, names, addresses, and attributes are all generified into
45
 * the person table (and hence this super class)
46
 * 
47
 * @see org.openmrs.Patient
48
 */
49
@Audited
50
public class Person extends BaseChangeableOpenmrsData {
51
        
52
        public static final long serialVersionUID = 2L;
53
        
54
        private static final Logger log = LoggerFactory.getLogger(Person.class);
1 ✔
55
        
56
        @DocumentId
57
        protected Integer personId;
58
        
59
        private Set<PersonAddress> addresses = null;
1 ✔
60
        
61
        @ContainedIn
1 ✔
62
        private Set<PersonName> names = null;
63
        
64
        @ContainedIn
1 ✔
65
        private Set<PersonAttribute> attributes = null;
66
        
67
        @Field
68
        private String gender;
69
        
70

71
        @Field(analyze = Analyze.YES)
72
        @DateBridge(encoding = EncodingType.STRING, resolution = Resolution.DAY)
73
        private Date birthdate;
74
        
75
        private Date birthtime;
76
        
77
        private Boolean birthdateEstimated = false;
1 ✔
78
        
79
        private Boolean deathdateEstimated = false;
1 ✔
80
        
81
        @Field
1 ✔
82
        private Boolean dead = false;
1 ✔
83
        
84
        private Date deathDate;
85
        
86
        private Concept causeOfDeath;
87
        
88
        private String causeOfDeathNonCoded;
89

90
        private User personCreator;
91
        
92
        private Date personDateCreated;
93

94
        private User personChangedBy;
95
        
96
        private Date personDateChanged;
97
        
98
        private Boolean personVoided = false;
1 ✔
99

100
        private User personVoidedBy;
101
        
102
        private Date personDateVoided;
103
        
104
        private String personVoidReason;
105
        
106
        @Field
107
        @NotAudited
108
        private boolean isPatient;
109
        
110
        /**
111
         * Convenience map from PersonAttributeType.name to PersonAttribute.<br>
112
         * <br>
113
         * This is "cached" for each user upon first load. When an attribute is changed, the cache is
114
         * cleared and rebuilt on next access.
115
         */
116
        @Transient
1 ✔
117
        Map<String, PersonAttribute> attributeMap = null;
118
        
119
        @Transient
1 ✔
120
        private Map<String, PersonAttribute> allAttributeMap = null;
121
        
122
        /**
123
         * default empty constructor
124
         */
125
        public Person() {
1 ✔
126
        }
1 ✔
127
        
128
        /**
129
         * This constructor is used to build a new Person object copy from another person object
130
         * (usually a patient or a user subobject). All attributes are copied over to the new object.
131
         * NOTE! All child collection objects are copied as pointers, each individual element is not
132
         * copied. <br>
133
         *
134
         * @param person Person to create this person object from
135
         */
136
        public Person(Person person) {
1 ✔
137
                if (person == null) {
1 ✔
138
                        return;
×
139
                }
140
                
141
                personId = person.getPersonId();
1 ✔
142
                setUuid(person.getUuid());
1 ✔
143
                addresses = person.getAddresses();
1 ✔
144
                names = person.getNames();
1 ✔
145
                attributes = person.getAttributes();
1 ✔
146
                
147
                gender = person.getGender();
1 ✔
148
                birthdate = person.getBirthdate();
1 ✔
149
                birthtime = person.getBirthDateTime();
1 ✔
150
                birthdateEstimated = person.getBirthdateEstimated();
1 ✔
151
                deathdateEstimated = person.getDeathdateEstimated();
1 ✔
152
                dead = person.getDead();
1 ✔
153
                deathDate = person.getDeathDate();
1 ✔
154
                causeOfDeath = person.getCauseOfDeath();
1 ✔
155
                causeOfDeathNonCoded = person.getCauseOfDeathNonCoded();
1 ✔
156
                // base creator/voidedBy/changedBy info is not copied here
157
                // because that is specific to and will be recreated
158
                // by the subobject upon save
159
                
160
                setPersonCreator(person.getPersonCreator());
1 ✔
161
                setPersonDateCreated(person.getPersonDateCreated());
1 ✔
162
                setPersonChangedBy(person.getPersonChangedBy());
1 ✔
163
                setPersonDateChanged(person.getPersonDateChanged());
1 ✔
164
                setPersonVoided(person.getPersonVoided());
1 ✔
165
                setPersonVoidedBy(person.getPersonVoidedBy());
1 ✔
166
                setPersonDateVoided(person.getPersonDateVoided());
1 ✔
167
                setPersonVoidReason(person.getPersonVoidReason());
1 ✔
168
                
169
                setPatient(person.getIsPatient());
1 ✔
170
        }
1 ✔
171
        
172
        /**
173
         * Default constructor taking in the primary key personId value
174
         * 
175
         * @param personId Integer internal id for this person
176
         * <strong>Should</strong> set person id
177
         */
178
        public Person(Integer personId) {
1 ✔
179
                this.personId = personId;
1 ✔
180
        }
1 ✔
181
        
182
        // Property accessors
183
        
184
        /**
185
         * @return Returns the personId.
186
         */
187
        public Integer getPersonId() {
188
                return personId;
1 ✔
189
        }
190
        
191
        /**
192
         * @param personId The personId to set.
193
         */
194
        public void setPersonId(Integer personId) {
195
                this.personId = personId;
1 ✔
196
        }
1 ✔
197
        
198
        /**
199
         * @return person's gender
200
         */
201
        public String getGender() {
202
                return this.gender;
1 ✔
203
        }
204
        
205
        /**
206
         * @param gender person's gender
207
         */
208
        public void setGender(String gender) {
209
                this.gender = gender;
1 ✔
210
        }
1 ✔
211
        
212
        /**
213
         * @return person's date of birth
214
         */
215
        public Date getBirthdate() {
216
                return this.birthdate;
1 ✔
217
        }
218
        
219
        /**
220
         * @param birthdate person's date of birth
221
         */
222
        public void setBirthdate(Date birthdate) {
223
                this.birthdate = birthdate;
1 ✔
224
        }
1 ✔
225
        
226
        /**
227
         * @return true if person's birthdate is estimated
228
         * @deprecated as of 2.0, use {@link #getBirthdateEstimated()}
229
         */
230
        @Deprecated
231
        @JsonIgnore
232
        public Boolean isBirthdateEstimated() {
233
                return getBirthdateEstimated();
1 ✔
234
        }
235
        
236
        public Boolean getBirthdateEstimated() {
237
                return birthdateEstimated;
1 ✔
238
        }
239
        
240
        /**
241
         * @param birthdateEstimated true if person's birthdate is estimated
242
         */
243
        public void setBirthdateEstimated(Boolean birthdateEstimated) {
244
                this.birthdateEstimated = birthdateEstimated;
1 ✔
245
        }
1 ✔
246
        
247
        public Boolean getDeathdateEstimated() {
248
                return this.deathdateEstimated;
1 ✔
249
        }
250
        
251
        /**
252
         * @param deathdateEstimated true if person's deathdate is estimated
253
         */
254
        public void setDeathdateEstimated(Boolean deathdateEstimated) {
255
                this.deathdateEstimated = deathdateEstimated;
1 ✔
256
        }
1 ✔
257
        
258
        /**
259
         * @param birthtime person's time of birth
260
         */
261
        public void setBirthtime(Date birthtime) {
262
                this.birthtime = birthtime;
1 ✔
263
        }
1 ✔
264
        
265
        /**
266
         * @return person's time of birth with the date portion set to the date from person's birthdate
267
         */
268
        public Date getBirthDateTime() {
269
                if (birthdate != null && birthtime != null) {
1 ✔
270
                        String birthDateString = new SimpleDateFormat("yyyy-MM-dd").format(birthdate);
1 ✔
271
                        String birthTimeString = new SimpleDateFormat("HH:mm:ss").format(birthtime);
1 ✔
272
                        
273
                        try {
274
                                return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(birthDateString + " " + birthTimeString);
1 ✔
275
                        }
276
                        catch (ParseException e) {
×
277
                                log.error("Failed to parse birth date string", e);
×
278
                        }
279
                }
280
                return null;
1 ✔
281
        }
282
        
283
        /**
284
         * @return person's time of birth.
285
         */
286
        public Date getBirthtime() {
287
                return this.birthtime;
1 ✔
288
        }
289
        
290
        /**
291
         * @return Returns the death status.
292
         * @deprecated as of 2.0, use {@link #getDead()}
293
         */
294
        @Deprecated
295
        @JsonIgnore
296
        public Boolean isDead() {
297
                return getDead();
1 ✔
298
        }
299
        
300
        /**
301
         * @return Returns the death status.
302
         */
303
        public Boolean getDead() {
304
                return dead;
1 ✔
305
        }
306
        
307
        /**
308
         * @param dead The dead to set.
309
         */
310
        public void setDead(Boolean dead) {
311
                this.dead = dead;
1 ✔
312
        }
1 ✔
313
        
314
        /**
315
         * @return date of person's death
316
         */
317
        public Date getDeathDate() {
318
                return this.deathDate;
1 ✔
319
        }
320
        
321
        /**
322
         * @param deathDate date of person's death
323
         */
324
        public void setDeathDate(Date deathDate) {
325
                this.deathDate = deathDate;
1 ✔
326
                if (deathDate != null) {
1 ✔
327
                        setDead(true);
1 ✔
328
                }
329
        }
1 ✔
330
        
331
        /**
332
         * @return cause of person's death
333
         */
334
        public Concept getCauseOfDeath() {
335
                return this.causeOfDeath;
1 ✔
336
        }
337
        
338
        /**
339
         * @param causeOfDeath cause of person's death
340
         */
341
        public void setCauseOfDeath(Concept causeOfDeath) {
342
                this.causeOfDeath = causeOfDeath;
1 ✔
343
        }
1 ✔
344
        
345
        /**
346
         * This method returns the non coded cause of death
347
         * 
348
         * @return non coded cause of death
349
         * @since 2.2.0
350
         */
351
        public String getCauseOfDeathNonCoded() {
352
                return this.causeOfDeathNonCoded;
1 ✔
353
        }
354
        
355
        /**
356
         * This method sets the non coded cause of death with the value given as parameter
357
         * 
358
         * @param causeOfDeathNonCoded is a String that describes as text the cause of death
359
         * @since 2.2.0
360
         * <strong>Should</strong> not fail with null causeOfDeathNonCoded
361
         * <strong>Should</strong> set the attribute causeOfDeathNonCoded with the given parameter
362
         */
363
        public void setCauseOfDeathNonCoded(String causeOfDeathNonCoded) {
364
                this.causeOfDeathNonCoded = causeOfDeathNonCoded;
1 ✔
365
        }
1 ✔
366
        
367
        /**
368
         * @return list of known addresses for person
369
         * @see org.openmrs.PersonAddress
370
         * <strong>Should</strong> not get voided addresses
371
         * <strong>Should</strong> not fail with null addresses
372
         */
373
        public Set<PersonAddress> getAddresses() {
374
                if (addresses == null) {
1 ✔
375
                        addresses = new TreeSet<>();
1 ✔
376
                }
377
                return this.addresses;
1 ✔
378
        }
379
        
380
        /**
381
         * @param addresses Set&lt;PersonAddress&gt; list of known addresses for person
382
         * @see org.openmrs.PersonAddress
383
         */
384
        public void setAddresses(Set<PersonAddress> addresses) {
385
                this.addresses = addresses;
1 ✔
386
        }
1 ✔
387
        
388
        /**
389
         * @return all known names for person
390
         * @see org.openmrs.PersonName
391
         * <strong>Should</strong> not get voided names
392
         * <strong>Should</strong> not fail with null names
393
         */
394
        public Set<PersonName> getNames() {
395
                if (names == null) {
1 ✔
396
                        names = new TreeSet<>();
1 ✔
397
                }
398
                return this.names;
1 ✔
399
        }
400
        
401
        /**
402
         * @param names update all known names for person
403
         * @see org.openmrs.PersonName
404
         */
405
        public void setNames(Set<PersonName> names) {
406
                this.names = names;
1 ✔
407
        }
1 ✔
408
        
409
        /**
410
         * @return all known attributes for person
411
         * @see org.openmrs.PersonAttribute
412
         * <strong>Should</strong> not get voided attributes
413
         * <strong>Should</strong> not fail with null attributes
414
         */
415
        public Set<PersonAttribute> getAttributes() {
416
                if (attributes == null) {
1 ✔
417
                        attributes = new TreeSet<>();
1 ✔
418
                }
419
                return this.attributes;
1 ✔
420
        }
421
        
422
        /**
423
         * Returns only the non-voided attributes for this person
424
         * 
425
         * @return list attributes
426
         * <strong>Should</strong> not get voided attributes
427
         * <strong>Should</strong> not fail with null attributes
428
         */
429
        public List<PersonAttribute> getActiveAttributes() {
430
                List<PersonAttribute> attrs = new ArrayList<>();
1 ✔
431
                for (PersonAttribute attr : getAttributes()) {
1 ✔
432
                        if (!attr.getVoided()) {
1 ✔
433
                                attrs.add(attr);
1 ✔
434
                        }
435
                }
1 ✔
436
                return attrs;
1 ✔
437
        }
438
        
439
        /**
440
         * @param attributes update all known attributes for person
441
         * @see org.openmrs.PersonAttribute
442
         */
443
        public void setAttributes(Set<PersonAttribute> attributes) {
444
                this.attributes = attributes;
1 ✔
445
                attributeMap = null;
1 ✔
446
                allAttributeMap = null;
1 ✔
447
        }
1 ✔
448
        
449
        // Convenience methods
450
        
451
        /**
452
         * Convenience method to add the <code>attribute</code> to this person's attribute list if the
453
         * attribute doesn't exist already.<br>
454
         * <br>
455
         * Voids any current attribute with type = <code>newAttribute.getAttributeType()</code><br>
456
         * <br>
457
         * NOTE: This effectively limits persons to only one attribute of any given type **
458
         * 
459
         * @param newAttribute PersonAttribute to add to the Person
460
         * <strong>Should</strong> fail when new attribute exist
461
         * <strong>Should</strong> fail when new atribute are the same type with same value
462
         * <strong>Should</strong> void old attribute when new attribute are the same type with different value
463
         * <strong>Should</strong> remove attribute when old attribute are temporary
464
         * <strong>Should</strong> not save an attribute with a null value
465
         * <strong>Should</strong> not save an attribute with a blank string value
466
         * <strong>Should</strong> void old attribute when a null or blank string value is added
467
         */
468
        public void addAttribute(PersonAttribute newAttribute) {
469
                newAttribute.setPerson(this);
1 ✔
470
                boolean newIsNull = !StringUtils.hasText(newAttribute.getValue());
1 ✔
471
                
472
                for (PersonAttribute currentAttribute : getActiveAttributes()) {
1 ✔
473
                        if (currentAttribute.equals(newAttribute)) {
1 ✔
474
                                // if we have the same PersonAttributeId, don't add the new attribute
475
                                return;
1 ✔
476
                        } else if (currentAttribute.getAttributeType().equals(newAttribute.getAttributeType())) {
1 ✔
477
                                if (currentAttribute.getValue() != null && currentAttribute.getValue().equals(newAttribute.getValue())) {
1 ✔
478
                                        // this person already has this attribute
479
                                        return;
1 ✔
480
                                }
481
                                
482
                                // if the to-be-added attribute isn't already voided itself
483
                                // and if we have the same type, different value
484
                                if (!newAttribute.getVoided() || newIsNull) {
1 ✔
485
                                        if (currentAttribute.getCreator() != null) {
1 ✔
486
                                                currentAttribute.voidAttribute("New value: " + newAttribute.getValue());
1 ✔
487
                                        } else {
488
                                                // remove the attribute if it was just temporary (didn't have a creator
489
                                                // attached to it yet)
490
                                                removeAttribute(currentAttribute);
×
491
                                        }
492
                                }
493
                        }
494
                }
1 ✔
495
                attributeMap = null;
1 ✔
496
                allAttributeMap = null;
1 ✔
497
                if (!OpenmrsUtil.collectionContains(attributes, newAttribute) && !newIsNull) {
1 ✔
498
                        attributes.add(newAttribute);
1 ✔
499
                }
500
        }
1 ✔
501
        
502
        /**
503
         * Convenience method to get the <code>attribute</code> from this person's attribute list if the
504
         * attribute exists already.
505
         * 
506
         * @param attribute
507
         * <strong>Should</strong> not fail when person attribute is null
508
         * <strong>Should</strong> not fail when person attribute is not exist
509
         * <strong>Should</strong> remove attribute when exist
510
         */
511
        public void removeAttribute(PersonAttribute attribute) {
512
                if (attributes != null && attributes.remove(attribute)) {
1 ✔
513
                        attributeMap = null;
1 ✔
514
                        allAttributeMap = null;
1 ✔
515
                }
516
        }
1 ✔
517
        
518
        /**
519
         * Convenience Method to return the first non-voided person attribute matching a person
520
         * attribute type. <br>
521
         * <br>
522
         * Returns null if this person has no non-voided {@link PersonAttribute} with the given
523
         * {@link PersonAttributeType}, the given {@link PersonAttributeType} is null, or this person
524
         * has no attributes.
525
         * 
526
         * @param pat the PersonAttributeType to look for (can be a stub, see
527
         *            {@link PersonAttributeType#equals(Object)} for how its compared)
528
         * @return PersonAttribute that matches the given type
529
         * <strong>Should</strong> not fail when attribute type is null
530
         * <strong>Should</strong> not return voided attribute
531
         * <strong>Should</strong> return null when existing PersonAttributeType is voided
532
         */
533
        public PersonAttribute getAttribute(PersonAttributeType pat) {
534
                if (pat != null) {
1 ✔
535
                        for (PersonAttribute attribute : getAttributes()) {
1 ✔
536
                                if (pat.equals(attribute.getAttributeType()) && !attribute.getVoided()) {
1 ✔
537
                                        return attribute;
×
538
                                }
539
                        }
1 ✔
540
                }
541
                return null;
1 ✔
542
        }
543
        
544
        /**
545
         * Convenience method to get this person's first attribute that has a PersonAttributeType.name
546
         * equal to <code>attributeName</code>.<br>
547
         * <br>
548
         * Returns null if this person has no non-voided {@link PersonAttribute} with the given type
549
         * name, the given name is null, or this person has no attributes.
550
         * 
551
         * @param attributeName the name string to match on
552
         * @return PersonAttribute whose {@link PersonAttributeType#getName()} matchs the given name
553
         *         string
554
         * <strong>Should</strong> return person attribute based on attributeName
555
         * <strong>Should</strong> return null if AttributeName is voided
556
         */
557
        public PersonAttribute getAttribute(String attributeName) {
558
                if (attributeName != null) {
1 ✔
559
                        for (PersonAttribute attribute : getAttributes()) {
1 ✔
560
                                PersonAttributeType type = attribute.getAttributeType();
1 ✔
561
                                if (type != null && attributeName.equals(type.getName()) && !attribute.getVoided()) {
1 ✔
562
                                        return attribute;
1 ✔
563
                                }
564
                        }
1 ✔
565
                }
566
                
567
                return null;
1 ✔
568
        }
569
        
570
        /**
571
         * Convenience method to get this person's first attribute that has a PersonAttributeTypeId
572
         * equal to <code>attributeTypeId</code>.<br>
573
         * <br>
574
         * Returns null if this person has no non-voided {@link PersonAttribute} with the given type id
575
         * or this person has no attributes.<br>
576
         * <br>
577
         * The given id cannot be null.
578
         * 
579
         * @param attributeTypeId the id of the {@link PersonAttributeType} to look for
580
         * @return PersonAttribute whose {@link PersonAttributeType#getId()} equals the given Integer id
581
         * <strong>Should</strong> return PersonAttribute based on attributeTypeId
582
         * <strong>Should</strong> return null when existing personAttribute with matching attribute type id is voided
583
         */
584
        public PersonAttribute getAttribute(Integer attributeTypeId) {
585
                for (PersonAttribute attribute : getActiveAttributes()) {
1 ✔
586
                        if (attributeTypeId.equals(attribute.getAttributeType().getPersonAttributeTypeId())) {
1 ✔
587
                                return attribute;
1 ✔
588
                        }
589
                }
1 ✔
590
                return null;
1 ✔
591
        }
592
        
593
        /**
594
         * Convenience method to get all of this person's attributes that have a
595
         * PersonAttributeType.name equal to <code>attributeName</code>.
596
         * 
597
         * @param attributeName
598
         * <strong>Should</strong> return all PersonAttributes with matching attributeType names
599
         */
600
        public List<PersonAttribute> getAttributes(String attributeName) {
601
                List<PersonAttribute> ret = new ArrayList<>();
1 ✔
602
                
603
                for (PersonAttribute attribute : getActiveAttributes()) {
1 ✔
604
                        PersonAttributeType type = attribute.getAttributeType();
1 ✔
605
                        if (type != null && attributeName.equals(type.getName())) {
1 ✔
606
                                ret.add(attribute);
1 ✔
607
                        }
608
                }
1 ✔
609
                
610
                return ret;
1 ✔
611
        }
612
        
613
        /**
614
         * Convenience method to get all of this person's attributes that have a PersonAttributeType.id
615
         * equal to <code>attributeTypeId</code>.
616
         * 
617
         * @param attributeTypeId
618
         * <strong>Should</strong> return empty list when matching personAttribute by id is voided
619
         * <strong>Should</strong> return list of person attributes based on AttributeTypeId
620
         */
621
        public List<PersonAttribute> getAttributes(Integer attributeTypeId) {
622
                List<PersonAttribute> ret = new ArrayList<>();
1 ✔
623
                
624
                for (PersonAttribute attribute : getActiveAttributes()) {
1 ✔
625
                        if (attributeTypeId.equals(attribute.getAttributeType().getPersonAttributeTypeId())) {
1 ✔
626
                                ret.add(attribute);
1 ✔
627
                        }
628
                }
1 ✔
629
                
630
                return ret;
1 ✔
631
        }
632
        
633
        /**
634
         * Convenience method to get all of this person's attributes that have a PersonAttributeType
635
         * equal to <code>personAttributeType</code>.
636
         * 
637
         * @param personAttributeType
638
         */
639
        public List<PersonAttribute> getAttributes(PersonAttributeType personAttributeType) {
640
                List<PersonAttribute> ret = new ArrayList<>();
×
641
                for (PersonAttribute attribute : getAttributes()) {
×
642
                        if (personAttributeType.equals(attribute.getAttributeType()) && !attribute.getVoided()) {
×
643
                                ret.add(attribute);
×
644
                        }
645
                }
×
646
                return ret;
×
647
        }
648
        
649
        /**
650
         * Convenience method to get this person's active attributes in map form: &lt;String,
651
         * PersonAttribute&gt;.
652
         */
653
        public Map<String, PersonAttribute> getAttributeMap() {
654
                if (attributeMap != null) {
×
655
                        return attributeMap;
×
656
                }
657
                
658
                log.debug("Current Person Attributes: \n{}", printAttributes());
×
659
                
660
                attributeMap = new HashMap<>();
×
661
                for (PersonAttribute attribute : getActiveAttributes()) {
×
662
                        attributeMap.put(attribute.getAttributeType().getName(), attribute);
×
663
                }
×
664
                
665
                return attributeMap;
×
666
        }
667
        
668
        /**
669
         * Convenience method to get all of this person's attributes (including voided ones) in map
670
         * form: &lt;String, PersonAttribute&gt;.
671
         * 
672
         * @return All person's attributes in map form
673
         * @since 1.12
674
         */
675
        public Map<String, PersonAttribute> getAllAttributeMap() {
676
                if (allAttributeMap != null) {
×
677
                        return allAttributeMap;
×
678
                }
679
                
680
                log.debug("Current Person Attributes: \n{}", printAttributes());
×
681
                
682
                allAttributeMap = new HashMap<>();
×
683
                for (PersonAttribute attribute : getAttributes()) {
×
684
                        allAttributeMap.put(attribute.getAttributeType().getName(), attribute);
×
685
                }
×
686
                
687
                return allAttributeMap;
×
688
        }
689
        
690
        /**
691
         * Convenience method for viewing all of the person's current attributes
692
         * 
693
         * @return Returns a string with all the attributes
694
         */
695
        public String printAttributes() {
696
                StringBuilder s = new StringBuilder("");
×
697
                
698
                for (PersonAttribute attribute : getAttributes()) {
×
699
                        s.append(attribute.getAttributeType()).append(" : ").append(attribute.getValue()).append(" : voided? ")
×
700
                                .append(attribute.getVoided()).append("\n");
×
701
                }
×
702
                
703
                return s.toString();
×
704
        }
705
        
706
        /**
707
         * Convenience method to add the <code>name</code> to this person's name list if the name
708
         * doesn't exist already.
709
         * 
710
         * @param name
711
         */
712
        public void addName(PersonName name) {
713
                if (name != null) {
1 ✔
714
                        name.setPerson(this);
1 ✔
715
                        if (names == null) {
1 ✔
716
                                names = new TreeSet<>();
1 ✔
717
                        }
718
                        if (!OpenmrsUtil.collectionContains(names, name)) {
1 ✔
719
                                names.add(name);
1 ✔
720
                        }
721
                }
722
        }
1 ✔
723
        
724
        /**
725
         * Convenience method remove the <code>name</code> from this person's name list if the name
726
         * exists already.
727
         * 
728
         * @param name
729
         */
730
        public void removeName(PersonName name) {
731
                if (names != null) {
1 ✔
732
                        names.remove(name);
1 ✔
733
                }
734
        }
1 ✔
735
        
736
        /**
737
         * Convenience method to add the <code>address</code> to this person's address list if the
738
         * address doesn't exist already.
739
         * 
740
         * @param address
741
         * <strong>Should</strong> not add a person address with blank fields
742
         */
743
        public void addAddress(PersonAddress address) {
744
                if (address != null) {
1 ✔
745
                        address.setPerson(this);
1 ✔
746
                        if (addresses == null) {
1 ✔
747
                                addresses = new TreeSet<>();
1 ✔
748
                        }
749
                        if (!OpenmrsUtil.collectionContains(addresses, address) && !address.isBlank()) {
1 ✔
750
                                addresses.add(address);
1 ✔
751
                        }
752
                }
753
        }
1 ✔
754
        
755
        /**
756
         * Convenience method to remove the <code>address</code> from this person's address list if the
757
         * address exists already.
758
         * 
759
         * @param address
760
         */
761
        public void removeAddress(PersonAddress address) {
762
                if (addresses != null) {
1 ✔
763
                        addresses.remove(address);
1 ✔
764
                }
765
        }
1 ✔
766
        
767
        /**
768
         * Convenience method to get the {@link PersonName} object that is marked as "preferred". <br>
769
         * <br>
770
         * If two names are marked as preferred (or no names), the database ordering comes into effect
771
         * and the one that was created most recently will be returned. <br>
772
         * <br>
773
         * This method will never return a voided name, even if it is marked as preferred. <br>
774
         * <br>
775
         * Null is returned if this person has no names or all voided names.
776
         * 
777
         * @return the "preferred" person name.
778
         * @see #getNames()
779
         * @see PersonName#getPreferred()
780
         * <strong>Should</strong> get preferred and not-voided person name if exist
781
         * <strong>Should</strong> get not-voided person name if preferred address does not exist
782
         * <strong>Should</strong> get voided person address if person is voided and not-voided address does not exist
783
         * <strong>Should</strong> return null if person is not-voided and have voided names
784
         */
785
        public PersonName getPersonName() {
786
                // normally the DAO layer returns these in the correct order, i.e. preferred and non-voided first, but it's possible that someone
787
                // has fetched a Person, changed their names around, and then calls this method, so we have to be careful.
788
                if (getNames() != null && !getNames().isEmpty()) {
1 ✔
789
                        for (PersonName name : getNames()) {
1 ✔
790
                                if (name.getPreferred() && !name.getVoided()) {
1 ✔
791
                                        return name;
1 ✔
792
                                }
793
                        }
1 ✔
794
                        for (PersonName name : getNames()) {
1 ✔
795
                                if (!name.getVoided()) {
1 ✔
796
                                        return name;
1 ✔
797
                                }
798
                        }
1 ✔
799
                        
800
                        if (getVoided()) {
1 ✔
801
                                return getNames().iterator().next();
1 ✔
802
                        }
803
                }
804
                return null;
1 ✔
805
        }
806
        
807
        /**
808
         * Convenience method to get the given name attribute on this person's preferred PersonName
809
         * 
810
         * @return String given name of the person
811
         */
812
        public String getGivenName() {
813
                PersonName personName = getPersonName();
1 ✔
814
                if (personName == null) {
1 ✔
815
                        return "";
×
816
                } else {
817
                        return personName.getGivenName();
1 ✔
818
                }
819
        }
820
        
821
        /**
822
         * Convenience method to get the middle name attribute on this person's preferred PersonName
823
         * 
824
         * @return String middle name of the person
825
         */
826
        public String getMiddleName() {
827
                PersonName personName = getPersonName();
1 ✔
828
                if (personName == null) {
1 ✔
829
                        return "";
×
830
                } else {
831
                        return personName.getMiddleName();
1 ✔
832
                }
833
        }
834
        
835
        /**
836
         * Convenience method to get the family name attribute on this person's preferred PersonName
837
         * 
838
         * @return String family name of the person
839
         */
840
        public String getFamilyName() {
841
                PersonName personName = getPersonName();
1 ✔
842
                if (personName == null) {
1 ✔
843
                        return "";
×
844
                } else {
845
                        return personName.getFamilyName();
1 ✔
846
                }
847
        }
848
        
849
        /**
850
         * Convenience method to get the {@link PersonAddress} object that is marked as "preferred". <br>
851
         * <br>
852
         * If two addresses are marked as preferred (or no addresses), the database ordering comes into
853
         * effect and the one that was created most recently will be returned. <br>
854
         * <br>
855
         * This method will never return a voided address, even if it is marked as preferred. <br>
856
         * <br>
857
         * Null is returned if this person has no addresses or all voided addresses.
858
         * 
859
         * @return the "preferred" person address.
860
         * @see #getAddresses()
861
         * @see PersonAddress#getPreferred()
862
         * <strong>Should</strong> get preferred and not-voided person address if exist
863
         * <strong>Should</strong> get not-voided person address if preferred address does not exist
864
         * <strong>Should</strong> get voided person address if person is voided and not-voided address does not exist
865
         * <strong>Should</strong> return null if person is not-voided and have voided address
866
         */
867
        public PersonAddress getPersonAddress() {
868
                // normally the DAO layer returns these in the correct order, i.e. preferred and non-voided first, but it's possible that someone
869
                // has fetched a Person, changed their addresses around, and then calls this method, so we have to be careful.
870
                if (getAddresses() != null && !getAddresses().isEmpty()) {
1 ✔
871
                        for (PersonAddress addr : getAddresses()) {
1 ✔
872
                                if (addr.getPreferred() && !addr.getVoided()) {
1 ✔
873
                                        return addr;
1 ✔
874
                                }
875
                        }
1 ✔
876
                        for (PersonAddress addr : getAddresses()) {
1 ✔
877
                                if (!addr.getVoided()) {
1 ✔
878
                                        return addr;
1 ✔
879
                                }
880
                        }
1 ✔
881
                        
882
                        if (getVoided()) {
1 ✔
883
                                return getAddresses().iterator().next();
1 ✔
884
                        }
885
                }
886
                return null;
1 ✔
887
        }
888
        
889
        /**
890
         * Convenience method to calculate this person's age based on the birthdate For a person who
891
         * lived 1990 to 2000, age would be -5 in 1985, 5 in 1995, 10 in 2000, and 10 2010.
892
         * 
893
         * @return Returns age as an Integer.
894
         * <strong>Should</strong> get correct age after death
895
         */
896
        public Integer getAge() {
897
                return getAge(null);
1 ✔
898
        }
899
        
900
        /**
901
         * Convenience method: calculates the person's age on a given date based on the birthdate
902
         * 
903
         * @param onDate (null defaults to today)
904
         * @return int value of the person's age
905
         * <strong>Should</strong> get age before birthday
906
         * <strong>Should</strong> get age on birthday with no minutes defined
907
         * <strong>Should</strong> get age on birthday with minutes defined
908
         * <strong>Should</strong> get age after birthday
909
         * <strong>Should</strong> get age after death
910
         * <strong>Should</strong> get age with given date after death
911
         * <strong>Should</strong> get age with given date before death
912
         * <strong>Should</strong> get age with given date before birth
913
         */
914
        public Integer getAge(Date onDate) {
915
                if (birthdate == null) {
1 ✔
916
                        return null;
1 ✔
917
                }
918
                
919
                // Use default end date as today.
920
                Calendar today = Calendar.getInstance();
1 ✔
921
                // But if given, use the given date.
922
                if (onDate != null) {
1 ✔
923
                        today.setTime(onDate);
1 ✔
924
                }
925
                
926
                // If date given is after date of death then use date of death as end date
927
                if (getDeathDate() != null && today.getTime().after(getDeathDate())) {
1 ✔
928
                        today.setTime(getDeathDate());
1 ✔
929
                }
930
                
931
                Calendar bday = Calendar.getInstance();
1 ✔
932
                bday.setTime(birthdate);
1 ✔
933
                
934
                int age = today.get(Calendar.YEAR) - bday.get(Calendar.YEAR);
1 ✔
935
                
936
                // Adjust age when today's date is before the person's birthday
937
                int todaysMonth = today.get(Calendar.MONTH);
1 ✔
938
                int bdayMonth = bday.get(Calendar.MONTH);
1 ✔
939
                int todaysDay = today.get(Calendar.DAY_OF_MONTH);
1 ✔
940
                int bdayDay = bday.get(Calendar.DAY_OF_MONTH);
1 ✔
941
                
942
                if (todaysMonth < bdayMonth) {
1 ✔
943
                        age--;
×
944
                } else if (todaysMonth == bdayMonth && todaysDay < bdayDay) {
1 ✔
945
                        // we're only comparing on month and day, not minutes, etc
946
                        age--;
1 ✔
947
                }
948
                
949
                return age;
1 ✔
950
        }
951

952
        /**
953
         * Method to get the age of a person in months.
954
         *
955
         * @return the age in months as an Integer e.g. 20 (to mean 20 months)
956
         *
957
         * @since 2.7.0
958
         */
959
        public Integer getAgeInMonths() {
960
                return getAgeInChronoUnit(ChronoUnit.MONTHS);
1 ✔
961
        }
962

963
        /**
964
         * Method to get the age of a person in weeks.
965
         *
966
         * @return the age in weeks as an Integer e.g. 20 (to mean 20 weeks)
967
         *
968
         * @since 2.7.0
969
         */
970
        public Integer getAgeInWeeks() {
971
                return getAgeInChronoUnit(ChronoUnit.WEEKS);
1 ✔
972
        }
973

974
        /**
975
         * Method to get the age of a person in days.
976
         *
977
         * @return the age in days as an Integer e.g. 20 (to mean 20 days)
978
         *
979
         * @since 2.7.0
980
         */
981
        public Integer getAgeInDays() {
982
                return getAgeInChronoUnit(ChronoUnit.DAYS);
1 ✔
983
        }
984

985
        /**
986
         * Gets the age of a person with the specified ChronoUnit.
987
         *
988
         * @param chronoUnit the unit of precision for the age calculation (e.g. WEEKS, MONTHS, YEARS)
989
         * @return the age in the specified unit as an Integer
990
         *
991
         * @since 2.7.0
992
         */
993
        private Integer getAgeInChronoUnit(ChronoUnit chronoUnit) {
994
                if (this.birthdate == null) {
1 ✔
995
                        return null;
1 ✔
996
                }
997

998
                LocalDate birthDate = new java.sql.Date(this.birthdate.getTime()).toLocalDate();
1 ✔
999
                LocalDate endDate = LocalDate.now();
1 ✔
1000

1001
                // If date given is after date of death then use date of death as end date
1002
                if (this.deathDate != null) {
1 ✔
1003
                        LocalDate deathDate = new java.sql.Date(this.deathDate.getTime()).toLocalDate();
1 ✔
1004

1005
                        if (endDate.isAfter(deathDate)) {
1 ✔
1006
                                endDate = deathDate;
1 ✔
1007
                        }
1008
                }
1009

1010
                switch (chronoUnit) {
1 ✔
1011
                        case DAYS:
1012
                                return (int) ChronoUnit.DAYS.between(birthDate, endDate);
1 ✔
1013
                        case WEEKS:
1014
                                return (int) ChronoUnit.WEEKS.between(birthDate, endDate);
1 ✔
1015
                        case MONTHS:
1016
                                return (int) ChronoUnit.MONTHS.between(birthDate, endDate);
1 ✔
1017
                        default:
1018
                                throw new IllegalArgumentException("Unsupported ChronoUnit: " + chronoUnit);
×
1019
                }
1020
        }
1021
        
1022
        /**
1023
         * Convenience method: sets a person's birth date from an age as of the given date Also sets
1024
         * flag indicating that the birth date is inexact. This sets the person's birth date to January
1025
         * 1 of the year that matches this age and date
1026
         * 
1027
         * @param age (the age to set)
1028
         * @param ageOnDate (null defaults to today)
1029
         */
1030
        public void setBirthdateFromAge(int age, Date ageOnDate) {
1031
                Calendar c = Calendar.getInstance();
1 ✔
1032
                c.setTime(ageOnDate == null ? new Date() : ageOnDate);
1 ✔
1033
                c.set(Calendar.DATE, 1);
1 ✔
1034
                c.set(Calendar.MONTH, Calendar.JANUARY);
1 ✔
1035
                c.add(Calendar.YEAR, -1 * age);
1 ✔
1036
                setBirthdate(c.getTime());
1 ✔
1037
                setBirthdateEstimated(true);
1 ✔
1038
                
1039
        }
1 ✔
1040
        
1041
        public User getPersonChangedBy() {
1042
                return personChangedBy;
1 ✔
1043
        }
1044
        
1045
        public void setPersonChangedBy(User changedBy) {
1046
                this.personChangedBy = changedBy;
1 ✔
1047
                this.setChangedBy(changedBy);
1 ✔
1048
        }
1 ✔
1049
        
1050
        public Date getPersonDateChanged() {
1051
                return personDateChanged;
1 ✔
1052
        }
1053
        
1054
        public void setPersonDateChanged(Date dateChanged) {
1055
                this.personDateChanged = dateChanged;
1 ✔
1056
                this.setDateChanged(dateChanged);
1 ✔
1057
        }
1 ✔
1058
        
1059
        public User getPersonCreator() {
1060
                return personCreator;
1 ✔
1061
        }
1062
        
1063
        public void setPersonCreator(User creator) {
1064
                this.personCreator = creator;
1 ✔
1065
                this.setCreator(creator);
1 ✔
1066
        }
1 ✔
1067
        
1068
        public Date getPersonDateCreated() {
1069
                return personDateCreated;
1 ✔
1070
        }
1071
        
1072
        public void setPersonDateCreated(Date dateCreated) {
1073
                this.personDateCreated = dateCreated;
1 ✔
1074
                this.setDateCreated(dateCreated);
1 ✔
1075
        }
1 ✔
1076
        
1077
        public Date getPersonDateVoided() {
1078
                return personDateVoided;
1 ✔
1079
        }
1080
        
1081
        public void setPersonDateVoided(Date dateVoided) {
1082
                this.personDateVoided = dateVoided;
1 ✔
1083
                this.setDateVoided(dateVoided);
1 ✔
1084
        }
1 ✔
1085
        
1086
        public void setPersonVoided(Boolean voided) {
1087
                this.personVoided = voided;
1 ✔
1088
                this.setVoided(voided);
1 ✔
1089
        }
1 ✔
1090
        
1091
        public Boolean getPersonVoided() {
1092
                return personVoided;
1 ✔
1093
        }
1094
        
1095
        /**
1096
         * @deprecated as of 2.0, use {@link #getPersonVoided()}
1097
         */
1098
        @Deprecated
1099
        @JsonIgnore
1100
        public Boolean isPersonVoided() {
1101
                return getPersonVoided();
×
1102
        }
1103
        
1104
        public User getPersonVoidedBy() {
1105
                return personVoidedBy;
1 ✔
1106
        }
1107
        
1108
        public void setPersonVoidedBy(User voidedBy) {
1109
                this.personVoidedBy = voidedBy;
1 ✔
1110
                this.setVoidedBy(voidedBy);
1 ✔
1111
        }
1 ✔
1112
        
1113
        public String getPersonVoidReason() {
1114
                return personVoidReason;
1 ✔
1115
        }
1116
        
1117
        public void setPersonVoidReason(String voidReason) {
1118
                this.personVoidReason = voidReason;
1 ✔
1119
                this.setVoidReason(voidReason);
1 ✔
1120
        }
1 ✔
1121
        
1122
        /**
1123
         * @return true/false whether this person is a patient or not
1124
         * @deprecated as of 2.0, use {@link #getIsPatient()}
1125
         */
1126
        @Deprecated
1127
        @JsonIgnore
1128
        @NotAudited
1129
        public boolean isPatient() {
1130
                return getIsPatient();
1 ✔
1131
        }
1132
        
1133
        @NotAudited
1134
        public boolean getIsPatient() {
1135
                return isPatient;
1 ✔
1136
        }
1137
        
1138
        /**
1139
         * This should only be set by the database layer by looking at whether a row exists in the
1140
         * patient table
1141
         * 
1142
         * @param isPatient whether this person is a patient or not
1143
         */
1144
        protected void setPatient(boolean isPatient) {
1145
                this.isPatient = isPatient;
1 ✔
1146
        }
1 ✔
1147
        
1148
        /**
1149
         * @see java.lang.Object#toString()
1150
         */
1151
        @Override
1152
        public String toString() {
1153
                return "Person(personId=" + personId + ")";
1 ✔
1154
        }
1155
        
1156
        /**
1157
         * @since 1.5
1158
         * @see org.openmrs.OpenmrsObject#getId()
1159
         */
1160
        @Override
1161
        public Integer getId() {
1162
                
1163
                return getPersonId();
1 ✔
1164
        }
1165
        
1166
        /**
1167
         * @since 1.5
1168
         * @see org.openmrs.OpenmrsObject#setId(java.lang.Integer)
1169
         */
1170
        @Override
1171
        public void setId(Integer id) {
1172
                setPersonId(id);
1 ✔
1173
                
1174
        }
1 ✔
1175
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc