//
// MessagePack for Java
//
// Copyright (C) 2009 - 2013 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package org.msgpack.template.builder;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.msgpack.MessageTypeException;
import org.msgpack.packer.Packer;
import org.msgpack.template.PackerTemplate;
import org.msgpack.template.AbstractPackerTemplate;
import org.msgpack.template.AbstractUnpackerTemplate;
import org.msgpack.template.TemplateRegistry;
import org.msgpack.template.UnpackerTemplate;
import org.msgpack.unpacker.Unpacker;
@SuppressWarnings({ "rawtypes", "unchecked" })
public class ReflectionTemplateBuilder extends AbstractTemplateBuilder {
private static Logger LOG = Logger.getLogger(ReflectionBeansTemplateBuilder.class.getName());
protected static abstract class ReflectionFieldPackerTemplate extends AbstractPackerTemplate<Object> {
protected FieldEntry entry;
ReflectionFieldPackerTemplate(final FieldEntry entry) {
this.entry = entry;
}
void setNil(Object v) {
entry.set(v, null);
}
}
static final class FieldPackerTemplateImpl extends ReflectionFieldPackerTemplate {
private PackerTemplate packerTemplate;
public FieldPackerTemplateImpl(final FieldEntry entry, final PackerTemplate packerTemplate) {
super(entry);
this.packerTemplate = packerTemplate;
}
@Override
public void write(Packer packer, Object v, boolean required)
throws IOException {
packerTemplate.write(packer, v, required);
}
}
protected static abstract class ReflectionFieldUnpackerTemplate extends AbstractUnpackerTemplate<Object> {
protected FieldEntry entry;
ReflectionFieldUnpackerTemplate(final FieldEntry entry) {
this.entry = entry;
}
void setNil(Object v) {
entry.set(v, null);
}
}
static final class FieldUnpackerTemplateImpl extends
ReflectionFieldUnpackerTemplate {
private UnpackerTemplate unpackerTemplate;
public FieldUnpackerTemplateImpl(final FieldEntry entry,
final UnpackerTemplate unpackerTemplate) {
super(entry);
this.unpackerTemplate = unpackerTemplate;
}
@Override
public Object read(Unpacker unpacker, Object to, boolean required)
throws IOException {
// Class<Object> type = (Class<Object>) entry.getType();
Object f = entry.get(to);
Object o = unpackerTemplate.read(unpacker, f, required);
if (o != f) {
entry.set(to, o);
}
return o;
}
}
protected static class ReflectionClassPackerTemplate<T> extends
AbstractPackerTemplate<T> {
protected Class<T> targetClass;
protected ReflectionFieldPackerTemplate[] packerTemplates;
protected ReflectionClassPackerTemplate(Class<T> targetClass,
ReflectionFieldPackerTemplate[] packerTemplates) {
this.targetClass = targetClass;
this.packerTemplates = packerTemplates;
}
@Override
public void write(Packer packer, T target, boolean required)
throws IOException {
if (target == null) {
if (required) {
throw new MessageTypeException("attempted to write null");
}
packer.writeNil();
return;
}
try {
packer.writeArrayHeader(packerTemplates.length);
for (ReflectionFieldPackerTemplate tmpl : packerTemplates) {
if (!tmpl.entry.isAvailable()) {
packer.writeNil();
continue;
}
Object obj = tmpl.entry.get(target);
if (obj == null) {
if (tmpl.entry.isNotNullable()) {
throw new MessageTypeException(tmpl.entry.getName()
+ " cannot be null by @NotNullable");
}
packer.writeNil();
} else {
tmpl.write(packer, obj, true);
}
}
} catch (IOException e) {
throw e;
} catch (Exception e) {
throw new MessageTypeException(e);
}
}
}
protected static class ReflectionClassUnpackerTemplate<T> extends
AbstractUnpackerTemplate<T> {
protected Class<T> targetClass;
protected ReflectionFieldUnpackerTemplate[] unpackerTemplates;
protected ReflectionClassUnpackerTemplate(Class<T> targetClass,
ReflectionFieldUnpackerTemplate[] unpackerTemplates) {
this.targetClass = targetClass;
this.unpackerTemplates = unpackerTemplates;
}
@Override
public T read(Unpacker unpacker, T to, boolean required)
throws IOException {
if (!required && unpacker.trySkipNil()) {
return null;
}
try {
if (to == null) {
to = targetClass.newInstance();
}
unpacker.readArrayHeader();
for (int i = 0; i < unpackerTemplates.length; i++) {
ReflectionFieldUnpackerTemplate tmpl = unpackerTemplates[i];
if (!tmpl.entry.isAvailable()) {
unpacker.skip();
} else if (tmpl.entry.isOptional() && unpacker.trySkipNil()) {
// if Optional + nil, than keep default value
} else {
tmpl.read(unpacker, to, false);
}
}
return to;
} catch (IOException e) {
throw e;
} catch (Exception e) {
throw new MessageTypeException(e);
}
}
}
public ReflectionTemplateBuilder(TemplateRegistry registry) {
super(registry);
}
@Override
public boolean matchType(Type targetType, boolean hasAnnotation) {
Class<?> targetClass = (Class<?>) targetType;
boolean matched = matchAtClassTemplateBuilder(targetClass, hasAnnotation);
if (matched && LOG.isLoggable(Level.FINE)) {
LOG.fine("matched type: " + targetClass.getName());
}
return matched;
}
@Override
public <T> PackerTemplate<T> buildPackerTemplate(Class<T> targetClass, FieldEntry[] entries) {
if (entries == null) {
throw new NullPointerException("entries is null: " + targetClass);
}
ReflectionFieldPackerTemplate[] packerTemplates = toPackerTemplates(entries);
return new ReflectionClassPackerTemplate<T>(targetClass, packerTemplates);
}
protected ReflectionFieldPackerTemplate[] toPackerTemplates(
FieldEntry[] entries) {
// TODO Now it is simply cast. #SF
for (FieldEntry entry : entries) {
Field field = ((DefaultFieldEntry) entry).getField();
int mod = field.getModifiers();
if (!Modifier.isPublic(mod)) {
field.setAccessible(true);
}
}
ReflectionFieldPackerTemplate[] packerTemplates = new ReflectionFieldPackerTemplate[entries.length];
for (int i = 0; i < entries.length; i++) {
FieldEntry entry = entries[i];
// Class<?> t = entry.getType();
PackerTemplate packerTemplate = registry.lookupPackerTemplate(entry
.getGenericType());
packerTemplates[i] = new FieldPackerTemplateImpl(entry,
packerTemplate);
}
return packerTemplates;
}
@Override
public <T> UnpackerTemplate<T> buildUnpackerTemplate(Class<T> targetClass,
FieldEntry[] entries) {
if (entries == null) {
throw new NullPointerException("entries is null: " + targetClass);
}
ReflectionFieldUnpackerTemplate[] unpackerTemplates = toUnpackerTemplates(entries);
return new ReflectionClassUnpackerTemplate<T>(targetClass,
unpackerTemplates);
}
protected ReflectionFieldUnpackerTemplate[] toUnpackerTemplates(
FieldEntry[] entries) {
// TODO Now it is simply cast. #SF
for (FieldEntry entry : entries) {
Field field = ((DefaultFieldEntry) entry).getField();
int mod = field.getModifiers();
if (!Modifier.isPublic(mod)) {
field.setAccessible(true);
}
}
ReflectionFieldUnpackerTemplate[] unpackerTemplates = new ReflectionFieldUnpackerTemplate[entries.length];
for (int i = 0; i < entries.length; i++) {
FieldEntry entry = entries[i];
// Class<?> t = entry.getType();
UnpackerTemplate unpackerTemplate = registry
.lookupUnpackerTemplate(entry.getGenericType());
unpackerTemplates[i] = new FieldUnpackerTemplateImpl(entry,
unpackerTemplate);
}
return unpackerTemplates;
}
}