Skip to content

Commit 0011cd2

Browse files
committed
Add exceptions hierarchy
1 parent 2028d20 commit 0011cd2

21 files changed

Lines changed: 448 additions & 48 deletions

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
1313
- Add EPMD server.
1414
- Add more unit and integration tests.
1515

16+
## [0.1.0](https://github.com/appulse-projects/epmd-java/releases/tag/0.1.0) - 2018-01-29
17+
18+
### Added
19+
20+
- Serialization/Deserialization exceptions in `Core`.
21+
22+
### Changed
23+
24+
- Fixed `RegistrationResult` length (it doesn't have this by spec).
25+
1626
## [0.0.2](https://github.com/appulse-projects/epmd-java/releases/tag/0.0.2) - 2018-01-28
1727

1828
### Changed

core/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ limitations under the License.
2525
<parent>
2626
<groupId>io.appulse</groupId>
2727
<artifactId>epmd-java</artifactId>
28-
<version>0.0.2</version>
28+
<version>0.1.0</version>
2929
</parent>
3030

3131
<groupId>io.appulse.epmd.java</groupId>

core/src/main/java/io/appulse/epmd/java/core/mapper/deserializer/DataDeserializer.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package io.appulse.epmd.java.core.mapper.deserializer;
1818

1919
import io.appulse.epmd.java.core.mapper.DataSerializable;
20+
import io.appulse.epmd.java.core.mapper.deserializer.exception.DeserializationException;
2021
import io.appulse.utils.Bytes;
2122

2223
/**
@@ -27,8 +28,13 @@
2728
class DataDeserializer implements Deserializer {
2829

2930
@Override
30-
public <T> T deserialize (Bytes bytes, Class<T> type) throws Exception {
31-
T result = type.newInstance();
31+
public <T> T deserialize (Bytes bytes, Class<T> type) throws DeserializationException {
32+
T result;
33+
try {
34+
result = type.newInstance();
35+
} catch (IllegalAccessException | InstantiationException ex) {
36+
throw new DeserializationException(ex);
37+
}
3238
((DataSerializable) result).read(bytes);
3339
return result;
3440
}

core/src/main/java/io/appulse/epmd/java/core/mapper/deserializer/Deserializer.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package io.appulse.epmd.java.core.mapper.deserializer;
1818

19+
import io.appulse.epmd.java.core.mapper.deserializer.exception.DeserializationException;
1920
import io.appulse.utils.Bytes;
2021

2122
/**
@@ -25,7 +26,7 @@
2526
*/
2627
interface Deserializer {
2728

28-
<T> T deserialize (Bytes buffer, Class<T> type) throws Exception;
29+
<T> T deserialize (Bytes buffer, Class<T> type) throws DeserializationException;
2930

3031
boolean isApplicable (Class<?> type);
3132
}

core/src/main/java/io/appulse/epmd/java/core/mapper/deserializer/EnumDeserializer.java

Lines changed: 45 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,22 @@
1818

1919
import static java.nio.charset.StandardCharsets.ISO_8859_1;
2020
import static java.util.Arrays.asList;
21+
import static java.util.Optional.empty;
22+
import static java.util.Optional.ofNullable;
2123

24+
import java.lang.reflect.InvocationTargetException;
2225
import java.lang.reflect.Method;
2326
import java.lang.reflect.Modifier;
24-
2527
import java.util.Collections;
2628
import java.util.HashSet;
2729
import java.util.Optional;
2830
import java.util.Set;
2931
import java.util.stream.Stream;
3032

33+
import io.appulse.epmd.java.core.mapper.deserializer.exception.DeserializationException;
34+
import io.appulse.epmd.java.core.mapper.deserializer.exception.EnumUnknownValueException;
3135
import io.appulse.utils.Bytes;
3236

33-
import lombok.val;
34-
3537
/**
3638
*
3739
* @author Artem Labazin
@@ -57,44 +59,62 @@ class EnumDeserializer implements Deserializer {
5759

5860
@Override
5961
@SuppressWarnings("unchecked")
60-
public <T> T deserialize (Bytes bytes, Class<T> type) throws Exception {
61-
val string = bytes.getString(ISO_8859_1);
62-
63-
val constants = type.getEnumConstants();
64-
Optional<Object> constant = Stream.of(constants)
65-
.map(it -> (Enum<?>) it)
66-
.filter(it -> it.name().equals(string))
67-
.findAny()
68-
.map(it -> (Object) it);
62+
public <T> T deserialize (Bytes bytes, Class<T> type) throws DeserializationException {
63+
String string = bytes.getString(ISO_8859_1);
64+
T[] constants = type.getEnumConstants();
6965

66+
Optional<Object> constant = findConstant(constants, string);
7067
if (constant.isPresent()) {
7168
return (T) constant.get();
7269
}
7370

74-
Optional<Method> optional = Stream.of(type.getDeclaredMethods())
75-
.filter(it -> Modifier.isStatic(it.getModifiers()))
76-
.filter(it -> Modifier.isPublic(it.getModifiers()))
77-
.filter(it -> it.getParameterCount() == 1)
78-
.filter(it -> it.getParameterTypes()[0] == String.class)
79-
.filter(it -> it.getReturnType() == type)
80-
.filter(it -> ENUM_CREATE_METHODS_NAMES.contains(it.getName()))
81-
.findAny();
82-
83-
if (optional.isPresent()) {
84-
Method method = optional.get();
85-
return (T) method.invoke(null, string);
71+
Optional<Object> methodResult = getByMethod(type, string);
72+
if (methodResult.isPresent()) {
73+
return (T) methodResult.get();
8674
}
8775

8876
Optional<T> undefined = Stream.of(constants)
8977
.filter(it -> ENUM_UNKNOWN_VALUE.contains(it.toString()))
9078
.findAny();
9179

9280
return undefined
93-
.orElseThrow(() -> new RuntimeException("Unknown enum value " + string));
81+
.orElseThrow(() -> new EnumUnknownValueException(string));
9482
}
9583

9684
@Override
9785
public boolean isApplicable (Class<?> type) {
9886
return type.isEnum();
9987
}
88+
89+
private Optional<Object> findConstant (Object[] constants, String string) {
90+
return Stream.of(constants)
91+
.map(it -> (Enum<?>) it)
92+
.filter(it -> it.name().equals(string))
93+
.findAny()
94+
.map(it -> (Object) it);
95+
}
96+
97+
private Optional<Object> getByMethod (Class<?> type, String string) {
98+
Optional<Method> optional = Stream.of(type.getDeclaredMethods())
99+
.filter(it -> Modifier.isStatic(it.getModifiers()))
100+
.filter(it -> Modifier.isPublic(it.getModifiers()))
101+
.filter(it -> it.getParameterCount() == 1)
102+
.filter(it -> it.getParameterTypes()[0] == String.class)
103+
.filter(it -> it.getReturnType() == type)
104+
.filter(it -> ENUM_CREATE_METHODS_NAMES.contains(it.getName()))
105+
.findAny();
106+
107+
if (!optional.isPresent()) {
108+
return empty();
109+
}
110+
111+
Method method = optional.get();
112+
Object result = null;
113+
try {
114+
result = method.invoke(null, string);
115+
} catch (IllegalAccessException | InvocationTargetException ex) {
116+
throw new DeserializationException(ex);
117+
}
118+
return ofNullable(result);
119+
}
100120
}

core/src/main/java/io/appulse/epmd/java/core/mapper/deserializer/MessageDeserializer.java

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
import java.util.List;
2525

2626
import io.appulse.epmd.java.core.mapper.Message;
27+
import io.appulse.epmd.java.core.mapper.deserializer.exception.InvalidReceivedMessageLengthException;
28+
import io.appulse.epmd.java.core.mapper.deserializer.exception.InvalidReceivedMessageTagException;
29+
import io.appulse.epmd.java.core.mapper.deserializer.exception.NoApplicableDeserializerException;
30+
import io.appulse.epmd.java.core.mapper.exception.MessageAnnotationMissingException;
2731
import io.appulse.epmd.java.core.model.Tag;
2832
import io.appulse.utils.Bytes;
2933

@@ -50,24 +54,34 @@ public final class MessageDeserializer {
5054
public <T> T deserialize (byte[] bytes, Class<T> type) {
5155
val buffer = ofNullable(bytes)
5256
.map(Bytes::wrap)
53-
.orElseThrow(RuntimeException::new);
57+
.orElseThrow(NullPointerException::new);
5458

5559
val annotation = ofNullable(type)
5660
.map(it -> it.getAnnotation(Message.class))
57-
.orElseThrow(RuntimeException::new);
61+
.orElseThrow(MessageAnnotationMissingException::new);
5862

59-
val lengthBytes = annotation.lengthBytes();
60-
if (lengthBytes > 0 && asInteger(buffer.getBytes(lengthBytes)) != buffer.remaining()) {
61-
throw new RuntimeException();
63+
if (annotation.lengthBytes() > 0) {
64+
val receivedMessageLength = asInteger(buffer.getBytes(annotation.lengthBytes()));
65+
if (receivedMessageLength != buffer.remaining()) {
66+
val message = String.format("Expected length is %d - %d bytes, but actual length is %d bytes.",
67+
annotation.lengthBytes(), receivedMessageLength, buffer.remaining());
68+
throw new InvalidReceivedMessageLengthException(message);
69+
}
6270
}
63-
if (annotation.value() != UNDEFINED && annotation.value() != Tag.of(buffer.getByte())) {
64-
throw new RuntimeException();
71+
72+
if (annotation.value() != UNDEFINED) {
73+
val tag = Tag.of(buffer.getByte());
74+
if (annotation.value() != tag) {
75+
val message = String.format("Expected tag is: %s, but actual tag is: %s",
76+
annotation.value(), tag);
77+
throw new InvalidReceivedMessageTagException(message);
78+
}
6579
}
6680

6781
return DESERIALIZERS.stream()
6882
.filter(it -> it.isApplicable(type))
6983
.findAny()
70-
.orElseThrow(RuntimeException::new)
84+
.orElseThrow(NoApplicableDeserializerException::new)
7185
.deserialize(buffer, type);
7286
}
7387
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright 2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.appulse.epmd.java.core.mapper.deserializer.exception;
18+
19+
/**
20+
*
21+
* @author Artem Labazin
22+
* @since 0.1.0
23+
*/
24+
public class DeserializationException extends RuntimeException {
25+
26+
private static final long serialVersionUID = -6918027649527350593L;
27+
28+
public DeserializationException () {
29+
super();
30+
}
31+
32+
public DeserializationException (String message) {
33+
super(message);
34+
}
35+
36+
public DeserializationException (String message, Throwable cause) {
37+
super(message, cause);
38+
}
39+
40+
public DeserializationException (Throwable cause) {
41+
super(cause);
42+
}
43+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright 2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.appulse.epmd.java.core.mapper.deserializer.exception;
18+
19+
/**
20+
*
21+
* @author Artem Labazin
22+
* @since 0.1.0
23+
*/
24+
public class EnumUnknownValueException extends DeserializationException {
25+
26+
private static final long serialVersionUID = 1696232532905750930L;
27+
28+
public EnumUnknownValueException () {
29+
super();
30+
}
31+
32+
public EnumUnknownValueException (String message) {
33+
super(message);
34+
}
35+
36+
public EnumUnknownValueException (String message, Throwable cause) {
37+
super(message, cause);
38+
}
39+
40+
public EnumUnknownValueException (Throwable cause) {
41+
super(cause);
42+
}
43+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright 2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.appulse.epmd.java.core.mapper.deserializer.exception;
18+
19+
/**
20+
*
21+
* @author Artem Labazin
22+
* @since 0.1.0
23+
*/
24+
public class InvalidReceivedMessageLengthException extends DeserializationException {
25+
26+
private static final long serialVersionUID = 1625435783124656623L;
27+
28+
public InvalidReceivedMessageLengthException () {
29+
super();
30+
}
31+
32+
public InvalidReceivedMessageLengthException (String message) {
33+
super(message);
34+
}
35+
36+
public InvalidReceivedMessageLengthException (String message, Throwable cause) {
37+
super(message, cause);
38+
}
39+
40+
public InvalidReceivedMessageLengthException (Throwable cause) {
41+
super(cause);
42+
}
43+
}

0 commit comments

Comments
 (0)