Есть у нас с одной стороны Java, с другой стороны Erlang (и его библиотеки для инетрфейса с Java'ой).
Со стороны Java String, со стороны Erlang'а — OtpErlangString.
Со стороны Java Integer, со стороны Erlang'а — OtpErlangInt.
ну и т.п.
То есть для передачи чего-то там в Erlang нужно делать что-то типа:
String s = "text";
OtpeErlangString s1 = new OtpErlangString(s);
// куда-то там передаем
На простейших объектах и когда оно делается ручками, оно все понятно. Но хочется слегка автоматизировать процесс То есть если у нас есть
ArrayList arr = new ArrayList();
arr.add("aaa");
arr.add(123);
ArrayList arr2 = new ArrayList();
arr2.add(new ArrayList());
arr.add(arr);
то хочется магического:
ErlangObject eo = new ErlangObject(arr); // из примера выше
eo.get(); // Получем OtpErlangObject, соедржащий OtpErlangList,
// в котором есть OtpErlangString, OtpErlangInt
// еще один OtpErlangList и т.п.
Если смотреть на задачу в целом то: написать реализацию на эрланге для protobuf http://code.google.com/p/protobuf/ ? Или найти готовую (хотя я сомневаюсь что оно есть для эрланга).
Впрочем если куски данных гоняются большие (скажем пара мегабайт), то про protobuf можно сразу забыть.
M>А если мне все это дело захочется расширить? Например, унаследоваться от этого класса и добавить для сериализации новые типы?
M>В общем, куда копать
public interface Converter {
Set<Class<?>> getSupportedClasses();
<I, O> O convert(I in) throws IllegalArgumentException;
}
public abstract class AbstractErlangJavaConverter<J, E> implements Converter {
private final Set<Class<?>> classes = new HashSet<Class<?>>();
private final Class<J> javaClass;
private final Class<E> erlangClass;
protected AbstractErlangJavaConverter(Class<J> javaClass, Class<E> erlangClass) {
this.classes.add(javaClass);
this.classes.add(erlangClass);
this.javaClass = javaClass;
this.erlangClass = erlangClass;
}
@Override
public Set<Class<?>> getSupportedClasses() {
return classes;
}
@SuppressWarnings("unchecked")
@Override
public <I, O> convert(I in) throws IllegalArgumentException {
Class<?> argClass = in.getClass();
// Exact match.if (argClass == javaClass) {
return fromJava((J)in);
} else if (argClass == erlangClass()) {
return fromErlang((E)in);
}
// IS-A match.if (javaClass.isAssignableFrom(argClass)) {
return fromJava((J)in)
} else if (erlangClass.isAssignableFrom(argClass)) {
return fromErlang((E)in);
}
throw new IllegalArgumentException(/* describe supported arguments and given one */)
}
protected abstract E fromJava(J in);
protected abstract J fromErlang(E in);
}
public class BooleanConverter extends AbstractErlangJavaConverter<Boolean, OtpErlangBoolean> {
public BooleanConverter() {
super(Boolean.class, OtpErlangBoolean.class);
}
public OtpErlangBoolean fromJava(Boolean b) {
return OtpErlangBoolean((Boolean)object);
}
public Boolean toJava(OtpErlangBoolean b) {
// ...
}
}
...
public class ConversionManager {
private final Map<Class<?>, Converter<?, ?>> converters = new HashMap<>();
@SuppressWarnings("unchecked")
public <I, O> O convert(I in) throws IllegalArgumentException {
// Try exact match.
Converter<I, O> converter = (Converter<I, O>)converters.get(in.getClass());
if (converter != null {
return converter.convert(in);
}
// Try IS-A match.for (Map.Entry<Class<?>, Converter<?, ?>> entry : converters.entrySet()) {
if (entry.getKey().isAssignableFrom(in.getClass()) {
return (O)entry.getValue().convert(in);
}
}
throw new IllegalArgumentException(/* describe supported arguments and given one */)
}
//@Autowiredpublic void register(Converter<?, ?> ... converters) {
for (Converter<?, ?> converter: converters) {
for (Class<?> clazz : converter.getSupportedClasses()) {
if (converters.contains(clazz)) {
// handle
}
converters.put(clazz, converter);
}
}
}
}
Т.е. основная идея — разделить движок и стратегии конвертирования. При этом для обобщенного конвертирования со стороны джавы можно использовать рефлекшн, т.е. если во время выполнения ConversionManager.convert() не найдено подходящего конвертера, можно делегировать этому обобщенному.
K>Если смотреть на задачу в целом то: написать реализацию на эрланге для protobuf http://code.google.com/p/protobuf/ ? Или найти готовую (хотя я сомневаюсь что оно есть для эрланга).
K>Впрочем если куски данных гоняются большие (скажем пара мегабайт), то про protobuf можно сразу забыть.
Не, через промежуточный слой, конечно, можно, но не хочется
DZ>Т.е. основная идея — разделить движок и стратегии конвертирования. При этом для обобщенного конвертирования со стороны джавы можно использовать рефлекшн, т.е. если во время выполнения ConversionManager.convert() не найдено подходящего конвертера, можно делегировать этому обобщенному.
То, что общий опыт в Java у меня около недели не способствует скорейшему разруливанию ситуации
Возникли вопросы. Вопросы в коде
public class ConversionManager {
// на все Converter<?, ?> : Converter does not have type parameters // при замене на AbstractErlangJavaConverter<?, ?> возникают ошибки ниже private final Map<Class<?>, Converter<?, ?>> converters = new HashMap<>();
@SuppressWarnings("unchecked")
public <I, O> O convert(I in) throws IllegalArgumentException {
// Try exact match.
Converter<I, O> converter = (Converter<I, O>)converters.get(in.getClass());
if (converter != null {
//type parameters of <O>O cannot be determined; no unique maximal instance exists
//for type variable O with upper bounds O,java.lang.Objectreturn converter.convert(in);
}
// Try IS-A match.for (Map.Entry<Class<?>, Converter<?, ?>> entry : converters.entrySet()) {
if (entry.getKey().isAssignableFrom(in.getClass()) {
return (O)entry.getValue().convert(in);
}
}
throw new IllegalArgumentException(/* describe supported arguments and given one */)
}
//@Autowiredpublic void register(Converter<?, ?> ... converters) {
for (Converter<?, ?> converter: converters) {
for (Class<?> clazz : converter.getSupportedClasses()) {
//cannot find symbol method contains(java.lang.Class<capture#138 of ?>)if (converters.contains(clazz)) {
// handle
}
converters.put(clazz, converter);
}
}
}
}
Здравствуйте, Mamut, Вы писали:
M>То, что общий опыт в Java у меня около недели не способствует скорейшему разруливанию ситуации
M>Возникли вопросы. Вопросы в коде
Сорри, писал не в ide, не проверял на компилабельность.
Этот код компилируется под java6:
public interface Converter {
Set<Class<?>> getSupportedClasses();
<I, O> O convert(I in) throws IllegalArgumentException;
}
public abstract class AbstractErlangJavaConverter<J, E> implements Converter {
private final Set<Class<?>> classes = new HashSet<Class<?>>();
private final Class<J> javaClass;
private final Class<E> erlangClass;
protected AbstractErlangJavaConverter(Class<J> javaClass, Class<E> erlangClass) {
this.classes.add(javaClass);
this.classes.add(erlangClass);
this.javaClass = javaClass;
this.erlangClass = erlangClass;
}
@Override
public Set<Class<?>> getSupportedClasses() {
return classes;
}
@SuppressWarnings("unchecked")
@Override
public <I, O> O convert(I in) throws IllegalArgumentException {
Class<?> argClass = in.getClass();
// Exact match.if (argClass == javaClass) {
return (O) fromJava((J)in);
} else if (argClass == erlangClass) {
return (O) fromErlang((E)in);
}
// IS-A match.if (javaClass.isAssignableFrom(argClass)) {
return (O) fromJava((J)in);
} else if (erlangClass.isAssignableFrom(argClass)) {
return (O) fromErlang((E)in);
}
throw new IllegalArgumentException(/* describe supported arguments and given one */);
}
protected abstract E fromJava(J in);
protected abstract J fromErlang(E in);
}
public class BooleanConverter extends AbstractErlangJavaConverter<Boolean, OtpErlangBoolean> {
public BooleanConverter() {
super(Boolean.class, OtpErlangBoolean.class);
}
public OtpErlangBoolean fromJava(Boolean b) {
//TODO implementreturn null;
}
@Override
protected Boolean fromErlang(OtpErlangBoolean in) {
//TODO implementreturn null;
}
}
public class ConversionManager {
private final Map<Class<?>, Converter> converters = new HashMap<Class<?>, Converter>();
@SuppressWarnings("unchecked")
public <I, O> O convert(I in) throws IllegalArgumentException {
// Try exact match.
Converter converter = converters.get(in.getClass());
if (converter != null) {
return converter.<I, O>convert(in);
}
// Try IS-A match.for (Map.Entry<Class<?>, Converter> entry : converters.entrySet()) {
if (entry.getKey().isAssignableFrom(in.getClass())) {
return (O)entry.getValue().convert(in);
}
}
throw new IllegalArgumentException(/* describe supported arguments and given one */);
}
//@Autowiredpublic void register(Converter ... converters) {
for (Converter converter: converters) {
for (Class<?> clazz : converter.getSupportedClasses()) {
if (this.converters.containsKey(clazz)) {
// handle
}
this.converters.put(clazz, converter);
}
}
}
}
Здравствуйте, denis.zhdanov, Вы писали:
DZ>Здравствуйте, Mamut, Вы писали:
M>>То, что общий опыт в Java у меня около недели не способствует скорейшему разруливанию ситуации
M>>Возникли вопросы. Вопросы в коде
DZ>Сорри, писал не в ide, не проверял на компилабельность.
DZ>Этот код компилируется под java6:
public abstract class AbstractErlangJavaConverter<J, E> implements Converter {
private final Set<Class<?>> classes = new HashSet<Class<?>>();
private final Class<J> javaClass;
private final Class<E> erlangClass;
protected AbstractErlangJavaConverter(Class<J> javaClass, Class<E> erlangClass) {
this.classes.add(javaClass);
this.classes.add(erlangClass);
this.javaClass = javaClass;
this.erlangClass = erlangClass;
}
...
(на правах саморекламы) — можно не заставлять передавать в конструктор объекты Class явно — их можно выводить в рантайм — тыц
Здравствуйте, denis.zhdanov, Вы писали:
DZ>Здравствуйте, Mamut, Вы писали:
M>>То, что общий опыт в Java у меня около недели не способствует скорейшему разруливанию ситуации
M>>Возникли вопросы. Вопросы в коде
DZ>Сорри, писал не в ide, не проверял на компилабельность.