Skip to content

Commit

Permalink
Merge pull request #22 from antkudruk/develop
Browse files Browse the repository at this point in the history
Refactored, separated member selection ans member implementation
  • Loading branch information
antkudruk authored Jun 19, 2021
2 parents b962745 + 8033d77 commit ad0da5f
Show file tree
Hide file tree
Showing 120 changed files with 1,095 additions and 414 deletions.
141 changes: 127 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,16 +138,30 @@ wrapper classes properly.

You can download **Uniform Factory** into your project from Maven Central.

Here is an example for Gradle

```
dependencies {
compile group: 'com.github.antkudruk', name: 'uniform-factory', version: '0.0.1'
compile group: 'com.github.antkudruk', name: 'uniform-factory', version: '0.1.0'
}
```

and for Maven

```
<dependency>
<groupId>com.github.antkudruk</groupId>
<artifactId>uniform-factory</artifactId>
<version>0.1.0</version>
</dependency>
```

**Uniform Factory** is written to be applied in ByteBuddy Gradle Plugin to
generate uniformed **wrapper** classes. Just import and apply
`byte-buddy-gradle-plugin` and specify your plugin class.

Here is an example for Gradle

```
plugins {
id 'java'
Expand All @@ -161,6 +175,30 @@ byteBuddy {
}
```

and in Maven

```
<plugin>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy-maven-plugin</artifactId>
<version>1.10.6</version>
<executions>
<execution>
<goals>
<goal>transform</goal>
</goals>
</execution>
</executions>
<configuration>
<transformations>
<transformation>
<plugin><!-- Specify your plugin class reference here --></plugin>
</transformation>
</transformations>
</configuration>
</plugin>
```

Let's take a look at some examples.

### Empty wrapper
Expand Down Expand Up @@ -270,6 +308,80 @@ Object origin = new OriginImpl();
Wrapper wrapper = ((Origin)origin).getWrapper();
```

#### Using explicit interface to enhance objects with wrappers

You can avoid class cast made in the previous example the following way

* Add `@Marker` annotation to the `Origin` interface.

* Add a default implementation to the `Origin` interface to prevent compilation
error. This default implementation should basically throw an exception, but you
may implement the different logic.

```
@Marker
public interface Origin {
default Wrapper getWrapper() {
throw new RuntimeException("Wrapper method hasn't been implemented.");
}
}
```

* Add `@Inherited` to the Marker annotation. This will implicitly add the
`@Marker` annotation to each object implementing `Origin` interface.

```
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
@Inherited
public @interface Marker { }
```

* Add `Origin` interface to the interfaces list of each origin class.

```
@Marker
public class OriginImpl implements Origin {
}
```
After that, the `OriginImpl` class is going to have an implementation for
`getWrapper()` method that returns the appropriate wrapper.

```
OriginImpl origin = new OriginImpl();
Wrapper wrapper = origin.getWrapper();
```

This way, if you implement `getWrapper()` method explicitly, your
implementation it's not going to be overridden by the plugin.

#### Select type criteria

You may want to add wrappers to classes satisfying a custom criteria, for
example, matching class names to a special regular expression.
**UniformFactory** provides a flexible way to select particular classes for
that.

Let's implement a plugin to add wrappers to methods that explicitly implement
the `Origin` interface, but using custom class selection criteria.

```
public class PluginImpl extends WrapperPlugin<Wrapper> {
public PluginImpl() {
super(
Origin.class,
Wrapper.class,
// Class selection criteria
td -> td.getInterfaces()
.stream()
.map(TypeDefinition::asErasure)
.anyMatch(new TypeDescription.ForLoadedType(Origin.class)::equals),
"examplePlugin",
ClassFactoryGeneratorImpl.class);
}
}
```

### Method Singleton

Let's enhance our empty `Wrapper` class.
Expand Down Expand Up @@ -301,7 +413,8 @@ method.
public class ClassFactoryGeneratorImpl extends DefaultMetaClassFactory<Wrapper> {
public ClassFactoryGeneratorImpl() throws NoSuchMethodException {
super(new ClassFactory.ShortcutBuilder<>(Wrapper.class)
.addMethodSingleton(Identity.class, Wrapper.class.getMethod("getIdentity"), String.class)
.addMethodSingleton(Wrapper.class.getMethod("getIdentity"), String.class)
.setMarkerAnnotation(Identity.class)
.addResultTranslator(Long.class, Object::toString)
.endMethodDescription()
.build());
Expand Down Expand Up @@ -418,11 +531,12 @@ an empty list of children.
public class ClassFactoryGeneratorImpl extends DefaultMetaClassFactory<TreeElement> {
public ClassFactoryGeneratorImpl() throws ReflectiveOperationException {
super(new ClassFactory.ShortcutBuilder<>(TreeElement.class)
.addMethodSingleton(Label.class, TreeElement.class.getMethod("getLabel"), String.class)
.addMethodSingleton(TreeElement.class.getMethod("getLabel"), String.class)
.setMarkerAnnotation(Label.class)
.endMethodDescription()
.addMethodSingleton(Nested.class, TreeElement.class.getMethod("nested"), List.class)
.addMethodSingleton(TreeElement.class.getMethod("nested"), List.class)
.setMarkerAnnotation(Nested.class)
.setDefaultValue(new ArrayList<>())
.endMethodDescription()
Expand Down Expand Up @@ -498,13 +612,12 @@ returning type of the **functional** interface.
```
public class ClassFactoryGeneratorImpl extends DefaultMetaClassFactory<Wrapper> {
public ClassFactoryGeneratorImpl() throws NoSuchMethodException {
super(new ClassFactory.ShortcutBuilder<>(Wrapper.class)
this.classFactory = new ClassFactory.ShortcutBuilder<>(Wrapper.class)
.addMethodList(
Processor.Process.class,
Wrapper.class.getMethod("getProcessors"),
boolean.class
)
.setMarkerAnnotation(Processor.Process.class)
.setFunctionalInterface(Processor.class)
.addResultTranslator(void.class, t -> true)
.addResultTranslator(Long.class, t -> t >= 0)
Expand Down Expand Up @@ -537,10 +650,10 @@ public class ClassFactoryGeneratorImpl implements MetaClassFactory<Wrapper> {
public ClassFactoryGeneratorImpl() throws NoSuchMethodException {
this.classFactory = new ClassFactory.ShortcutBuilder<>(Wrapper.class)
.addMethodList(
Processor.Process.class,
Wrapper.class.getMethod("getProcessors"),
boolean.class
)
.setMarkerAnnotation(Processor.Process.class)
.setFunctionalInterface(Processor.class)
.addResultTranslator(void.class, t -> true)
Expand Down Expand Up @@ -682,8 +795,8 @@ public class ClassFactoryGeneratorImpl extends DefaultMetaClassFactory<PointWrap
public ClassFactoryGeneratorImpl() throws NoSuchMethodException {
super(new ClassFactory.ShortcutBuilder<>(PointWrapper.class)
.addMethodMap(CoordinateMarker.class, PointWrapper.class.getMethod("getCoords"), long.class)
.setKeyGetter(CoordinateMarker::value)
.addMethodMap(PointWrapper.class.getMethod("getCoords"), long.class)
.setMarkerAnnotation(CoordinateMarker.class, CoordinateMarker::value)
.setFunctionalInterface(Coordinate.class)
.parameterSource(Long.class, 0)
Expand Down Expand Up @@ -727,9 +840,9 @@ public class MethodTreeWrapperClassFactory {
try {
classFactory = new ClassFactory.ShortcutBuilder<>(Wrapper.class)
.addMethodMap(FunctionalElement.class, Wrapper.class.getMethod("getWrappers"), String.class)
.addMethodMap(Wrapper.class.getMethod("getWrappers"), String.class)
.setMarkerAnnotation(FunctionalElement.class, FunctionalElement::value)
.setFunctionalInterface(Fun.class)
.setKeyGetter(FunctionalElement::value)
.parameterSource(String.class, 0)
.applyToAnnotated(First.class)
Expand Down Expand Up @@ -828,7 +941,7 @@ public class ClassFactoryGeneratorImpl extends DefaultMetaClassFactory<Wrapper>
## License

```
Copyright 2020 Anton Kudruk
Copyright 2020 - 2021 Anton Kudruk
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ plugins {
}

// The current version
def libraryVersion='0.0.1'
def libraryVersion='0.1.0'

group 'com.github.antkudruk'
version libraryVersion
Expand Down
File renamed without changes.
27 changes: 27 additions & 0 deletions gradle-listing-1-2-interface-inherited/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
plugins {
id 'java'
id "net.bytebuddy.byte-buddy-gradle-plugin" version "1.10.6"
}

group 'hz.xorlab'
version '1.0-SNAPSHOT'

sourceCompatibility = 1.11

repositories {
mavenCentral()
}

dependencies {
compile project(path: ":")
testCompile group: 'junit', name: 'junit', version: '4.12'
compile group: 'net.bytebuddy', name: 'byte-buddy', version: '1.10.6'

compile group: 'net.bytebuddy', name: 'byte-buddy-gradle-plugin', version: '1.10.6'
}

byteBuddy {
transformation {
plugin = "com.github.antkudruk.uniformfactory.test.gradleplugin.emptywrapper.interfaceinherited.PluginImpl"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.github.antkudruk.uniformfactory.test.gradleplugin.emptywrapper.interfaceinherited;

import com.github.antkudruk.uniformfactory.classfactory.ClassFactory;
import com.github.antkudruk.uniformfactory.pluginbuilder.DefaultMetaClassFactory;

public class ClassFactoryGeneratorImpl extends DefaultMetaClassFactory<Wrapper> {
public ClassFactoryGeneratorImpl() {
super(new ClassFactory.Builder<>(Wrapper.class)
.build());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.github.antkudruk.uniformfactory.test.gradleplugin.emptywrapper.interfaceinherited;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
@Inherited
public @interface Marker {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.github.antkudruk.uniformfactory.test.gradleplugin.emptywrapper.interfaceinherited;

@Marker
public interface Origin {
default Wrapper getWrapper() {
throw new RuntimeException("Wrapper method hasn't been implemented.");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.github.antkudruk.uniformfactory.test.gradleplugin.emptywrapper.interfaceinherited;

@Marker
public class OriginImpl implements Origin {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.github.antkudruk.uniformfactory.test.gradleplugin.emptywrapper.interfaceinherited;

import com.github.antkudruk.uniformfactory.pluginbuilder.WrapperPlugin;

public class PluginImpl extends WrapperPlugin<Wrapper> {
public PluginImpl() {
super(
Origin.class,
Wrapper.class,
Marker.class,
"examplePlugin",
ClassFactoryGeneratorImpl.class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.github.antkudruk.uniformfactory.test.gradleplugin.emptywrapper.interfaceinherited;

public interface Wrapper {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.github.antkudruk.uniformfactory.test.gradleplugin.emptywrapper.interfaceinherited;

import org.junit.Test;

public class EmptyTest {

@SuppressWarnings("ConstantConditions")
@Test
public void test() {
OriginImpl origin = new OriginImpl();
assert Wrapper.class.isAssignableFrom(origin.getWrapper().getClass());
}
}
27 changes: 27 additions & 0 deletions gradle-listing-1-3-custom-select-type-criteria/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
plugins {
id 'java'
id "net.bytebuddy.byte-buddy-gradle-plugin" version "1.10.6"
}

group 'hz.xorlab'
version '1.0-SNAPSHOT'

sourceCompatibility = 1.11

repositories {
mavenCentral()
}

dependencies {
compile project(path: ":")
testCompile group: 'junit', name: 'junit', version: '4.12'
compile group: 'net.bytebuddy', name: 'byte-buddy', version: '1.10.6'

compile group: 'net.bytebuddy', name: 'byte-buddy-gradle-plugin', version: '1.10.6'
}

byteBuddy {
transformation {
plugin = "com.github.antkudruk.uniformfactory.test.gradleplugin.emptywrapper.interfacebased.PluginImpl"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.github.antkudruk.uniformfactory.test.gradleplugin.emptywrapper.interfacebased;

import com.github.antkudruk.uniformfactory.classfactory.ClassFactory;
import com.github.antkudruk.uniformfactory.pluginbuilder.DefaultMetaClassFactory;

public class ClassFactoryGeneratorImpl extends DefaultMetaClassFactory<Wrapper> {
public ClassFactoryGeneratorImpl() {
super(new ClassFactory.Builder<>(Wrapper.class)
.build());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.github.antkudruk.uniformfactory.test.gradleplugin.emptywrapper.interfacebased;

public class ExplicitOriginImpl implements Origin {
@Override
public Wrapper getWrapper() {
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.github.antkudruk.uniformfactory.test.gradleplugin.emptywrapper.interfacebased;

public interface Origin {
default Wrapper getWrapper() {
throw new RuntimeException("The method should be implemented by the plugin. Please, specify the plugin un your build script.");
}
}
Loading

0 comments on commit ad0da5f

Please sign in to comment.