Skip to content
This repository has been archived by the owner on Mar 7, 2024. It is now read-only.

Commit

Permalink
added more exampes and helpful isX methods on types + fixed bug where…
Browse files Browse the repository at this point in the history
… guards was not generated for arrays
  • Loading branch information
mmc41 committed Oct 29, 2014
1 parent 6a01d4d commit 2b068b4
Show file tree
Hide file tree
Showing 19 changed files with 285 additions and 28 deletions.
13 changes: 12 additions & 1 deletion DOWNLOADS.md
Expand Up @@ -2,7 +2,7 @@

# Downloads

The <abbr title="Value Java Object Generator">VALJOGen</abbr> distribution can be used with maven by using the following dependency
The <abbr title="Value Java Object Generator">VALJOGen</abbr> distribution can be used with maven by using the following dependency:

```Xml
<dependency>
Expand All @@ -13,6 +13,17 @@ The <abbr title="Value Java Object Generator">VALJOGen</abbr> distribution can b
</dependency>
```

and/or the dependency:

```Xml
<dependency>
<groupId>com.41concepts</groupId>
<artifactId>valjogen-annotations</artifactId>
<version>1.0.0-RC4</version>
<optional>true</optional>
</dependency>
```

or you can download the following distribution files manually:

+ [valjogen-annotationprocessor-1.0.0-RC4.jar](http://search.maven.org/remotecontent?filepath=com/41concepts/valjogen-annotationprocessor/1.0.0-RC4/valjogen-annotationprocessor-1.0.0-RC4.jar)
Expand Down
6 changes: 6 additions & 0 deletions GETSTARTED.md
Expand Up @@ -26,12 +26,18 @@ public interface SimpleInterfaceWithNamedOutput

Refer to the [collection of examples along with their generated output](http://valjogen.41concepts.com/examples.html) for output and the full list of examples.

<a name="important-start"/>

**Advice:**

- It is generally a good idea if you structure your project in multiple modules with your interfaces in a module by itself. You can then use the VALJOGen annotation processor to produce output in the first stage only of a multistage build. Thus you will not have to re-generate the implementation objects unless needed. This saves time and makes it easier to work with generated code.
- Do **not** change the code of the generated classes manually. Instead update the interface, customize and rebuild using the annotation processor to regenerated output with changes.
- Do **not** (normally) check-in generated code in your source repository. If you use git you can configure the .gitignore file for this.

<br/>*In addtion, make sure output directory is empty when running the annotation processor. Some javac versions are fragile and might give an exception <code>java.lang.IllegalStateException: endPosTable already set</code> if you forgot to clean output directories before running the processor.*

<a name="important-end"/>

<a name="jumbotron-end"/>

## 1. Using VALJOGen processor with Maven:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -48,10 +48,10 @@ The VALJOGen annotationprocessor may be used with any standard-complient JDK1.8+
Contributors and contributions are welcome. [Refer to the contribution guide](CONTRIBUTING.md).

## 4. KNOWN ISSUES:
- Sometimes javac will fail with "java.lang.IllegalStateException: endPosTable already set" - in particular if the output directory is not empty. I suspect this is an error in the JDK but I do not know. If it happens clean(!) to remove existing ouputs, rebuild and it should succed.
- Maven does not always detect correctly when to rebuild after changes in templates. Do a `"mvn clean"` if this happens.
- Generated code only get the correct method parameter names if you add the "-parameters" option to javac.
- Support for XML/JSON serialization should be easier.
- Very rarely javac will fail compiling the integration tests with "java.lang.IllegalStateException: endPosTable already set". I suspect this is an error in the JDK but I do not know. If it happens clean(!) and rebuild and it should succed.
- Generator does not account for bounded generic type arguments when deciding if something is serializable or comparable.
- Due to [Eclipse bug 382590][eclipsebug] VALJOGen can not generated correct code when subclassing a generic interface. Please [vote for the bug in bugzilla][eclipsebug] to help get it fixed.

Expand Down
@@ -0,0 +1,31 @@
/*
* Copyright (C) 2014 41concepts Aps
*/
package com.fortyoneconcepts.valjogen.examples;

import com.fortyoneconcepts.valjogen.annotations.VALJOConfigure;
import com.fortyoneconcepts.valjogen.annotations.VALJOGenerate;

/**
* Example that shows a non-trivial custom template implementing an advanced custom method that calculate a digest of object state.
* The generated class is set to inherit from a base class that provide both contract and helper methods.
* The example also shows how to make the generated mutable class thread safe.
*/
@VALJOGenerate(comment="Example 13")
@VALJOConfigure(customJavaTemplateFileName="advanced_custom_method.stg", baseClazzName="DigestBaseClass", synchronizedAccessEnabled=true)
public interface AdvancedCustomDigestMethod
{
public String getName();
public void setName(String name);

public int getAge();
public void setAge(int age);

public String[] getAddress();
public void setAddress(String[] address);

public boolean isVerified();
public void setVerified(boolean verified);

// Custom method calculateDigest declared in base class.
}
@@ -0,0 +1,18 @@
/*
* Copyright (C) 2014 41concepts Aps
*/
package com.fortyoneconcepts.valjogen.examples;

import com.fortyoneconcepts.valjogen.annotations.VALJOConfigure;
import com.fortyoneconcepts.valjogen.annotations.VALJOGenerate;

/**
* Example that shows how to apply a simple custom template to provide constructor logging by overriding existing regions.
*/
@VALJOGenerate(comment="Example 10")
@VALJOConfigure(customJavaTemplateFileName="custom_logging.stg", synchronizedAccessEnabled=true)
public interface CustomLogginngWithRegions
{
public String getName();
public void setName(String name);
}
@@ -0,0 +1,38 @@
package com.fortyoneconcepts.valjogen.examples;

/**
* Example of a preexisting abstract base class that a generated class can extend from.
*
* In this case the bease class both specifies an abstract method that the
* generated class must implement (using custom templates) as well as
* helper methods useful for calculating digests. Helper methods using overloading
* like here can makes custom templates much simpler to write.
*
* Used by the "AdvancedCustomDigestMethod.java" example and its assoicated template "advanced_custom_method.stg".
*
* Note that the current set of getBytes methods only handle a subset of types such as bytes, integers,
* strings and arrays of those types. For a real implementation, one should overload with additional
* getBytes methods.
*/
public abstract class DigestBaseClass
{
// Will be implemented by a custom template specified in the interface for the example.
public abstract byte[] calculateDigest(String algorithm) throws java.security.NoSuchAlgorithmException;

protected static final byte getBytes(boolean v) {
return v ? (byte)1 : (byte)0;
}

protected static final byte[] getBytes(int v) {
return new byte[] {
(byte)((v >> 24) & 0xff),
(byte)((v >> 16) & 0xff),
(byte)((v >> 8) & 0xff),
(byte)((v >> 0) & 0xff),
};
}

protected static final byte[] getBytes(String v) {
return v.getBytes();
}
}
Expand Up @@ -7,15 +7,16 @@
import com.fortyoneconcepts.valjogen.annotations.VALJOGenerate;

/**
* Example that shows how to apply a custom template implementing a custom method.
* Example that shows how to apply a basic custom template implementing a simple custom method. A custom method that can tell when a property was last changed.
* Example also shows how to make the generated mutable class thread safe.
*/
@VALJOGenerate(comment="Example 11")
@VALJOConfigure(customJavaTemplateFileName="custom_method.stg", synchronizedAccessEnabled=true)
public interface CustomMethod
@VALJOConfigure(customJavaTemplateFileName="simple_custom_method.stg", synchronizedAccessEnabled=true)
public interface SimpleCustomMethod
{
public String getName();
public void setName(String name);

// Custom method here:
public long nanoLastUpdated();
}
@@ -0,0 +1,62 @@
/*
* Copyright (C) 2014 41concepts Aps
*/
/**
* This custom template shows how to implement a non-trivial custom method declared in the interface that iterate through all members of the class.
*
* The custom template for the new custom method must have a specific name of "method_"+specifier and the template must be configured by
* the VALJOConfigure annotation. See javadoc on VALJOConfigure#customJavaTemplateFileName for details about this. Also refer to
* javadocs in the com.fortyoneconcepts.valjogen.model packakge for template arguments clazz of type Clazz and method of type Method.
*
* The digest implementation iterates though all class members (fields) and calls update methods on a digester before returning the digest. Note,
* how the abstract base class in this example supplies helper methods to get byte arrays from member values.
*/

@class.imports() ::= <<
<! Add our log class manually - could also have been done easier with VALJOConfigure's importClasses option !>
<@super.imports()>
import java.security.MessageDigest;
>>

method_calculateDigest_String(clazz, method) ::= <<
/**
* Returnes the message digest of the members in the class.
*/
<declare_method(clazz, method)>
{
<! Construct a digest using first algorithm specified in first argument of method (we could hardcode this but in the example we use the model to tell us the name of the argument) !>
MessageDigest digester = MessageDigest.getInstance(<first(method.parameters).name>);

<! Iterate through all members of the class and call one of the template methods below depending on the overall type of the member !>
<clazz.members:{m | <(toByteTemplateNamesByTypeCategory.(m.type.typeCategory))(m.name, m.type)> }; wrap, anchor, separator="\n">

return digester.digest();
}
>>

/* A static ST map that works as a switch so types can be handled by different templates depending on category */
toByteTemplateNamesByTypeCategory ::= [ "PRIMITIVE": "toByte_primitive", "ARRAY": "toByte_array", default: "toByte_object"]

/* Primitive members are handled here. Note how bytes are easier dealth with then other primitives */
toByte_primitive(var, type) ::= <%
<if(type.primitiveByte)>
digester.update(<var>);
<else>
digester.update(getBytes(<var>));
<endif>
%>

/* Arrays are handled here. Note how primitive arrays of bytes are easier dealth with then other arrays */
toByte_array(var, type) ::= <<
<if(type.arrayComponentType.primitiveByte)>
digester.update(<var>);<\\>
<else><\\>
for (int i=0; i\<<var>.length; ++i)
digester.update(getBytes(<var>[i]));<\\>
<endif>
>>

/* All object types need help from our base class in this implementation. */
toByte_object(var, type) ::= <%
digester.update(getBytes(<var>));
%>
Expand Up @@ -13,7 +13,7 @@
* NOTE 1: The import could also have been done easier with VALJOConfigure's importClasses option - this is just an alternative.
*/

<@class.imports() ::= <<
@class.imports() ::= <<
<! Add our log class manually - Note 1 !>
<@super.imports()>
import java.util.logging.Logger;
Expand Down
Expand Up @@ -4,7 +4,7 @@
import java.util.Objects;
import javax.annotation.Generated;

@Generated(value = "com.fortyoneconcepts.valjogen", date="2014-10-17T19:58Z", comments="Generated by ValjoGen code generator (ValjoGen.41concepts.com) from com.fortyoneconcepts.valjogen.testsources.ComplexInterfaceWithAllTypes")
@Generated(value = "com.fortyoneconcepts.valjogen", date="2014-10-29T12:20Z", comments="Generated by ValjoGen code generator (ValjoGen.41concepts.com) from com.fortyoneconcepts.valjogen.testsources.ComplexInterfaceWithAllTypes")
public final class ComplexClass implements ComplexInterfaceWithAllTypes
{
private final ComplexInterfaceWithAllTypes other;
Expand Down Expand Up @@ -48,29 +48,29 @@ private ComplexClass(final ComplexInterfaceWithAllTypes other, final Object _obj
this._object=Objects.requireNonNull(_object);
this._string=Objects.requireNonNull(_string);
this.date=Objects.requireNonNull(date);
this.objectArray=objectArray;
this.objectMultiArray=objectMultiArray;
this.objectArray=Objects.requireNonNull(objectArray);
this.objectMultiArray=Objects.requireNonNull(objectMultiArray);
this._byte=_byte;
this._int=_int;
this._long=_long;
this._char=_char;
this._boolean=_boolean;
this._float=_float;
this._double=_double;
this.byteArray=byteArray;
this.intArray=intArray;
this.longArray=longArray;
this.charArray=charArray;
this.booleanArray=booleanArray;
this.floatArray=floatArray;
this.doubleArray=doubleArray;
this.byteMultiArray=byteMultiArray;
this.intMultiArray=intMultiArray;
this.longMultiArray=longMultiArray;
this.charMultiArray=charMultiArray;
this.booleanMultiArray=booleanMultiArray;
this.floatMultiArray=floatMultiArray;
this.doubleMultiArray=doubleMultiArray;
this.byteArray=Objects.requireNonNull(byteArray);
this.intArray=Objects.requireNonNull(intArray);
this.longArray=Objects.requireNonNull(longArray);
this.charArray=Objects.requireNonNull(charArray);
this.booleanArray=Objects.requireNonNull(booleanArray);
this.floatArray=Objects.requireNonNull(floatArray);
this.doubleArray=Objects.requireNonNull(doubleArray);
this.byteMultiArray=Objects.requireNonNull(byteMultiArray);
this.intMultiArray=Objects.requireNonNull(intMultiArray);
this.longMultiArray=Objects.requireNonNull(longMultiArray);
this.charMultiArray=Objects.requireNonNull(charMultiArray);
this.booleanMultiArray=Objects.requireNonNull(booleanMultiArray);
this.floatMultiArray=Objects.requireNonNull(floatMultiArray);
this.doubleMultiArray=Objects.requireNonNull(doubleMultiArray);
}

/**
Expand Down
Expand Up @@ -4,7 +4,7 @@
import java.util.Objects;
import javax.annotation.Generated;

@Generated(value = "com.fortyoneconcepts.valjogen", date="2014-10-17T19:58Z", comments="Generated by ValjoGen code generator (ValjoGen.41concepts.com) from com.fortyoneconcepts.valjogen.testsources.CustomTemplateInterface")
@Generated(value = "com.fortyoneconcepts.valjogen", date="2014-10-29T12:20Z", comments="Generated by ValjoGen code generator (ValjoGen.41concepts.com) from com.fortyoneconcepts.valjogen.testsources.CustomTemplateInterface")
public final class CustomTemplateClass implements CustomTemplateInterface
{
// Inserted magic code
Expand Down
Expand Up @@ -4,7 +4,7 @@
import java.util.Objects;
import javax.annotation.Generated;

@Generated(value = "com.fortyoneconcepts.valjogen", date="2014-10-17T19:58Z", comments="Generated by ValjoGen code generator (ValjoGen.41concepts.com) from com.fortyoneconcepts.valjogen.testsources.MutableSerializableInterface")
@Generated(value = "com.fortyoneconcepts.valjogen", date="2014-10-29T12:20Z", comments="Generated by ValjoGen code generator (ValjoGen.41concepts.com) from com.fortyoneconcepts.valjogen.testsources.MutableSerializableInterface")
public final class SerializableClass implements MutableSerializableInterface
{
private static final long serialVersionUID = 42;
Expand Down
Expand Up @@ -4,7 +4,7 @@
import java.util.Objects;
import javax.annotation.Generated;

@Generated(value = "com.fortyoneconcepts.valjogen", date="2014-10-17T19:58Z", comments="Generated by ValjoGen code generator (ValjoGen.41concepts.com) from com.fortyoneconcepts.valjogen.testsources.ImmutableSerializableInterfaceWithBaseClass")
@Generated(value = "com.fortyoneconcepts.valjogen", date="2014-10-29T12:20Z", comments="Generated by ValjoGen code generator (ValjoGen.41concepts.com) from com.fortyoneconcepts.valjogen.testsources.ImmutableSerializableInterfaceWithBaseClass")
public final class SerializableWithBaseClass extends BaseClass implements ImmutableSerializableInterfaceWithBaseClass
{
private static final long serialVersionUID = 43;
Expand Down
Expand Up @@ -4,7 +4,7 @@
import java.util.Objects;
import javax.annotation.Generated;

@Generated(value = "com.fortyoneconcepts.valjogen", date="2014-10-17T19:58Z", comments="Generated by ValjoGen code generator (ValjoGen.41concepts.com) from com.fortyoneconcepts.valjogen.testsources.SimpleInterface")
@Generated(value = "com.fortyoneconcepts.valjogen", date="2014-10-29T12:20Z", comments="Generated by ValjoGen code generator (ValjoGen.41concepts.com) from com.fortyoneconcepts.valjogen.testsources.SimpleInterface")
public final class SimpleClass implements SimpleInterface
{
private final Object _object;
Expand Down
Expand Up @@ -199,6 +199,30 @@ public TypeCategory getTypeCategory()
return TypeCategory.OBJECT;
}

@Override
public boolean isCollection()
{
assert initializedType : "Type initialization missing for type "+qualifiedProtoTypicalTypeName;

if (this.getQualifiedName().equals("java.util.Collection"))
return true;

boolean collection = getSuperTypesWithAscendants().stream().anyMatch(t -> t.getQualifiedName().equals("java.util.Collection"));
return collection;
}

@Override
public boolean isIterable()
{
assert initializedType : "Type initialization missing for type "+qualifiedProtoTypicalTypeName;

if (this.getQualifiedName().equals("java.lang.Iterable"))
return true;

boolean iterable = getSuperTypesWithAscendants().stream().anyMatch(t -> t.getQualifiedName().equals("java.lang.Iterable"));
return iterable;
}

@Override
public boolean isSerializable()
{
Expand Down
Expand Up @@ -38,6 +38,36 @@ public boolean isVoid()
return (qualifiedProtoTypicalTypeName.equals("void"));
}

@Override
public boolean isPrimitiveByte()
{
return (qualifiedProtoTypicalTypeName.equals("byte"));
}

@Override
public boolean isPrimitiveBoolean()
{
return (qualifiedProtoTypicalTypeName.equals("boolean"));
}

@Override
public boolean isPrimitiveShort()
{
return (qualifiedProtoTypicalTypeName.equals("short"));
}

@Override
public boolean isPrimitiveInt()
{
return (qualifiedProtoTypicalTypeName.equals("int"));
}

@Override
public boolean isPrimitiveLong()
{
return (qualifiedProtoTypicalTypeName.equals("long"));
}

@Override
public boolean isPrimitiveFloat() {
return (qualifiedProtoTypicalTypeName.equals("float"));
Expand Down

0 comments on commit 2b068b4

Please sign in to comment.