Skip to content

Commit

Permalink
add class 'ChannelFactory'
Browse files Browse the repository at this point in the history
  • Loading branch information
jrfeng committed Jun 21, 2020
1 parent 1fab359 commit 00f0794
Show file tree
Hide file tree
Showing 6 changed files with 168 additions and 10 deletions.
19 changes: 19 additions & 0 deletions .idea/compiler.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])

implementation project(path: ":helper")
implementation project(path: ":pipe")
annotationProcessor project(path: ":processor")

implementation 'androidx.appcompat:appcompat:1.1.0'
Expand Down
95 changes: 95 additions & 0 deletions app/src/androidTest/java/channel/helper/ChannelFactoryTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package channel.helper;

import android.os.HandlerThread;

import androidx.test.ext.junit.runners.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;

import static org.junit.Assert.*;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import channel.helper.pipe.HandlerPipe;
import channel.helper.test.Bar;

@RunWith(AndroidJUnit4.class)
public class ChannelFactoryTest {
@Test(timeout = 3000)
public void factoryTest() throws InterruptedException {
final String value = "Hello";

final CountDownLatch countDownLatch = new CountDownLatch(1);

Bar receiver = new Bar() {
@Override
public void noParam() {

}

@Override
public void byteParam(byte aByte) {

}

@Override
public void shortParam(short aShort) {

}

@Override
public void intParam(int aInt) {

}

@Override
public void longParam(long aLong) {

}

@Override
public void floatParam(float aFloat) {

}

@Override
public void doubleParam(double aDouble) {

}

@Override
public void stringParam(String aString) {
assertEquals(value, aString);
countDownLatch.countDown();
}

@Override
public void enumParam(TimeUnit aEnum1, TimeUnit aEnum2) {

}

@Override
public void manyParam(byte aByte, short aShort, int aInt, long aLong, float aFloat, double aDouble, String aString, TimeUnit aEnum1, TimeUnit aEnum2) {

}

@Override
public void extendsTest(String value) {

}
};

HandlerThread handlerThread = new HandlerThread("ChannelFactoryTest");
handlerThread.start();

Dispatcher barDispatcher = ChannelFactory.newDispatcher(Bar.class, receiver);
Bar emitter = ChannelFactory.newEmitter(Bar.class, new HandlerPipe(handlerThread.getLooper(), barDispatcher));

emitter.stringParam(value);

countDownLatch.await();
handlerThread.quit();
}
}
1 change: 1 addition & 0 deletions helper/src/main/java/channel/helper/Channel.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

@Target(ElementType.TYPE)
public @interface Channel {
@Deprecated
String name() default "";
String inspector() default "";
}
39 changes: 39 additions & 0 deletions helper/src/main/java/channel/helper/ChannelFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package channel.helper;

import java.lang.reflect.Constructor;

public class ChannelFactory {
private ChannelFactory() {
throw new AssertionError();
}

@SuppressWarnings("unchecked cast")
public static <T> T newEmitter(Class<T> clazz, Emitter pipe) {
String emitterName = clazz.getPackage().getName() + "."
+ clazz.getSimpleName()
+ "__ChannelWrapper$Emitter";

try {
Class<? extends T> emitter = (Class<? extends T>) Class.forName(emitterName);
Constructor<? extends T> constructor = emitter.getConstructor(Emitter.class);
return (T) constructor.newInstance(pipe);
} catch (Exception e) {
throw new IllegalStateException("emitter create failed", e);
}
}

@SuppressWarnings("unchecked cast")
public static <T> Dispatcher newDispatcher(Class<T> clazz, T receiver) {
String dispatcherName = clazz.getPackage().getName() + "."
+ clazz.getSimpleName()
+ "__ChannelWrapper$Dispatcher";

try {
Class<? extends Dispatcher> dispatcher = (Class<? extends Dispatcher>) Class.forName(dispatcherName);
Constructor<? extends Dispatcher> constructor = dispatcher.getConstructor(clazz);
return constructor.newInstance(receiver);
} catch (Exception e) {
throw new IllegalStateException("dispatcher create failed", e);
}
}
}
23 changes: 13 additions & 10 deletions processor/src/main/java/channel/processor/ChannelProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ private void buildChannelHelper(TypeElement targetInterface) {

List<Pair<String, ExecutableElement>> methodIdPairs = generateAllMethodId(methods);

TypeSpec channelWrapperType = buildChannelWrapper(channel.name(), targetInterface, methodIdPairs);
TypeSpec channelWrapperType = buildChannelWrapper(targetInterface, methodIdPairs);

writeJavaFile(channelWrapperType, targetInterface);
}
Expand Down Expand Up @@ -169,10 +169,8 @@ private List<Pair<String, ExecutableElement>> generateAllMethodId(List<Executabl
return methodIdPairs;
}

private TypeSpec buildChannelWrapper(String name, TypeElement targetInterface, List<Pair<String, ExecutableElement>> methodIdPairs) {
if ("".equals(name)) {
name = targetInterface.getSimpleName() + "Channel";
}
private TypeSpec buildChannelWrapper(TypeElement targetInterface, List<Pair<String, ExecutableElement>> methodIdPairs) {
String wrapperName = targetInterface.getSimpleName() + "__ChannelWrapper";

ClassName string = ClassName.get("java.lang", "String");
FieldSpec KEY_CLASS_NAME = FieldSpec.builder(string, FIELD_KEY_CLASS_NAME, Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL)
Expand All @@ -185,9 +183,14 @@ private TypeSpec buildChannelWrapper(String name, TypeElement targetInterface, L
.initializer("$S", targetInterface.getQualifiedName())
.build();

TypeSpec.Builder builder = TypeSpec.classBuilder(name)
.addMethod(MethodSpec.constructorBuilder().addModifiers(Modifier.PRIVATE).build())
.addModifiers(Modifier.PUBLIC)
// private default constructor
MethodSpec defaultConstructor = MethodSpec.constructorBuilder().addModifiers(Modifier.PRIVATE)
.addStatement("throw new AssertionError()")
.build();

TypeSpec.Builder builder = TypeSpec.classBuilder(wrapperName)
.addMethod(defaultConstructor)
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.addField(KEY_CLASS_NAME)
.addField(KEY_METHOD_ID)
.addField(CLASS_NAME)
Expand Down Expand Up @@ -217,7 +220,7 @@ private List<FieldSpec> generateMethodIdField(List<Pair<String, ExecutableElemen
private TypeSpec buildEmitter(TypeElement targetInterface, List<Pair<String, ExecutableElement>> methodIdPairs) {
TypeSpec.Builder builder = TypeSpec.classBuilder("Emitter")
.addSuperinterface(targetInterface.asType())
.addModifiers(Modifier.PUBLIC, Modifier.STATIC);
.addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL);

ClassName Emitter = ClassName.get(Emitter.class);

Expand Down Expand Up @@ -335,7 +338,7 @@ private TypeSpec buildDispatcher(TypeElement targetInterface, List<Pair<String,
// class: Dispatcher
TypeSpec.Builder builder = TypeSpec.classBuilder("Dispatcher")
.addSuperinterface(ClassName.get(Dispatcher.class))
.addModifiers(Modifier.PUBLIC, Modifier.STATIC);
.addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL);

// field
final String field_callbackWeakReference = "callbackWeakReference";
Expand Down

0 comments on commit 00f0794

Please sign in to comment.