Package com.mysema.query.collections

Source Code of com.mysema.query.collections.CollQuerySerializer

/*
* Copyright 2011, Mysema Ltd
*
* 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 com.mysema.query.collections;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.primitives.Primitives;
import com.mysema.query.QueryException;
import com.mysema.query.codegen.Serializer;
import com.mysema.query.support.SerializerBase;
import com.mysema.query.types.Constant;
import com.mysema.query.types.Expression;
import com.mysema.query.types.FactoryExpression;
import com.mysema.query.types.Operator;
import com.mysema.query.types.Ops;
import com.mysema.query.types.Path;
import com.mysema.query.types.PathType;
import com.mysema.query.types.SubQueryExpression;
import com.mysema.query.types.Template;

/**
* CollQuerySerializer is a {@link Serializer} implementation for the Java language
*
* @author tiwe
*/
public final class CollQuerySerializer extends SerializerBase<CollQuerySerializer> {

    private static final Set<Class<?>> WRAPPER_TYPES = ImmutableSet.copyOf(Primitives.allWrapperTypes());
   
    private static final Map<Operator<?>, String> OPERATOR_SYMBOLS = Maps.newIdentityHashMap();
   
    private static final Map<Class<?>, String> CAST_SUFFIXES = Maps.newHashMap();
   
    static {
        OPERATOR_SYMBOLS.put(Ops.EQ, " == ");
        OPERATOR_SYMBOLS.put(Ops.NE, " != ");
        OPERATOR_SYMBOLS.put(Ops.GT, " > ");
        OPERATOR_SYMBOLS.put(Ops.LT, " < ");
        OPERATOR_SYMBOLS.put(Ops.GOE, " >= ");
        OPERATOR_SYMBOLS.put(Ops.LOE, " <= ");
       
        OPERATOR_SYMBOLS.put(Ops.ADD, " + ");
        OPERATOR_SYMBOLS.put(Ops.SUB, " - ");
        OPERATOR_SYMBOLS.put(Ops.MULT, " * ");
        OPERATOR_SYMBOLS.put(Ops.DIV, " / ");
       
        CAST_SUFFIXES.put(Boolean.class, ".booleanValue()");
        CAST_SUFFIXES.put(Byte.class, ".byteValue()");
        CAST_SUFFIXES.put(Character.class, ".charValue()");
        CAST_SUFFIXES.put(Double.class, ".doubleValue()");
        CAST_SUFFIXES.put(Float.class, ".floatValue()");
        CAST_SUFFIXES.put(Integer.class, ".intValue()");
        CAST_SUFFIXES.put(Long.class, ".longValue()");
        CAST_SUFFIXES.put(Short.class, ".shortValue()");
        CAST_SUFFIXES.put(String.class, ".toString()");
    }
   
    public CollQuerySerializer(CollQueryTemplates templates) {
        super(templates);
    }

    @Override
    public Void visit(Path<?> path, Void context) {
        final PathType pathType = path.getMetadata().getPathType();
        if (pathType == PathType.PROPERTY) {
            final Path<?> parent = path.getMetadata().getParent();
            final String property = path.getMetadata().getName();     
            final Class<?> parentType = parent.getType();
            try {
                // getter
                Method m = getAccessor(parentType, property);
                if (m != null && Modifier.isPublic(m.getModifiers())) {                   
                    handle(parent);
                    append(".").append(m.getName()).append("()");   
                } else {
                    // field
                    Field f = getField(parentType, property);
                    if (f != null && Modifier.isPublic(f.getModifiers())) {
                        handle(parent);
                        append(".").append(property);
                    } else {
                        // field access by reflection
                        append(CollQueryFunctions.class.getName() + ".<");
                        append(((Class)path.getType()).getName()).append(">get(");
                        handle(parent);
                        append(", \""+property+"\")");
                    }
                }               
            } catch (Exception e) {
                throw new QueryException(e);
            }
           
        } else if (pathType == PathType.DELEGATE) {
            append("(");
            append("(").append(path.getType().getName()).append(")");
            path.getMetadata().getParent().accept(this, context);
            append(")");

        } else {
            List<Object> args = new ArrayList<Object>(2);
            if (path.getMetadata().getParent() != null) {
                args.add((Expression<?>)path.getMetadata().getParent());
            }
            args.add(path.getMetadata().getElement());
            final Template template = getTemplate(pathType);
            for (Template.Element element : template.getElements()) {
                Object rv = element.convert(args);
                if (rv instanceof Expression) {                   
                    ((Expression)rv).accept(this, context);
                } else if (element.isString()) {   
                    append(rv.toString());
                } else {
                    visitConstant(rv);
                }
            }
        }
        return null;

    }
   
    private Method getAccessor(Class<?> owner, String property) {
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(owner);
            PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
            for(PropertyDescriptor pd : descriptors) {
                if(pd.getName().equals(property)) {
                    return pd.getReadMethod();
                }
            }
            return null;
        } catch (IntrospectionException e) {
            return null;
        }       
    }

    private Field getField(Class<?> owner, String field) {
        try {
            return owner.getField(field);
        } catch (NoSuchFieldException e) {
            return null;
        }
    }
   
    @Override
    public Void visit(SubQueryExpression<?> expr, Void context) {
        throw new IllegalArgumentException("Not supported");
    }

    private void visitCast(Operator<?> operator, Expression<?> source, Class<?> targetType) {
        if (Number.class.isAssignableFrom(source.getType()) && !Constant.class.isInstance(source)) {
            append("new ").append(source.getType().getSimpleName()).append("(");
            handle(source);
            append(")");
        } else {
            handle(source);
        }
       
        if (CAST_SUFFIXES.containsKey(targetType)) {
            append(CAST_SUFFIXES.get(targetType));
        } else {
            throw new IllegalArgumentException("Unsupported cast type " + targetType.getName());
        }
    }

    @Override
    protected void visitOperation(Class<?> type, Operator<?> operator, List<? extends Expression<?>> args) {
        if (Ops.aggOps.contains(operator)) {
            throw new UnsupportedOperationException("Aggregation operators are only supported as single expressions");
        }
        if (args.size() == 2 && OPERATOR_SYMBOLS.containsKey(operator)
             && isPrimitive(args.get(0).getType()) && isPrimitive(args.get(1).getType())) {
            handle(args.get(0));
            append(OPERATOR_SYMBOLS.get(operator));
            handle(args.get(1));
            if (args.get(1) instanceof Constant) {
                append(CAST_SUFFIXES.get(args.get(1).getType()));
            }
            return;
        }
       
        if (operator == Ops.STRING_CAST) {
            visitCast(operator, args.get(0), String.class);
        } else if (operator == Ops.NUMCAST) {
            visitCast(operator, args.get(0), (Class<?>) ((Constant<?>) args.get(1)).getConstant());
        } else {
            super.visitOperation(type, operator, args);
        }
    }
   
    private static boolean isPrimitive(Class<?> type) {
        return type.isPrimitive() || WRAPPER_TYPES.contains(type);
    }

    @Override
    public Void visit(FactoryExpression<?> expr, Void context) {
        visitConstant(expr);
        append(".newInstance(");
        handle(", ", expr.getArgs());
        append(")");
        return null;
    }

}
TOP

Related Classes of com.mysema.query.collections.CollQuerySerializer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.