antipatterns

Collection of helpers to extend Java functionality

License

License

Categories

Categories

Ant Build Tools UML Business Logic Libraries Documents Processing
GroupId

GroupId

com.github.fluorumlabs
ArtifactId

ArtifactId

antipatterns
Last Version

Last Version

1.0.0-beta1
Release Date

Release Date

Type

Type

jar
Description

Description

antipatterns
Collection of helpers to extend Java functionality
Project URL

Project URL

https://github.com/fluorumlabs/antipatterns
Source Code Management

Source Code Management

http://github.com/fluorumlabs/antipatterns/tree/master

Download antipatterns

How to add to project

<!-- https://jarcasting.com/artifacts/com.github.fluorumlabs/antipatterns/ -->
<dependency>
    <groupId>com.github.fluorumlabs</groupId>
    <artifactId>antipatterns</artifactId>
    <version>1.0.0-beta1</version>
</dependency>
// https://jarcasting.com/artifacts/com.github.fluorumlabs/antipatterns/
implementation 'com.github.fluorumlabs:antipatterns:1.0.0-beta1'
// https://jarcasting.com/artifacts/com.github.fluorumlabs/antipatterns/
implementation ("com.github.fluorumlabs:antipatterns:1.0.0-beta1")
'com.github.fluorumlabs:antipatterns:jar:1.0.0-beta1'
<dependency org="com.github.fluorumlabs" name="antipatterns" rev="1.0.0-beta1">
  <artifact name="antipatterns" type="jar" />
</dependency>
@Grapes(
@Grab(group='com.github.fluorumlabs', module='antipatterns', version='1.0.0-beta1')
)
libraryDependencies += "com.github.fluorumlabs" % "antipatterns" % "1.0.0-beta1"
[com.github.fluorumlabs/antipatterns "1.0.0-beta1"]

Dependencies

compile (3)

Group / Artifact Type Version
org.apache.commons : commons-lang3 jar 3.8.1
commons-beanutils : commons-beanutils jar 1.9.3
com.google.code.findbugs : jsr305 jar 3.0.2

test (1)

Group / Artifact Type Version
junit : junit jar 4.11

Project Modules

There are no modules declared in this project.

AntiPatterns

Maven metadata URL GitHub Build Status

What?

antipatterns is a collection of helpers and weird stuff to make Java development easier and support harder :)

Features

Access private methods/fields/constructors in a type-safe manner

import com.github.fluorumlabs.antipatterns.AntiPatterns;

...

@TargetClass(Boolean.class)
private interface BooleanMirror {
    @Static
    @DirectField
    void FALSE(Boolean value);

    static BooleanMirror attach() {
        return AntiPatterns.attachStatic(BooleanMirror.class);
    }
}

// Change Boolean.FALSE to true
BooleanMirror.attach().FALSE(true);

...

// Add fluent API to third-party libraries
private interface FluentList<T> extends AntiPatterns.Attachable<List<T>> {
    @ReturnType(boolean.class)
    FluentList<T> add(T value);

    @ReturnType(boolean.class)
    FluentList<T> addAll(@ArgumentType(Collection.class) TestFluentAPI<T> other);

    static <T> FluentList<T> attach(List<T> instance) {
        return AntiPatterns.attach(FluentList.class, instance);
    }
}

...

FluentList<String> fluentList = FluentList.attach(new ArrayList<String>());
fluentList.add("1").add("2").add("3");
List<String> list = fluentList.instance();

...

// Create singleton API bridges
@TargetClass.API
public interface PrivateMatcherAPI {
    int getMatchedGroupIndex(Matcher that, String name);
    
    static PrivateMatcherAPI create() {
        return AntiPatterns.attachStatic(PrivateMatcherAPI.class);
    }
}

Upgrade object instance to a subclass

import com.github.fluorumlabs.antipatterns.AntiPatterns;

...

public class WebpageRouteRegistry extends ApplicationRouteRegistry {
    @Override
    public Optional<Class<? extends Component>> getNavigationTarget(String pathString, List<String> segments) {
        ...
    }
}

...

// upgrade ApplicationRouteRegistry to WebpageRouteRegistry
RouteRegistry newRegistry = AntiPatterns.upgrade(getRouteRegistry(), WebpageRouteRegistry.class);

// make a shallow clone
Entity sameButDifferent = AntiPatterns.shallowClone(entity);

Access trusted MethodHandles.Lookup instance

import com.github.fluorumlabs.antipatterns.AntiPatterns;

...

MethodHandle Matcher_getMatchedGroupIndex = AntiPatterns.lookupAll().findVirtual(Matcher.class, "getMatchedGroupIndex", MethodType.methodType(int.class, String.class));

String interpolation

import static com.github.fluorumlabs.antipatterns.AntiPatterns.interpolate;

...

// Replace tokens with actual values of current user
String result = interpolate("Hello, ${user.firstName} ${user.lastName}!", user -> getCurrentUser());

// String interpolation with format specifiers
String result = interpolate("${percent %.2f}% completed", percent -> 100*progressValue);

Ignoring run-time exceptions

import com.github.fluorumlabs.antipatterns.AntiPatterns;

...

// Wrap suppliers
AntiPatterns.guarded(() -> AntiPatterns.of(Integer.parse("234234j"))).ifPresent(...);

// Wrap functions
someStringOptional.map(AntiPatterns.guarded(id -> Integer.parse(id)).ifPresent(...);

// Wrap runnables
AntiPatterns.guarded(() -> discussionService.incrementViewCount(root));

Getting Optional elements of array or List,

import com.github.fluorumlabs.antipatterns.AntiPatterns;

...

// Get first element of list/array or Optional.empty() if list/array is null or empty
AntiPatterns.getFirst(someList).ifPresent(...);

// Get 16-th element of list/array or Optional.empty() if list/array is null or has less then 17 elements
AntiPatterns.get(someList, 16).ifPresent(...);

Trying sequentially suppliers of Optional

import com.github.fluorumlabs.antipatterns.AntiPatterns;

...

// First try getEntityFromUrl, then, if it fails, getEntityFromSession, otherwise obtain default entity
SomeEntity entity = AntiPatterns.trySequentially(this::getEntityFromUrl, 
                                              this::getEntityFromSession, 
                                              this::getDefaultEntity)
    .orElseThrow(EntityNotFound::new);

Simple builders for arrays and maps

import static com.github.fluorumlabs.antipatterns.AntiPatterns.array;
import static com.github.fluorumlabs.antipatterns.AntiPatterns.hashMap;

...

// Build array of strings
String[] options = array("option1", "option2");

// Build hashmap with entries [("option1", optionObject1), ("option2", optionObject2)]
Map<String,Option> options = hashMap(option1 -> optionObject1, 
                                     option2 -> optionObject2);

RegExp helpers

import com.github.fluorumlabs.antipatterns.AntiPatterns;

...

// Pattern matching [[...]]
private static final Pattern TEMPLATE_PATTERN = Pattern.compile("\\[\\[([^\\]]+)\\]\\]");
// Properties
private Map<String,String> properties;

...

// Replace tokens [[...]] with properties
String result = AntiPatterns.replaceFunctional(TEMPLATE_PATTERN, message, groups -> properties.get(groups[1]));

// Get pattern matches as stream
Stream<String[]> groups = AntiPatterns.matchAsStream(TEMPLATE_PATTERN, message);

Safe casting of objects

import com.github.fluorumlabs.antipatterns.AntiPatterns;

...

// Cast baseEntity to Entity, or return Optional.empty() if it's not possible
Optional<Entity> entity = AntiPatterns.safeCast(baseEntity, Entity.class);

// Cast baseEntity to Entity in stream
Stream<Entity> entities = baseEntities.stream()
    .map(AntiPatterns.safeCast(Entity.class))
    .filter(Objects::nonNull);

Usage

<dependency>
   <groupId>com.github.fluorumlabs</groupId>
   <artifactId>antipatterns</artifactId>
   <version>1.0.0-beta1</version>
</dependency>

Versions

Version
1.0.0-beta1
1.0.0-alpha3
1.0.0-alpha2
1.0.0-alpha1