private static Method getSetter(Class<?> clazz, StateField field) { try { return clazz.getMethod(field.getSetterName(), field.getType()); } catch (NoSuchMethodException e) { throw Throwables.propagate(e); } }
/** Computes the size in bytes that this state will occupy, when serialized as a Slice */ private static int serializedSizeOf(Class<?> stateClass) { List<StateField> fields = enumerateFields(stateClass); int size = 0; for (StateField field : fields) { size += field.sizeOfType(); } return size; }
/** Computes the byte offset to store this field at, when serializing it to a Slice */ private static int offsetOfField(StateField targetField, List<StateField> fields) { int offset = 0; for (StateField field : fields) { if (targetField.getName().equals(field.getName())) { break; } offset += field.sizeOfType(); } return offset; }
private static FieldDefinition generateGroupedField( ClassDefinition definition, Block constructor, Block ensureCapacity, StateField stateField) { Class<?> bigArrayType = getBigArrayType(stateField.getType()); FieldDefinition field = definition.declareField( a(PRIVATE), UPPER_CAMEL.to(LOWER_CAMEL, stateField.getName()) + "Values", bigArrayType); // Generate getter definition .declareMethod(a(PUBLIC), stateField.getGetterName(), type(stateField.getType())) .getBody() .comment("return field.get(getGroupId());") .pushThis() .getField(field) .pushThis() .invokeVirtual(AbstractGroupedAccumulatorState.class, "getGroupId", long.class) .invokeVirtual(bigArrayType, "get", stateField.getType(), long.class) .ret(stateField.getType()); // Generate setter definition .declareMethod( a(PUBLIC), stateField.getSetterName(), type(void.class), arg("value", stateField.getType())) .getBody() .comment("return field.set(getGroupId(), value);") .pushThis() .getField(field) .pushThis() .invokeVirtual(AbstractGroupedAccumulatorState.class, "getGroupId", long.class) .getVariable("value") .invokeVirtual(bigArrayType, "set", void.class, long.class, stateField.getType()) .ret(); ensureCapacity .pushThis() .getField(field) .getVariable("size") .invokeVirtual(field.getType(), "ensureCapacity", type(void.class), type(long.class)); // Initialize field in constructor constructor.pushThis().newObject(field.getType()).dup(); pushInitialValue(constructor, stateField); constructor.invokeConstructor(field.getType(), type(stateField.getType())); constructor.putField(field); return field; }
private static void pushInitialValue(Block block, StateField stateField) { Object initialValue = stateField.getInitialValue(); if (initialValue != null) { if (initialValue instanceof Number) { block.push((Number) initialValue); } else if (initialValue instanceof Boolean) { block.push((boolean) initialValue); } else { throw new IllegalArgumentException( "Unsupported initial value type: " + initialValue.getClass()); } } else { block.pushJavaDefault(stateField.getType()); } }
private static void generateField( ClassDefinition definition, Block constructor, StateField stateField) { FieldDefinition field = definition.declareField( a(PRIVATE), UPPER_CAMEL.to(LOWER_CAMEL, stateField.getName()) + "Value", stateField.getType()); // Generate getter definition .declareMethod(a(PUBLIC), stateField.getGetterName(), type(stateField.getType())) .getBody() .pushThis() .getField(field) .ret(stateField.getType()); // Generate setter definition .declareMethod( a(PUBLIC), stateField.getSetterName(), type(void.class), arg("value", stateField.getType())) .getBody() .pushThis() .getVariable("value") .putField(field) .ret(); constructor.pushThis(); pushInitialValue(constructor, stateField); constructor.putField(field); }
private static void checkInterface(Class<?> clazz, List<StateField> fields) { checkArgument(clazz.isInterface(), clazz.getName() + " is not an interface"); Set<String> setters = new HashSet<>(); Set<String> getters = new HashSet<>(); Set<String> isGetters = new HashSet<>(); Map<String, Class<?>> fieldTypes = new HashMap<>(); for (StateField field : fields) { fieldTypes.put(field.getName(), field.getType()); } for (Method method : clazz.getMethods()) { if (method.getName().equals("getEstimatedSize")) { checkArgument( method.getReturnType().equals(long.class), "getEstimatedSize must return long"); checkArgument( method.getParameterTypes().length == 0, "getEstimatedSize may not have parameters"); continue; } if (method.getName().startsWith("get")) { String name = method.getName().substring(3); checkArgument( fieldTypes.get(name).equals(method.getReturnType()), "Expected %s to return type %s, but found %s", method.getName(), fieldTypes.get(name), method.getReturnType()); checkArgument( method.getParameterTypes().length == 0, "Expected %s to have zero parameters", method.getName()); getters.add(name); } else if (method.getName().startsWith("is")) { String name = method.getName().substring(2); checkArgument( fieldTypes.get(name) == boolean.class, "Expected %s to have type boolean, but found %s", name, fieldTypes.get(name)); checkArgument( method.getParameterTypes().length == 0, "Expected %s to have zero parameters", method.getName()); checkArgument( method.getReturnType() == boolean.class, "Expected %s to return boolean", method.getName()); isGetters.add(name); } else if (method.getName().startsWith("set")) { String name = method.getName().substring(3); checkArgument( method.getParameterTypes().length == 1, "Expected setter to have one parameter"); checkArgument( fieldTypes.get(name).equals(method.getParameterTypes()[0]), "Expected %s to accept type %s, but found %s", method.getName(), fieldTypes.get(name), method.getParameterTypes()[0]); checkArgument( getInitialValue(method) == null, "initial value annotation not allowed on setter"); checkArgument( method.getReturnType().equals(void.class), "%s may not return a value", method.getName()); setters.add(name); } else { throw new IllegalArgumentException( "Cannot generate implementation for method: " + method.getName()); } } checkArgument( getters.size() + isGetters.size() == setters.size() && setters.size() == fields.size(), "Wrong number of getters/setters"); }