Skip to content

Commit

Permalink
WIP method handle generation
Browse files Browse the repository at this point in the history
  • Loading branch information
jodastephen committed Jan 12, 2017
1 parent a5ecc55 commit ad7d61a
Show file tree
Hide file tree
Showing 14 changed files with 2,021 additions and 23 deletions.
6 changes: 3 additions & 3 deletions pom.xml
Expand Up @@ -599,9 +599,9 @@
<maven-surefire-report-plugin.version>2.18.1</maven-surefire-report-plugin.version>
<maven-toolchains-plugin.version>1.1</maven-toolchains-plugin.version>
<!-- Properties for maven-compiler-plugin -->
<maven.compiler.compilerVersion>1.6</maven.compiler.compilerVersion>
<maven.compiler.source>1.6</maven.compiler.source>
<maven.compiler.target>1.6</maven.compiler.target>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.fork>true</maven.compiler.fork>
<maven.compiler.verbose>true</maven.compiler.verbose>
<!-- Properties for maven-javadoc-plugin -->
Expand Down
14 changes: 11 additions & 3 deletions src/main/java/org/joda/beans/gen/BeanData.java
Expand Up @@ -165,7 +165,7 @@ public void setBeanStyle(String beanStyle) {
*/
public boolean isBeanStyleValid() {
return "full".equals(beanStyle) || "smart".equals(beanStyle) ||
"minimal".equals(beanStyle) || "light".equals(beanStyle);
"minimal".equals(beanStyle) || "light".equals(beanStyle) || "handle".equals(beanStyle);
}

/**
Expand All @@ -176,6 +176,14 @@ public boolean isBeanStyleLight() {
return "light".equals(beanStyle);
}

/**
* Is the bean style indicating that method handles should be used.
* @return the flag
*/
public boolean isBeanStyleHandle() {
return "handle".equals(beanStyle);
}

/**
* Is the bean style minimal.
* @return the flag
Expand Down Expand Up @@ -245,7 +253,7 @@ public String getEffectiveMetaScope() {
* @return the scope
*/
public boolean isMetaScopePrivate() {
return "private".equals(beanMetaScope) || isBeanStyleLight();
return "private".equals(beanMetaScope) || isBeanStyleLight() || isBeanStyleHandle();
}

//-----------------------------------------------------------------------
Expand Down Expand Up @@ -294,7 +302,7 @@ public String getEffectiveBuilderScope() {
*/
public boolean isEffectiveBuilderScopeVisible() {
return ("smart".equals(beanBuilderScope) || "public".equals(beanBuilderScope) || "package".equals(beanBuilderScope)) &&
!isBeanStyleLight();
!isBeanStyleLight() && !isBeanStyleHandle();
}

/**
Expand Down
69 changes: 57 additions & 12 deletions src/main/java/org/joda/beans/gen/BeanGen.java
Expand Up @@ -18,6 +18,9 @@
import java.beans.ConstructorProperties;
import java.beans.PropertyChangeSupport;
import java.io.File;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
Expand All @@ -39,6 +42,7 @@
import org.joda.beans.impl.direct.DirectFieldsBeanBuilder;
import org.joda.beans.impl.direct.DirectMetaBean;
import org.joda.beans.impl.direct.DirectMetaPropertyMap;
import org.joda.beans.impl.handle.HandleMetaBean;
import org.joda.beans.impl.light.LightMetaBean;

/**
Expand Down Expand Up @@ -317,7 +321,8 @@ private void generateBuilderBasedConstructor() {

private void generateArgBasedConstructor() {
if (data.getConstructorStyle() == CONSTRUCTOR_BY_ARGS && data.getImmutableConstructor() == CONSTRUCTOR_NONE &&
((data.isMutable() && (data.isBuilderScopeVisible() || data.isBeanStyleLight())) || data.isImmutable())) {
((data.isMutable() && (data.isBuilderScopeVisible() || data.isBeanStyleLight() || data.isBeanStyleHandle())) ||
data.isImmutable())) {
String scope = data.getEffectiveConstructorScope();
boolean generateAnnotation = data.isConstructorPropertiesAnnotation();
boolean generateJavadoc = !"private ".equals(scope);
Expand Down Expand Up @@ -361,7 +366,7 @@ private void generateArgBasedConstructor() {
insertRegion.add("\t\t\t" + prop.getBuilderType() + " " + prop.getData().getPropertyName() + (i < nonDerived.size() - 1 ? "," : ") {"));
}
// validate (mutable light beans call setters which validate)
if (!(data.isMutable() && data.isBeanStyleLight())) {
if (!(data.isMutable() && (data.isBeanStyleLight() || data.isBeanStyleHandle()))) {
for (PropertyGen prop : properties) {
if (prop.getData().isValidated()) {
insertRegion.add("\t\t" + prop.getData().getValidationMethodName() +
Expand All @@ -373,7 +378,7 @@ private void generateArgBasedConstructor() {
// assign
for (int i = 0; i < nonDerived.size(); i++) {
PropertyGen prop = nonDerived.get(i);
if (data.isMutable() && data.isBeanStyleLight()) {
if (data.isMutable() && (data.isBeanStyleLight() || data.isBeanStyleHandle())) {
String generateSetInvoke = prop.getData().getSetterGen().generateSetInvoke(
prop.getData(), prop.getData().getPropertyName());
insertRegion.add("\t\t" + generateSetInvoke + ";");
Expand All @@ -392,13 +397,53 @@ private void generateArgBasedConstructor() {

//-----------------------------------------------------------------------
private void generateMeta() {
if (data.isBeanStyleLight()) {
if (data.isBeanStyleLight() || data.isBeanStyleHandle()) {
data.ensureImport(MetaBean.class);
data.ensureImport(LightMetaBean.class);
insertRegion.add("\t/**");
insertRegion.add("\t * The meta-bean for {@code " + data.getTypeRaw() + "}.");
insertRegion.add("\t */");
insertRegion.add("\tprivate static MetaBean META_BEAN = LightMetaBean.of(" + data.getTypeRaw() + ".class);");
if (data.isBeanStyleLight()) {
data.ensureImport(LightMetaBean.class);
insertRegion.add("\t/**");
insertRegion.add("\t * The meta-bean for {@code " + data.getTypeRaw() + "}.");
insertRegion.add("\t */");
insertRegion.add("\tprivate static final MetaBean META_BEAN = LightMetaBean.of(" + data.getTypeRaw() + ".class);");
} else {
data.ensureImport(HandleMetaBean.class);
data.ensureImport(MethodHandle.class);
data.ensureImport(MethodHandles.class);
data.ensureImport(MethodType.class);
insertRegion.add("\t/**");
insertRegion.add("\t * The constructor method handle.");
insertRegion.add("\t */");
insertRegion.add("\tprivate static final MethodHandle CONSTRUCTOR_HANDLE =");
insertRegion.add("\t\t\tHandleMetaBean.findConstructorHandle(" +
data.getTypeRaw() + ".class, MethodHandles.lookup());");

// insertRegion.add("\tprivate static final MethodHandle CONSTRUCTOR_HANDLE;");
// insertRegion.add("\tstatic {");
// insertRegion.add("\t\ttry {");
// insertRegion.add("\t\t\tCONSTRUCTOR_HANDLE = MethodHandles.lookup().findConstructor(");
// insertRegion.add("\t\t\t\t\t" + data.getTypeRaw() + ".class,");
// insertRegion.add("\t\t\t\t\tMethodType.methodType(");
// List<PropertyGen> nonDerived = nonDerivedProperties();
// if (nonDerived.size() == 0) {
// insertRegion.add("\t\t\t\t\t\t\tvoid.class));");
// } else {
// insertRegion.add("\t\t\t\t\t\t\tvoid.class,");
// for (int i = 0; i < nonDerived.size(); i++) {
// PropertyGen prop = nonDerived.get(i);
// insertRegion.add("\t\t\t\t\t\t\t" + prop.getData().getBuilderType() + ".class" +
// (i == nonDerived.size() - 1 ? "));" : ","));
// }
// }
// insertRegion.add("\t\t} catch (NoSuchMethodException | IllegalAccessException ex) {");
// insertRegion.add("\t\t\tthrow new IllegalStateException(\"Unexpected error: \" + ex.getMessage(), ex);");
// insertRegion.add("\t\t}");
// insertRegion.add("\t}");
insertRegion.add("\t/**");
insertRegion.add("\t * The meta-bean for {@code " + data.getTypeRaw() + "}.");
insertRegion.add("\t */");
insertRegion.add("\tprivate static final MetaBean META_BEAN =");
insertRegion.add("\t\t\tHandleMetaBean.of(" + data.getTypeRaw() + ".class, MethodHandles.lookup(), CONSTRUCTOR_HANDLE);");
}
insertRegion.add("");
insertRegion.add("\t/**");
insertRegion.add("\t * The meta-bean for {@code " + data.getTypeRaw() + "}.");
Expand Down Expand Up @@ -527,7 +572,7 @@ private void generateMetaBean() {
data.ensureImport(MetaBean.class);
insertRegion.add("\t@Override");
insertRegion.add("\tpublic MetaBean metaBean() {");
if (data.isBeanStyleLight()) {
if (data.isBeanStyleLight() || data.isBeanStyleHandle()) {
insertRegion.add("\t\treturn META_BEAN;");
} else {
insertRegion.add("\t\treturn " + data.getTypeRaw() + ".Meta.INSTANCE;");
Expand Down Expand Up @@ -802,7 +847,7 @@ private String toStringFieldAccessor(PropertyGen prop) {

//-----------------------------------------------------------------------
private void generateMetaClass() {
if (data.isBeanStyleLight()) {
if (data.isBeanStyleLight() || data.isBeanStyleHandle()) {
return;
}
generateSeparator();
Expand Down Expand Up @@ -1045,7 +1090,7 @@ private void generateMetaValidate() {

//-----------------------------------------------------------------------
private void generateBuilderClass() {
if ((data.isMutable() && data.isBuilderScopeVisible() == false) || data.isBeanStyleLight()) {
if ((data.isMutable() && data.isBuilderScopeVisible() == false) || data.isBeanStyleLight() || data.isBeanStyleHandle()) {
return;
}
List<PropertyGen> nonDerived = nonDerivedProperties();
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/joda/beans/gen/BeanParser.java
Expand Up @@ -186,7 +186,7 @@ BeanGen parse() {
data.setConstructorStyle(CONSTRUCTOR_BY_BUILDER);
}
} else {
if (data.isBeanStyleLight()) {
if (data.isBeanStyleLight() || data.isBeanStyleHandle()) {
data.setConstructorStyle(CONSTRUCTOR_BY_ARGS);
} else {
data.setConstructorStyle(CONSTRUCTOR_BY_BUILDER);
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/joda/beans/gen/PropertyData.java
Expand Up @@ -882,7 +882,7 @@ public CopyGen getCopyGen() {
*/
public void resolveBuilderGen() {
if (getBean().isMutable()) {
if (!getBean().isBuilderScopeVisible() && !getBean().isBeanStyleLight()) {
if (!getBean().isBuilderScopeVisible() && !getBean().isBeanStyleLight() && !getBean().isBeanStyleHandle()) {
return; // no builder
}
}
Expand Down
114 changes: 114 additions & 0 deletions src/main/java/org/joda/beans/impl/handle/HandleBeanBuilder.java
@@ -0,0 +1,114 @@
/*
* Copyright 2001-2017 Stephen Colebourne
*
* 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.joda.beans.impl.handle;

import java.util.Map;
import java.util.Map.Entry;

import org.joda.beans.Bean;
import org.joda.beans.BeanBuilder;
import org.joda.beans.JodaBeanUtils;
import org.joda.beans.MetaProperty;

/**
* Implementation of {@code BeanBuilder} that builds light beans.
*
* @author Stephen Colebourne
* @param <B> the bean type
*/
class HandleBeanBuilder<B extends Bean>
implements BeanBuilder<B> {

/** The meta-bean. */
private final HandleMetaBean<B> metaBean;
/** The data. */
private final Object[] data;

//-----------------------------------------------------------------------
/**
* Constructs the builder wrapping the target bean.
*
* @param metaBean the target meta-bean, not null
*/
HandleBeanBuilder(HandleMetaBean<B> metaBean, Object[] data) {
this.metaBean = metaBean;
this.data = data;
}

//-----------------------------------------------------------------------
@Override
public Object get(String propertyName) {
return get(metaBean.metaProperty(propertyName));
}

@Override
public Object get(MetaProperty<?> metaProperty) {
return data[index(metaProperty)];
}

//-----------------------------------------------------------------------
@Override
public BeanBuilder<B> set(String propertyName, Object value) {
return set(metaBean.metaProperty(propertyName), value);
}

@Override
public BeanBuilder<B> set(MetaProperty<?> metaProperty, Object value) {
data[index(metaProperty)] = value;
return this;
}

@Override
public BeanBuilder<B> setString(String propertyName, String value) {
return setString(metaBean.metaProperty(propertyName), value);
}

@Override
public BeanBuilder<B> setString(MetaProperty<?> metaProperty, String value) {
Object object = JodaBeanUtils.stringConverter().convertFromString(metaProperty.propertyType(), value);
return set(metaProperty, object);
}

@Override
public BeanBuilder<B> setAll(Map<String, ? extends Object> propertyValueMap) {
for (Entry<String, ? extends Object> entry : propertyValueMap.entrySet()) {
set(entry.getKey(), entry.getValue());
}
return this;
}

private int index(MetaProperty<?> metaProperty) {
return ((HandleMetaProperty<?>) metaProperty).getConstructorIndex();
}

//-----------------------------------------------------------------------
@Override
public B build() {
return metaBean.build(data);
}

//-----------------------------------------------------------------------
/**
* Returns a string that summarises the builder.
*
* @return a summary string, not null
*/
@Override
public String toString() {
return "BeanBuilder for " + metaBean.beanName();
}

}

0 comments on commit ad7d61a

Please sign in to comment.