In my projects, I’m using a wrapper class for the space keys, as I think this helps a lot in following the “fail as quickly as possible” recommendation to avoid exceptions in deeper parts of the code. So, when for example I get a REST call or a Macro parameter with a space key as a String, I do the validation and only advance if it passes it. When in a UI, if possible, I use dropdowns that only allow existing space keys.
This is the code:
import org.apache.commons.lang3.StringUtils;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Wrapper class for Confluence Space Key
*/
public class SpaceKey {
public static final String SPACE_KEY_CAN_NOT_BE_BLANK_MESSAGE = "Space key can not be blank";
public static final String INVALID_SPACE_KEY_MESSAGE =
"Space key may only consist of ASCII letters or numbers (A-Z, a-z, 0-9), or begin with ~ if it's a personal space, with a maximum length of 255 characters. Invalid space key found: ";
private static final String SPACE_KEY_PATTERN = "(~)*[a-zA-Z\\d]{1,255}";
private static final Pattern pattern = Pattern.compile(SPACE_KEY_PATTERN);
private final String delegate;
private SpaceKey(String delegate) {
checkSpaceKey(delegate);
if (delegate.startsWith("~")) {
this.delegate = delegate;
} else {
this.delegate = delegate.toUpperCase();
}
}
private void checkSpaceKey(String spaceKey) {
if (StringUtils.isBlank(spaceKey)) {
throw new IllegalArgumentException(SPACE_KEY_CAN_NOT_BE_BLANK_MESSAGE);
}
Matcher matcher = pattern.matcher(spaceKey);
if (!matcher.matches()) {
throw new IllegalArgumentException(INVALID_SPACE_KEY_MESSAGE + spaceKey);
}
}
/**
* Checks if a given String is a valid space key
* @param spaceKey space key in string format
* @return true if it is a valid space key, false otherwise
*/
public static boolean isValid(String spaceKey) {
if (StringUtils.isBlank(spaceKey)) {
return false;
}
Matcher matcher = pattern.matcher(spaceKey);
return matcher.matches();
}
/**
* Initializes a SpaceKey from a space key in String format
* @param spaceKey space key in string format to initialize the space key from
* @return a verified Confluence space key
* @throws IllegalArgumentException in case the given {@code spaceKey} does not comply with Confluence space key restrictions
*/
public static SpaceKey fromString(String spaceKey) {
return new SpaceKey(spaceKey);
}
@Override
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof SpaceKey))
return false;
SpaceKey other = (SpaceKey) o;
return this.delegate.equals(other.delegate);
}
@Override
public int hashCode() {
return delegate.hashCode();
}
@Override
public String toString() {
return delegate;
}
}