mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-11-15 14:56:41 +00:00
fixed parameterized type transitive lookup in NMEA AbstractSentenceListener
Change-Id: Iba08f867257a8ae707f8c1c8a11dae865da52c25
This commit is contained in:
1 parent
123777280d
commit
bcdc8a260c
2 files changed
+151
-117
No files matched your search
+112
-112
@@ -1,113 +1,113 @@
|
||||
package com.sap.sailing.nmeaconnector.test;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.common.Wind;
|
||||
import com.sap.sailing.nmeaconnector.NmeaFactory;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
import net.sf.marineapi.nmea.event.AbstractSentenceListener;
|
||||
import net.sf.marineapi.nmea.event.SentenceListener;
|
||||
import net.sf.marineapi.nmea.io.SentenceReader;
|
||||
import net.sf.marineapi.nmea.parser.DataNotAvailableException;
|
||||
import net.sf.marineapi.nmea.sentence.PositionSentence;
|
||||
import net.sf.marineapi.nmea.sentence.Sentence;
|
||||
import net.sf.marineapi.nmea.sentence.TimeSentence;
|
||||
import net.sf.marineapi.nmea.util.Position;
|
||||
import net.sf.marineapi.nmea.util.Time;
|
||||
|
||||
public class GeneralizedSentenceListenerTest {
|
||||
private SentenceReader sentenceReader;
|
||||
private SentenceReaderSupport readerSupport;
|
||||
|
||||
@Before
|
||||
public void setUp() throws FileNotFoundException {
|
||||
sentenceReader = new SentenceReader(new FileInputStream("resources/LogSS.txt"));
|
||||
readerSupport = new SentenceReaderSupport(sentenceReader);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegisterPositionListener() throws InterruptedException {
|
||||
final List<Position> positions = new ArrayList<>();
|
||||
SentenceListener positionListener = new AbstractSentenceListener<PositionSentence>() {
|
||||
@Override
|
||||
public void sentenceRead(PositionSentence sentence) {
|
||||
try {
|
||||
final Position position = sentence.getPosition();
|
||||
positions.add(position);
|
||||
} catch (DataNotAvailableException e) {
|
||||
// this can happen and simply means we don't have a position; so we
|
||||
// can safely ignore this exception
|
||||
}
|
||||
}
|
||||
};
|
||||
sentenceReader.addSentenceListener(positionListener);
|
||||
readerSupport.startReading();
|
||||
readerSupport.waitUntilAllMessagesHaveBeenRead();
|
||||
assertFalse(positions.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegisterTimeListener() throws InterruptedException {
|
||||
final List<Time> times = new ArrayList<>();
|
||||
SentenceListener timeListener = new AbstractSentenceListener<TimeSentence>() {
|
||||
@Override
|
||||
public void sentenceRead(TimeSentence sentence) {
|
||||
try {
|
||||
final Time time = sentence.getTime();
|
||||
times.add(time);
|
||||
} catch (DataNotAvailableException e) {
|
||||
// this can happen and simply means we don't have a position; so we
|
||||
// can safely ignore this exception
|
||||
}
|
||||
}
|
||||
};
|
||||
sentenceReader.addSentenceListener(timeListener);
|
||||
readerSupport.startReading();
|
||||
readerSupport.waitUntilAllMessagesHaveBeenRead();
|
||||
assertFalse(times.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleNmeaWindReceiverScenario() throws FileNotFoundException, InterruptedException {
|
||||
final Iterable<Wind> wind = NmeaFactory.INSTANCE.readWind(new FileInputStream("resources/LogSS.txt"));
|
||||
assertFalse(Util.isEmpty(wind));
|
||||
}
|
||||
|
||||
private static class MyGenericSentenceListener<A, B extends Sentence> extends AbstractSentenceListener<B> {
|
||||
private B lastSentence;
|
||||
|
||||
@Override
|
||||
public void sentenceRead(B sentence) {
|
||||
lastSentence = sentence;
|
||||
}
|
||||
|
||||
public B getLastSentence() {
|
||||
return lastSentence;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyOtherGenericSentenceListener<A> extends MyGenericSentenceListener<A, TimeSentence> {}
|
||||
|
||||
private static class MyConcreteSentenceListener extends MyOtherGenericSentenceListener<String> {}
|
||||
|
||||
private static class MyConcreteSentenceListenerSubclass extends MyConcreteSentenceListener {}
|
||||
|
||||
@Test
|
||||
public void testComplicatedGenericSentenceListenerSubclass() throws InterruptedException {
|
||||
MyConcreteSentenceListenerSubclass listener = new MyConcreteSentenceListenerSubclass();
|
||||
sentenceReader.addSentenceListener(listener);
|
||||
readerSupport.startReading();
|
||||
readerSupport.waitUntilAllMessagesHaveBeenRead();
|
||||
assertNotNull(listener.getLastSentence());
|
||||
}
|
||||
package com.sap.sailing.nmeaconnector.test;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.common.Wind;
|
||||
import com.sap.sailing.nmeaconnector.NmeaFactory;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
import net.sf.marineapi.nmea.event.AbstractSentenceListener;
|
||||
import net.sf.marineapi.nmea.event.SentenceListener;
|
||||
import net.sf.marineapi.nmea.io.SentenceReader;
|
||||
import net.sf.marineapi.nmea.parser.DataNotAvailableException;
|
||||
import net.sf.marineapi.nmea.sentence.PositionSentence;
|
||||
import net.sf.marineapi.nmea.sentence.Sentence;
|
||||
import net.sf.marineapi.nmea.sentence.TimeSentence;
|
||||
import net.sf.marineapi.nmea.util.Position;
|
||||
import net.sf.marineapi.nmea.util.Time;
|
||||
|
||||
public class GeneralizedSentenceListenerTest {
|
||||
private SentenceReader sentenceReader;
|
||||
private SentenceReaderSupport readerSupport;
|
||||
|
||||
@Before
|
||||
public void setUp() throws FileNotFoundException {
|
||||
sentenceReader = new SentenceReader(new FileInputStream("resources/LogSS.txt"));
|
||||
readerSupport = new SentenceReaderSupport(sentenceReader);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegisterPositionListener() throws InterruptedException {
|
||||
final List<Position> positions = new ArrayList<>();
|
||||
SentenceListener positionListener = new AbstractSentenceListener<PositionSentence>() {
|
||||
@Override
|
||||
public void sentenceRead(PositionSentence sentence) {
|
||||
try {
|
||||
final Position position = sentence.getPosition();
|
||||
positions.add(position);
|
||||
} catch (DataNotAvailableException e) {
|
||||
// this can happen and simply means we don't have a position; so we
|
||||
// can safely ignore this exception
|
||||
}
|
||||
}
|
||||
};
|
||||
sentenceReader.addSentenceListener(positionListener);
|
||||
readerSupport.startReading();
|
||||
readerSupport.waitUntilAllMessagesHaveBeenRead();
|
||||
assertFalse(positions.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegisterTimeListener() throws InterruptedException {
|
||||
final List<Time> times = new ArrayList<>();
|
||||
SentenceListener timeListener = new AbstractSentenceListener<TimeSentence>() {
|
||||
@Override
|
||||
public void sentenceRead(TimeSentence sentence) {
|
||||
try {
|
||||
final Time time = sentence.getTime();
|
||||
times.add(time);
|
||||
} catch (DataNotAvailableException e) {
|
||||
// this can happen and simply means we don't have a position; so we
|
||||
// can safely ignore this exception
|
||||
}
|
||||
}
|
||||
};
|
||||
sentenceReader.addSentenceListener(timeListener);
|
||||
readerSupport.startReading();
|
||||
readerSupport.waitUntilAllMessagesHaveBeenRead();
|
||||
assertFalse(times.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleNmeaWindReceiverScenario() throws FileNotFoundException, InterruptedException {
|
||||
final Iterable<Wind> wind = NmeaFactory.INSTANCE.readWind(new FileInputStream("resources/LogSS.txt"));
|
||||
assertFalse(Util.isEmpty(wind));
|
||||
}
|
||||
|
||||
private static class MyGenericSentenceListener<A, B extends Sentence> extends AbstractSentenceListener<B> {
|
||||
private B lastSentence;
|
||||
|
||||
@Override
|
||||
public void sentenceRead(B sentence) {
|
||||
lastSentence = sentence;
|
||||
}
|
||||
|
||||
public B getLastSentence() {
|
||||
return lastSentence;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyOtherGenericSentenceListener<A> extends MyGenericSentenceListener<A, TimeSentence> {}
|
||||
|
||||
private static class MyConcreteSentenceListener extends MyOtherGenericSentenceListener<String> {}
|
||||
|
||||
private static class MyConcreteSentenceListenerSubclass extends MyConcreteSentenceListener {}
|
||||
|
||||
@Test
|
||||
public void testComplicatedGenericSentenceListenerSubclass() throws InterruptedException {
|
||||
MyConcreteSentenceListenerSubclass listener = new MyConcreteSentenceListenerSubclass();
|
||||
sentenceReader.addSentenceListener(listener);
|
||||
readerSupport.startReading();
|
||||
readerSupport.waitUntilAllMessagesHaveBeenRead();
|
||||
assertNotNull(listener.getLastSentence());
|
||||
}
|
||||
}
|
||||
+39
-5
@@ -22,7 +22,10 @@ package net.sf.marineapi.nmea.event;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import net.sf.marineapi.nmea.sentence.Sentence;
|
||||
|
||||
@@ -48,13 +51,44 @@ public abstract class AbstractSentenceListener<T extends Sentence>
|
||||
private final Type expectedType;
|
||||
|
||||
public AbstractSentenceListener() {
|
||||
ParameterizedType superClass =
|
||||
(ParameterizedType) getClass().getGenericSuperclass();
|
||||
Type[] superClassTypeArgs = superClass.getActualTypeArguments();
|
||||
this.expectedType = superClassTypeArgs[0];
|
||||
// if during super class traversal we found a parameterized type we remember the
|
||||
// concrete parameter types that were used during the type instantiation keyed by
|
||||
// the type parameters
|
||||
final Map<TypeVariable<?>, Class<?>> concreteTypeForTypeVariable = new HashMap<>();
|
||||
ParameterizedType superClass = null;
|
||||
Class<?> c = getClass();
|
||||
while (superClass == null && c != null) {
|
||||
if (c.getGenericSuperclass() instanceof ParameterizedType) {
|
||||
final ParameterizedType pt = (ParameterizedType) c.getGenericSuperclass();
|
||||
if (pt.getRawType() == AbstractSentenceListener.class) {
|
||||
superClass = pt;
|
||||
} else {
|
||||
c = (Class<?>) pt.getRawType();
|
||||
int i=0;
|
||||
for (TypeVariable<?> tv : c.getTypeParameters()) {
|
||||
concreteTypeForTypeVariable.put(tv, resolve(pt.getActualTypeArguments()[i++], concreteTypeForTypeVariable));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
c = (c.getGenericSuperclass() instanceof Class<?>) ? (Class<?>) c.getGenericSuperclass() : null;
|
||||
}
|
||||
}
|
||||
assert superClass == null || superClass.getRawType() == AbstractSentenceListener.class;
|
||||
// we now assume that this class has exactly one type parameter [0] that is the expected type:
|
||||
this.expectedType = resolve(superClass.getActualTypeArguments()[0], concreteTypeForTypeVariable);
|
||||
}
|
||||
|
||||
/**
|
||||
private Class<?> resolve(Type type, Map<TypeVariable<?>, Class<?>> concreteTypeForTypeVariable) {
|
||||
if (type instanceof Class<?>) {
|
||||
return (Class<?>) type;
|
||||
} else if (type instanceof TypeVariable<?>) {
|
||||
return concreteTypeForTypeVariable.get((TypeVariable<?>) type);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty implementation.
|
||||
* @see net.sf.marineapi.nmea.event.SentenceListener#readingPaused()
|
||||
*/
|
||||
|
||||
Reference in new issue
Block a user