Skip to content

Package: CardinalityConstraintsValidator

CardinalityConstraintsValidator

nameinstructionbranchcomplexitylinemethod
CardinalityConstraintsValidator()
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
extractValueCount(Object)
M: 0 C: 16
100%
M: 1 C: 5
83%
M: 1 C: 3
75%
M: 0 C: 3
100%
M: 0 C: 1
100%
nonEmptyError(Object, String, String)
M: 0 C: 8
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
validate(Object, Field, Object)
M: 46 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 10 C: 0
0%
M: 1 C: 0
0%
validate(Object, FieldSpecification, Object)
M: 12 C: 59
83%
M: 1 C: 9
90%
M: 1 C: 5
83%
M: 1 C: 11
92%
M: 0 C: 1
100%
validateNonEmpty(Object, Attribute, int)
M: 0 C: 15
100%
M: 0 C: 4
100%
M: 0 C: 3
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
validateNonEmpty(Object, Field, int, ParticipationConstraints)
M: 14 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
validateParticipationConstraint(Object, Field, int, ParticipationConstraint)
M: 0 C: 40
100%
M: 0 C: 6
100%
M: 0 C: 4
100%
M: 0 C: 7
100%
M: 0 C: 1
100%

Coverage

1: /*
2: * JOPA
3: * Copyright (C) 2024 Czech Technical University in Prague
4: *
5: * This library is free software; you can redistribute it and/or
6: * modify it under the terms of the GNU Lesser General Public
7: * License as published by the Free Software Foundation; either
8: * version 3.0 of the License, or (at your option) any later version.
9: *
10: * This library is distributed in the hope that it will be useful,
11: * but WITHOUT ANY WARRANTY; without even the implied warranty of
12: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13: * Lesser General Public License for more details.
14: *
15: * You should have received a copy of the GNU Lesser General Public
16: * License along with this library.
17: */
18: package cz.cvut.kbss.jopa.sessions.validator;
19:
20: import cz.cvut.kbss.jopa.exceptions.CardinalityConstraintViolatedException;
21: import cz.cvut.kbss.jopa.model.annotations.ParticipationConstraint;
22: import cz.cvut.kbss.jopa.model.annotations.ParticipationConstraints;
23: import cz.cvut.kbss.jopa.model.metamodel.Attribute;
24: import cz.cvut.kbss.jopa.model.metamodel.FieldSpecification;
25: import cz.cvut.kbss.jopa.model.metamodel.QueryAttribute;
26: import cz.cvut.kbss.jopa.proxy.lazy.LazyLoadingProxy;
27:
28: import java.lang.reflect.Field;
29: import java.util.Collection;
30: import java.util.Objects;
31:
32: /**
33: * Validator of participation constraints.
34: */
35: class CardinalityConstraintsValidator extends IntegrityConstraintsValidator {
36:
37: CardinalityConstraintsValidator() {
38: }
39:
40: /**
41: * Validates cardinality constraints defined in the {@link ParticipationConstraints} annotation.
42: *
43: * @param identifier Field owner identifier (individual URI)
44: * @param field Field on which the constraints are defined
45: * @param value The value to validate
46: */
47: public void validate(Object identifier, Field field, Object value) {
48: Objects.requireNonNull(field);
49: final ParticipationConstraints constraints = field.getAnnotation(ParticipationConstraints.class);
50:• if (constraints == null) {
51: return;
52: }
53: final int valueCount = extractValueCount(value);
54:• for (ParticipationConstraint pc : constraints.value()) {
55: validateParticipationConstraint(identifier, field, valueCount, pc);
56: }
57:• if (constraints.value().length == 0) {
58: validateNonEmpty(identifier, field, valueCount, constraints);
59: }
60: }
61:
62: @Override
63: public void validate(Object identifier, FieldSpecification<?, ?> attribute, Object attributeValue) {
64: final int valueCount = extractValueCount(attributeValue);
65:
66: // Only proper attributes can have cardinality constraints
67:• if (attribute instanceof Attribute) {
68: final Attribute<?, ?> att = (Attribute<?, ?>) attribute;
69:• for (ParticipationConstraint pc : att.getConstraints()) {
70: validateParticipationConstraint(identifier, att.getJavaField(), valueCount, pc);
71: }
72:• if (att.getConstraints().length == 0) {
73: validateNonEmpty(identifier, att, valueCount);
74: }
75:• } else if (attribute instanceof QueryAttribute) {
76: final QueryAttribute<?, ?> queryAtt = (QueryAttribute<?, ?>) attribute;
77:• for (ParticipationConstraint pc : queryAtt.getConstraints()) {
78: validateParticipationConstraint(identifier, queryAtt.getJavaField(), valueCount, pc);
79: }
80: }
81: }
82:
83: private static int extractValueCount(Object value) {
84:• if (value == null || value instanceof LazyLoadingProxy<?>) {
85: return 0;
86: }
87:• return value instanceof Collection ? ((Collection<?>) value).size() : 1;
88: }
89:
90: private static void validateParticipationConstraint(Object id, Field field, int valueCount, ParticipationConstraint pc) {
91:• if (valueCount < pc.min()) {
92: throw new CardinalityConstraintViolatedException("At least " + pc.min() +
93: " values of attribute " + field.getDeclaringClass().getSimpleName() + "." + field.getName() +
94: " expected in instance " + id + ", but got only " + valueCount);
95: }
96:• if (pc.max() >= 0 && pc.max() < valueCount) {
97: throw new CardinalityConstraintViolatedException("At most " + pc.max() +
98: " values of attribute " + field.getDeclaringClass().getSimpleName() + "." + field.getName() +
99: " expected in instance " + id + ", but got " + valueCount);
100: }
101: }
102:
103: private static void validateNonEmpty(Object id, Field field, int valueCount, ParticipationConstraints constraints) {
104:• if (valueCount == 0 && constraints.nonEmpty()) {
105: throw nonEmptyError(id, field.getDeclaringClass().getSimpleName(), field.getName());
106: }
107: }
108:
109: private static CardinalityConstraintViolatedException nonEmptyError(Object id, String className, String fieldName) {
110: return new CardinalityConstraintViolatedException(
111: "Attribute " + className + "." + fieldName + " of instance " + id +
112: " was marked as nonEmpty, but contains no value.");
113: }
114:
115: private static void validateNonEmpty(Object id, Attribute<?, ?> attribute, int valueCount) {
116:• if (valueCount == 0 && attribute.isNonEmpty()) {
117: throw nonEmptyError(id, attribute.getDeclaringType().getJavaType().getSimpleName(), attribute.getName());
118: }
119: }
120: }