Add client side errors in case of data initialization with null values

This commit is contained in:
Leon Hofmeister 2020-10-22 23:58:55 +02:00
parent 44d3082958
commit 2eeb55ed52
Signed by: delvh
GPG Key ID: 3DECE05F6D9A647C
15 changed files with 72 additions and 41 deletions

View File

@ -1,6 +1,7 @@
package envoy.data; package envoy.data;
import java.io.Serializable; import java.io.Serializable;
import java.util.Objects;
/** /**
* This interface should be used for any type supposed to be a {@link Message} attachment (i.e. * This interface should be used for any type supposed to be a {@link Message} attachment (i.e.
@ -63,9 +64,9 @@ public final class Attachment implements Serializable {
* @since Envoy Common v0.1-beta * @since Envoy Common v0.1-beta
*/ */
public Attachment(byte[] data, String name, AttachmentType type) { public Attachment(byte[] data, String name, AttachmentType type) {
this.data = data; this.data = Objects.requireNonNull(data);
this.name = name; this.name = Objects.requireNonNull(name);
this.type = type; this.type = Objects.requireNonNull(type);
} }
/** /**

View File

@ -29,8 +29,8 @@ public abstract class Contact implements Serializable {
*/ */
public Contact(long id, String name, Set<? extends Contact> contacts) { public Contact(long id, String name, Set<? extends Contact> contacts) {
this.id = id; this.id = id;
this.name = name; this.name = Objects.requireNonNull(name);
this.contacts = contacts; this.contacts = contacts == null ? new HashSet<>() : contacts;
} }
/** /**

View File

@ -38,7 +38,8 @@ public final class GroupMessage extends Message {
Map<Long, MessageStatus> memberStatuses) { Map<Long, MessageStatus> memberStatuses) {
super(id, senderID, groupID, creationDate, receivedDate, readDate, text, attachment, status, super(id, senderID, groupID, creationDate, receivedDate, readDate, text, attachment, status,
forwarded); forwarded);
this.memberStatuses = memberStatuses; this.memberStatuses =
memberStatuses == null ? new HashMap<>() : memberStatuses;
} }
/** /**

View File

@ -2,6 +2,7 @@ package envoy.data;
import java.io.Serializable; import java.io.Serializable;
import java.time.Instant; import java.time.Instant;
import java.util.Objects;
/** /**
* Contains a {@link User}'s login / registration information as well as the client version. * Contains a {@link User}'s login / registration information as well as the client version.
@ -22,12 +23,12 @@ public final class LoginCredentials implements Serializable {
private LoginCredentials(String identifier, String password, boolean registration, private LoginCredentials(String identifier, String password, boolean registration,
boolean token, String clientVersion, boolean token, String clientVersion,
Instant lastSync) { Instant lastSync) {
this.identifier = identifier; this.identifier = Objects.requireNonNull(identifier);
this.password = password; this.password = Objects.requireNonNull(password);
this.registration = registration; this.registration = registration;
this.token = token; this.token = token;
this.clientVersion = clientVersion; this.clientVersion = Objects.requireNonNull(clientVersion);
this.lastSync = lastSync; this.lastSync = lastSync == null ? Instant.EPOCH : lastSync;
} }
/** /**

View File

@ -2,6 +2,7 @@ package envoy.data;
import java.io.Serializable; import java.io.Serializable;
import java.time.Instant; import java.time.Instant;
import java.util.Objects;
import dev.kske.eventbus.IEvent; import dev.kske.eventbus.IEvent;
@ -80,9 +81,9 @@ public class Message implements Serializable, IEvent {
this.creationDate = creationDate; this.creationDate = creationDate;
this.receivedDate = receivedDate; this.receivedDate = receivedDate;
this.readDate = readDate; this.readDate = readDate;
this.text = text; this.text = text == null ? "" : text;
this.attachment = attachment; this.attachment = attachment;
this.status = status; this.status = Objects.requireNonNull(status);
this.forwarded = forwarded; this.forwarded = forwarded;
} }

View File

@ -86,7 +86,7 @@ public final class User extends Contact {
*/ */
public User(long id, String name, UserStatus status, Set<Contact> contacts) { public User(long id, String name, UserStatus status, Set<Contact> contacts) {
super(id, name, contacts); super(id, name, contacts);
this.status = status; this.status = Objects.requireNonNull(status);
} }
@Override @Override

View File

@ -1,6 +1,7 @@
package envoy.event; package envoy.event;
import java.io.Serializable; import java.io.Serializable;
import java.util.Objects;
import dev.kske.eventbus.IEvent; import dev.kske.eventbus.IEvent;
@ -20,7 +21,16 @@ public abstract class Event<T> implements IEvent, Serializable {
private static final long serialVersionUID = 0L; private static final long serialVersionUID = 0L;
protected Event(T value) { protected Event(T value) {
this.value = value; this(value, false);
}
/**
* This constructor is reserved for {@link Valueless} events. No other event should contain null
* values. Only use if really necessary. Using this constructor with {@code true} implies that
* the user has to manually check if the value of the event is null.
*/
protected Event(T value, boolean canBeNull) {
this.value = canBeNull ? value : Objects.requireNonNull(value);
} }
/** /**
@ -46,7 +56,7 @@ public abstract class Event<T> implements IEvent, Serializable {
private static final long serialVersionUID = 0L; private static final long serialVersionUID = 0L;
protected Valueless() { protected Valueless() {
super(null); super(null, true);
} }
@Override @Override

View File

@ -20,7 +20,7 @@ public class GroupCreationResult extends Event<Group> {
* @since Envoy Common v0.2-beta * @since Envoy Common v0.2-beta
*/ */
public GroupCreationResult() { public GroupCreationResult() {
super(null); super(null, true);
} }
/** /**

View File

@ -2,6 +2,8 @@ package envoy.event;
import static envoy.event.ElementOperation.*; import static envoy.event.ElementOperation.*;
import java.util.Objects;
import envoy.data.*; import envoy.data.*;
/** /**
@ -30,7 +32,7 @@ public final class GroupResize extends Event<User> {
*/ */
public GroupResize(User user, Group group, ElementOperation operation) { public GroupResize(User user, Group group, ElementOperation operation) {
super(user); super(user);
this.operation = operation; this.operation = Objects.requireNonNull(operation);
final var contained = group.getContacts().contains(user); final var contained = group.getContacts().contains(user);
if (contained && operation.equals(ADD)) if (contained && operation.equals(ADD))
throw new IllegalArgumentException(String.format("Cannot add %s to %s!", user, group)); throw new IllegalArgumentException(String.format("Cannot add %s to %s!", user, group));

View File

@ -28,7 +28,7 @@ public final class IsTyping extends Event<Long> {
* @param destinationID the ID of the contact the user wrote to * @param destinationID the ID of the contact the user wrote to
* @since Envoy Common v0.2-beta * @since Envoy Common v0.2-beta
*/ */
public IsTyping(Long sourceID, long destinationID) { public IsTyping(long sourceID, long destinationID) {
super(sourceID); super(sourceID);
this.destinationID = destinationID; this.destinationID = destinationID;
} }

View File

@ -23,7 +23,7 @@ public final class IssueProposal extends Event<String> {
*/ */
public IssueProposal(String title, String description, boolean isBug) { public IssueProposal(String title, String description, boolean isBug) {
super(escape(title)); super(escape(title));
this.description = sanitizeDescription(description); this.description = description == null ? "" : sanitizeDescription(description);
bug = isBug; bug = isBug;
} }
@ -37,8 +37,8 @@ public final class IssueProposal extends Event<String> {
*/ */
public IssueProposal(String title, String description, String user, boolean isBug) { public IssueProposal(String title, String description, String user, boolean isBug) {
super(escape(title)); super(escape(title));
this.description = this.description = description == null ? ""
sanitizeDescription(description) + String.format("<br>Submitted by user %s.", user); : sanitizeDescription(description) + String.format("<br>Submitted by user %s.", user);
bug = isBug; bug = isBug;
} }

View File

@ -1,6 +1,7 @@
package envoy.event; package envoy.event;
import java.time.Instant; import java.time.Instant;
import java.util.Objects;
import envoy.data.Message; import envoy.data.Message;
@ -26,7 +27,7 @@ public class MessageStatusChange extends Event<Message.MessageStatus> {
public MessageStatusChange(long id, Message.MessageStatus status, Instant date) { public MessageStatusChange(long id, Message.MessageStatus status, Instant date) {
super(status); super(status);
this.id = id; this.id = id;
this.date = date; this.date = Objects.requireNonNull(date);
} }
/** /**

View File

@ -1,5 +1,7 @@
package envoy.event; package envoy.event;
import java.util.Objects;
import envoy.data.Contact; import envoy.data.Contact;
/** /**
@ -21,7 +23,7 @@ public final class PasswordChangeRequest extends Event<String> {
*/ */
public PasswordChangeRequest(String newPassword, String oldPassword, long userID) { public PasswordChangeRequest(String newPassword, String oldPassword, long userID) {
super(newPassword); super(newPassword);
this.oldPassword = oldPassword; this.oldPassword = Objects.requireNonNull(oldPassword);
id = userID; id = userID;
} }

View File

@ -1,5 +1,7 @@
package envoy.event.contact; package envoy.event.contact;
import java.util.Objects;
import envoy.data.User; import envoy.data.User;
import envoy.event.*; import envoy.event.*;
@ -24,7 +26,7 @@ public final class UserOperation extends Event<User> {
*/ */
public UserOperation(User contact, ElementOperation operationType) { public UserOperation(User contact, ElementOperation operationType) {
super(contact); super(contact);
this.operationType = operationType; this.operationType = Objects.requireNonNull(operationType);
} }
/** /**

View File

@ -1,7 +1,7 @@
package envoy.server.data; package envoy.server.data;
import java.time.Instant; import java.time.Instant;
import java.util.List; import java.util.*;
import java.util.logging.Level; import java.util.logging.Level;
import javax.persistence.*; import javax.persistence.*;
@ -223,6 +223,9 @@ public final class PersistenceManager {
* @since Envoy Server Standalone v0.2-beta * @since Envoy Server Standalone v0.2-beta
*/ */
public List<Message> getPendingMessages(User user, Instant lastSync) { public List<Message> getPendingMessages(User user, Instant lastSync) {
if (user == null)
return new ArrayList<>();
lastSync = Objects.requireNonNullElse(lastSync, Instant.EPOCH);
return entityManager.createNamedQuery(Message.getPending).setParameter("user", user) return entityManager.createNamedQuery(Message.getPending).setParameter("user", user)
.setParameter("lastSeen", lastSync).getResultList(); .setParameter("lastSeen", lastSync).getResultList();
} }
@ -236,6 +239,9 @@ public final class PersistenceManager {
* @since Envoy Server Standalone v0.2-beta * @since Envoy Server Standalone v0.2-beta
*/ */
public List<GroupMessage> getPendingGroupMessages(User user, Instant lastSync) { public List<GroupMessage> getPendingGroupMessages(User user, Instant lastSync) {
if (user == null)
return new ArrayList<>();
lastSync = Objects.requireNonNullElse(lastSync, Instant.EPOCH);
return entityManager.createNamedQuery(GroupMessage.getPendingGroupMsg) return entityManager.createNamedQuery(GroupMessage.getPendingGroupMsg)
.setParameter("userId", user.getID()) .setParameter("userId", user.getID())
.setParameter("lastSeen", lastSync) .setParameter("lastSeen", lastSync)
@ -277,16 +283,18 @@ public final class PersistenceManager {
* @since Envoy Server v0.3-beta * @since Envoy Server v0.3-beta
*/ */
public void addContactBidirectional(Contact contact1, Contact contact2) { public void addContactBidirectional(Contact contact1, Contact contact2) {
if (!(contact1 == null || contact2 == null)) {
// Add users to each others contact list // Add users to each others contact list
contact1.getContacts().add(contact2); contact1.getContacts().add(contact2);
contact2.getContacts().add(contact1); contact2.getContacts().add(contact1);
// Synchronize changes with the database // Synchronize changes with the database
transaction(() -> { transaction(() -> {
entityManager.merge(contact1); entityManager.merge(contact1);
entityManager.merge(contact2); entityManager.merge(contact2);
}); });
}
} }
/** /**
@ -308,16 +316,18 @@ public final class PersistenceManager {
* @since Envoy Server v0.3-beta * @since Envoy Server v0.3-beta
*/ */
public void removeContactBidirectional(Contact contact1, Contact contact2) { public void removeContactBidirectional(Contact contact1, Contact contact2) {
if (!(contact1 == null || contact2 == null)) {
// Remove users from each others contact list // Remove users from each others contact list
contact1.getContacts().remove(contact2); contact1.getContacts().remove(contact2);
contact2.getContacts().remove(contact1); contact2.getContacts().remove(contact1);
// Synchronize changes with the database // Synchronize changes with the database
transaction(() -> { transaction(() -> {
entityManager.merge(contact1); entityManager.merge(contact1);
entityManager.merge(contact2); entityManager.merge(contact2);
}); });
}
} }
/** /**