Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/henneberger/typekin

Structural typing for object graphs in Java
https://github.com/henneberger/typekin

Last synced: about 1 month ago
JSON representation

Structural typing for object graphs in Java

Awesome Lists containing this project

README

        

# Object Graphs and Structural Typing in Java

This gives Java a way to handle partial representations of data model while remaining type safe.
Types are generated at compile time via annotations.

## Getting started
```xml


com.github.henneberger
typekin-processor
1.0.2
provided

```

## Example Usage

```java
public class Main {
// The optional model definition. If present, all TypeOf
// annotations must match this structure.
//
// You add `implements St{name}Model`
@Model
abstract class Foo implements StFooModel {
public abstract String getA();
public abstract String getB();
public abstract String getC();
}

//A subset of the model (for code reuse)
@TypeOf(model = Foo.class)
public interface FooAFragment {
String getA();
}
@TypeOf(model = Foo.class)
public interface FooABFragment {
String getA();
String getB();
}
@TypeOf(model = Foo.class)
public interface FooCFragment {
String getC();
}
//compile error, D is not a property of the model
//@TypeOf(clazz = Foo.class)
//public interface FooDFragment {
// String getD();
//}

// A container of data that can contain any data.
// Function signatures are used to determine
// equivalence classes with TypeOf classes.
//
// You add `implements St{name}`
@StructuralType(model = Foo.class)
public static class FooAData implements StFooAData {
public String getA() { return "A"; }
}
@StructuralType(model = Foo.class)
public static class FooABData implements StFooABData {
public String getA() { return "A"; }
public String getB() { return "B"; }
}
@StructuralType(model = Foo.class)
public static class FooCData implements StFooCData {
public String getC() { return "C"; }
}

public static void main(String[] args) {
print(new FooAData());
print(new FooABData());
//print(new FooCData()); //compile error
}

public static void print(FooAFragment foo) {
System.out.println(foo.getA());
//System.out.println(foo.getB()); //compile error
//System.out.println(foo.getC()); //compile error
}
}

//This gets generated by the annotations:
interface StFooAData extends FooAFragment {}
interface StFooABData extends FooAFragment, FooABFragment {}
interface StFooCData extends FooCFragment {}

interface StFooModel extends FooAFragment, FooABFragment, FooCFragment {}
interface StFooRef extends StFooAData, StFooABData, StFooCData {}
```

### `@Model`
The `@Model` annotation defines the data model. All `@TypeOf` model fragments that
refer to a `@Model` class will be strongy typed. Only abstract methods will be recognized
for type candidates. For nested objects, a generated `Ref` class serves as a type reference.
Parameters:
- `name`: The name of the class it will generate
- `refName`: The name of the class it will generate for data model relationships
- `concreteName`: The name of the empty concrete class for jvm type validation

E.g.
```java
@Model(name = "FooModel", refName = "FooRef")
abstract class Foo implements FooModel {
public abstract String getA();
public abstract List getBar();
}

@Model(name = "BarModel", refName = "BarRef")
abstract class Bar implements BarModel {
public abstract String getA();
public abstract FooRef getFoo();
}
```

### `@TypeOf`
The `@TypeOf` annotation defines a partial representation of the data model. All `@StructuralType`
classes that have the same model class are compared structurally to all `@TypeOf` interfaces.
Parameters:
- `model`: The class of the model

E.g:
```java
@TypeOf(model = Foo.class)
public interface FooFragment {
String getA();
List extends BarFragment> getBar();
}
@TypeOf(model = Bar.class)
public interface BarFragment {
String getA();
FooFragment getFoo();
}
```

### `@StructuralType`
A concrete type that contains data. This can contain any data but only method signatures
that match the model will be used as candidates for `@TypeOf` classes.
Parameters:
- `model`: The class of the model
- `name`: The name of the class it will generate

E.g.
```java
@StructuralType(model = Foo.class, name = "FooDataType")
public class FooData extends FooDataType {
public String getA() { return null; }
public List getBar() { return null; }
public String extraParam() { return null; } //ok
}
@StructuralType(model = Bar.class, name = "BarDataType")
public class BarData extends BarDataType {
public String getA() { return null; }
public Foo getFoo() { return null; }
}
```

A full example can be found here:
[tests/src/main/java/com/github/henneberger/typekin/tests/example/FooExample.java](tests/src/main/java/com/github/henneberger/typekin/tests/example/FooExample.java)

### Limitations
Since it relies on compile time annotations, other annotations may not work with Typekin.

### Contributions
This work is inspiried by https://github.com/tlamr/stjava