EmailAddress.java

1
package fr.sii.ogham.email.message;
2
3
import java.util.regex.Matcher;
4
import java.util.regex.Pattern;
5
6
import fr.sii.ogham.core.util.EqualsBuilder;
7
import fr.sii.ogham.core.util.HashCodeBuilder;
8
9
/**
10
 * Represents an email address. jakarta.mail.internet.InternetAddress also
11
 * provides the same feature but we don't want to be sticked to a particular
12
 * implementation.
13
 * 
14
 * @author Aurélien Baudet
15
 *
16
 */
17
public class EmailAddress {
18
	private static final String QUOTED = "(\"(?<personal1>[^\"]+)\")";
19
	private static final String UNQUOTED = "(?<personal2>[^\"]+)";
20
	private static final String ADDRESS_WITH_TAG = "<(?<address>[^>]+)>";
21
	private static final Pattern SIMPLE_ADDRESS_WITH_PERSONAL = Pattern.compile("\\s*+("+QUOTED+"|"+UNQUOTED+")\\s++"+ADDRESS_WITH_TAG);
22
	private static final int MAX_SIZE = 320;
23
24
	/**
25
	 * The email address part (is of the form "user@domain.host")
26
	 */
27
	private String address;
28
29
	/**
30
	 * The user name part (can be anything)
31
	 */
32
	private String personal;
33
34
	/**
35
	 * Initialize the address with only the email address part (no personal). It
36
	 * is of the form "user@domain.host" or and "Personal Name
37
	 * &lt;user@host.domain&gt;" formats.
38
	 * 
39
	 * When using an address of the form "Personal Name
40
	 * &lt;user@host.domain&gt;", the address is parsed to split into two
41
	 * fields:
42
	 * <ul>
43
	 * <li>email address ("user@domain.host"), accessible through
44
	 * {@link #getAddress()}</li>
45
	 * <li>personal name if any ("Personal Name"), accessible through
46
	 * {@link #getPersonal()}</li>
47
	 * </ul>
48
	 * 
49
	 * <strong>IMPORTANT: The parsing of address and personal only supports
50
	 * simple cases. The cases defined in RFC822 and RFC2822 with comments,
51
	 * mailbox and group are not supported.</strong> If you need this feature,
52
	 * you need to use an external parser in order to extract information. If
53
	 * an address containing mailbox or group is provided, then no personal name
54
	 * is extracted but address is the full string.
55
	 * 
56
	 * @param rawAddress
57
	 *            the email address part
58
	 */
59
	public EmailAddress(String rawAddress) {
60
		super();
61
		EmailAddress parsed = parse(rawAddress);
62
		address = parsed.getAddress();
63
		personal = parsed.getPersonal();
64
	}
65
66
	/**
67
	 * Initialize the address with the email address and the personal parts.
68
	 * No parsing is applied.
69
	 * 
70
	 * @param address
71
	 *            the email address part, it is of the form "user@domain.host"
72
	 * @param personal
73
	 *            the personal part
74
	 */
75
	public EmailAddress(String address, String personal) {
76
		super();
77
		this.address = address;
78
		this.personal = personal;
79
	}
80
81
	public String getAddress() {
82 1 1. getAddress : replaced return value with "" for fr/sii/ogham/email/message/EmailAddress::getAddress → RUN_ERROR
		return address;
83
	}
84
85
	public String getPersonal() {
86 1 1. getPersonal : replaced return value with "" for fr/sii/ogham/email/message/EmailAddress::getPersonal → RUN_ERROR
		return personal;
87
	}
88
89
	@Override
90
	public String toString() {
91
		StringBuilder builder = new StringBuilder();
92 2 1. toString : negated conditional → RUN_ERROR
2. toString : negated conditional → RUN_ERROR
		if (personal != null && !personal.isEmpty()) {
93
			builder.append(personal).append(" ");
94
		}
95
		builder.append("<").append(address).append(">");
96 1 1. toString : replaced return value with "" for fr/sii/ogham/email/message/EmailAddress::toString → RUN_ERROR
		return builder.toString();
97
	}
98
99
	@Override
100
	public int hashCode() {
101 1 1. hashCode : replaced int return with 0 for fr/sii/ogham/email/message/EmailAddress::hashCode → RUN_ERROR
		return new HashCodeBuilder().append(address, personal).hashCode();
102
	}
103
104
	@Override
105
	public boolean equals(Object obj) {
106 2 1. equals : replaced boolean return with false for fr/sii/ogham/email/message/EmailAddress::equals → RUN_ERROR
2. equals : replaced boolean return with true for fr/sii/ogham/email/message/EmailAddress::equals → RUN_ERROR
		return new EqualsBuilder(this, obj).appendFields("address", "personal").isEqual();
107
	}
108
109
	public static EmailAddress parse(String rawAddress) {
110 1 1. parse : negated conditional → RUN_ERROR
		if(rawAddress == null) {
111
			throw new IllegalArgumentException("Address can't be null");
112
		}
113 2 1. parse : changed conditional boundary → RUN_ERROR
2. parse : negated conditional → RUN_ERROR
		if(rawAddress.length() > MAX_SIZE) {
114
			throw new IllegalArgumentException("Address maximum length is " + MAX_SIZE);
115
		}
116
		Matcher matcher = SIMPLE_ADDRESS_WITH_PERSONAL.matcher(rawAddress);
117 1 1. parse : negated conditional → RUN_ERROR
		if(matcher.matches()) {
118
			String address = matcher.group("address");
119 1 1. parse : negated conditional → RUN_ERROR
			String personal = matcher.group("personal1") != null ? matcher.group("personal1") : matcher.group("personal2");
120 1 1. parse : replaced return value with null for fr/sii/ogham/email/message/EmailAddress::parse → RUN_ERROR
			return new EmailAddress(address, personal);
121
		}
122 1 1. parse : replaced return value with null for fr/sii/ogham/email/message/EmailAddress::parse → RUN_ERROR
		return new EmailAddress(rawAddress, null);
123
	}
124
}

Mutations

82

1.1
Location : getAddress
Killed by :
replaced return value with "" for fr/sii/ogham/email/message/EmailAddress::getAddress → RUN_ERROR

86

1.1
Location : getPersonal
Killed by :
replaced return value with "" for fr/sii/ogham/email/message/EmailAddress::getPersonal → RUN_ERROR

92

1.1
Location : toString
Killed by :
negated conditional → RUN_ERROR

2.2
Location : toString
Killed by :
negated conditional → RUN_ERROR

96

1.1
Location : toString
Killed by :
replaced return value with "" for fr/sii/ogham/email/message/EmailAddress::toString → RUN_ERROR

101

1.1
Location : hashCode
Killed by :
replaced int return with 0 for fr/sii/ogham/email/message/EmailAddress::hashCode → RUN_ERROR

106

1.1
Location : equals
Killed by :
replaced boolean return with false for fr/sii/ogham/email/message/EmailAddress::equals → RUN_ERROR

2.2
Location : equals
Killed by :
replaced boolean return with true for fr/sii/ogham/email/message/EmailAddress::equals → RUN_ERROR

110

1.1
Location : parse
Killed by :
negated conditional → RUN_ERROR

113

1.1
Location : parse
Killed by :
changed conditional boundary → RUN_ERROR

2.2
Location : parse
Killed by :
negated conditional → RUN_ERROR

117

1.1
Location : parse
Killed by :
negated conditional → RUN_ERROR

119

1.1
Location : parse
Killed by :
negated conditional → RUN_ERROR

120

1.1
Location : parse
Killed by :
replaced return value with null for fr/sii/ogham/email/message/EmailAddress::parse → RUN_ERROR

122

1.1
Location : parse
Killed by :
replaced return value with null for fr/sii/ogham/email/message/EmailAddress::parse → RUN_ERROR

Active mutators

Tests examined


Report generated by PIT 1.13.1