com.google.gwtorm.server.CodeGenSupport.java Source code

Java tutorial

Introduction

Here is the source code for com.google.gwtorm.server.CodeGenSupport.java

Source

// Copyright 2008 Google Inc.
//
// 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.google.gwtorm.server;

import com.google.gwtorm.schema.ColumnModel;

import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;

import java.lang.reflect.Method;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

public class CodeGenSupport implements Opcodes {
    public final MethodVisitor mv;
    private ColumnModel col;
    private int dupOnSet;
    private int columnIdx;
    private Type entityType;

    private int lastLocal = 2;
    private List<Integer> freeLocals = new ArrayList<Integer>(4);

    public CodeGenSupport(final MethodVisitor method) {
        mv = method;
    }

    public void push(final int val) {
        switch (val) {
        case -1:
            mv.visitInsn(ICONST_M1);
            break;
        case 0:
            mv.visitInsn(ICONST_0);
            break;
        case 1:
            mv.visitInsn(ICONST_1);
            break;
        case 2:
            mv.visitInsn(ICONST_2);
            break;
        case 3:
            mv.visitInsn(ICONST_3);
            break;
        case 4:
            mv.visitInsn(ICONST_4);
            break;
        case 5:
            mv.visitInsn(ICONST_5);
            break;
        default:
            if (Byte.MIN_VALUE >= val && val < Byte.MAX_VALUE) {
                mv.visitIntInsn(BIPUSH, val);
            } else if (Short.MIN_VALUE >= val && val < Short.MAX_VALUE) {
                mv.visitIntInsn(SIPUSH, val);
            } else {
                mv.visitLdcInsn(Integer.valueOf(val));
            }
            break;
        }
    }

    public void loadVar(final Type type, final int index) {
        mv.visitVarInsn(type.getOpcode(ILOAD), index);
    }

    public int newLocal() {
        if (freeLocals.isEmpty()) {
            return ++lastLocal;
        }
        return freeLocals.remove(freeLocals.size() - 1);
    }

    public void freeLocal(final int index) {
        freeLocals.add(index);
    }

    public void setEntityType(final Type et) {
        entityType = et;
    }

    public void setFieldReference(final ColumnModel cm) {
        col = cm;
        dupOnSet = -1;
        columnIdx++;
    }

    public void resetColumnIndex(final int s) {
        columnIdx = s;
    }

    public int getColumnIndex() {
        return columnIdx;
    }

    public ColumnModel getFieldReference() {
        return col;
    }

    public void pushSqlHandle() {
        mv.visitVarInsn(ALOAD, 1);
    }

    public void pushEntity() {
        mv.visitVarInsn(ALOAD, 2);
    }

    public void pushColumnIndex() {
        push(columnIdx);
    }

    public void invokePreparedStatementSet(final String sqlTypeName) {
        final Method m;
        try {
            m = PreparedStatement.class.getMethod("set" + sqlTypeName, Integer.TYPE,
                    ResultSet.class.getMethod("get" + sqlTypeName, Integer.TYPE).getReturnType());
        } catch (SecurityException e) {
            throw new RuntimeException("java.sql has no " + sqlTypeName);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException("java.sql has no " + sqlTypeName, e);
        }
        mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(PreparedStatement.class), m.getName(),
                Type.getMethodDescriptor(m));
    }

    public void invokeResultSetGet(final String sqlTypeName) {
        final Method m;
        try {
            m = ResultSet.class.getMethod("get" + sqlTypeName, Integer.TYPE);
        } catch (SecurityException e) {
            throw new RuntimeException("java.sql has no " + sqlTypeName);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException("java.sql has no " + sqlTypeName, e);
        }
        mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(ResultSet.class), m.getName(),
                Type.getMethodDescriptor(m));
    }

    public void fieldSetBegin() {
        pushEntity();
        if (col.getParent() != null) {
            appendGetField(col.getParent());
        }
    }

    public void fieldSetEnd() {
        final Type c = containerClass(col);
        if (dupOnSet >= 0) {
            mv.visitInsn(DUP);
            mv.visitVarInsn(ASTORE, dupOnSet);
        }
        mv.visitFieldInsn(PUTFIELD, c.getInternalName(), col.getFieldName(), toType(col).getDescriptor());
    }

    public void setDupOnFieldSetEnd(final int varIdx) {
        dupOnSet = varIdx;
    }

    public void pushFieldValue() {
        pushEntity();
        appendGetField(col);
    }

    protected void appendGetField(final ColumnModel c) {
        if (c.getParent() != null) {
            appendGetField(c.getParent());
        }
        final Type t = containerClass(c);
        mv.visitFieldInsn(GETFIELD, t.getInternalName(), c.getFieldName(), toType(c).getDescriptor());
    }

    private Type containerClass(final ColumnModel c) {
        if (c.getParent() == null) {
            return entityType;
        }
        final String n = c.getParent().getNestedClassName();
        return Type.getObjectType(n.replace('.', '/'));
    }

    public static Type toType(final ColumnModel c) {
        if (c.isSqlPrimitive()) {
            return Type.getType(c.getPrimitiveType());
        }
        return Type.getObjectType(c.getNestedClassName().replace('.', '/'));
    }
}