Skip to content

Commit 329b718

Browse files
committed
Added map and mapWithSameRepresentation methods to Obfuscated
1 parent 2315d2b commit 329b718

File tree

2 files changed

+132
-6
lines changed

2 files changed

+132
-6
lines changed

src/main/java/com/github/robtimus/obfuscation/Obfuscated.java

Lines changed: 79 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
package com.github.robtimus.obfuscation;
1919

2020
import java.util.Objects;
21+
import java.util.function.Function;
2122
import java.util.function.Supplier;
2223

2324
/**
@@ -30,13 +31,16 @@
3031
public abstract class Obfuscated<T> {
3132

3233
private final T value;
34+
private final Obfuscator obfuscator;
3335

34-
private Obfuscated(T value) {
36+
private Obfuscated(T value, Obfuscator obfuscator) {
3537
this.value = Objects.requireNonNull(value);
38+
this.obfuscator = Objects.requireNonNull(obfuscator);
3639
}
3740

3841
private Obfuscated(Obfuscated<T> other) {
3942
this.value = other.value;
43+
this.obfuscator = other.obfuscator;
4044
}
4145

4246
static <T> Obfuscated<T> of(T value, Obfuscator obfuscator, Supplier<? extends CharSequence> representation) {
@@ -52,6 +56,10 @@ public final T value() {
5256
return value;
5357
}
5458

59+
final Obfuscator obfuscator() {
60+
return obfuscator;
61+
}
62+
5563
@Override
5664
public final boolean equals(Object o) {
5765
if (this == o) {
@@ -72,6 +80,56 @@ public final int hashCode() {
7280
@Override
7381
public abstract String toString();
7482

83+
/**
84+
* Applies a mapping function to the obfuscated value.
85+
* The result is similar to calling {@link Obfuscator#obfuscateObject(Object)} on the obfuscator that created this object, passing the result of
86+
* applying the given mapping function to the obfuscated value.
87+
*
88+
* @param <U> The result type of the mapping function.
89+
* @param mapper The mapping function to apply.
90+
* @return An {@code Obfuscated} object wrapping the result of applying the given mapping function to this object's value.
91+
* @throws NullPointerException If the mapping function is {@code null},
92+
* or if the mapping function returns a {@code null} value when applied to this object's value.
93+
* @since 1.1
94+
*/
95+
public final <U> Obfuscated<U> map(Function<? super T, ? extends U> mapper) {
96+
U mapped = mapper.apply(value);
97+
return obfuscator().obfuscateObject(mapped);
98+
}
99+
100+
/**
101+
* Applies a mapping function to the obfuscated value.
102+
* The result is similar to calling {@link Obfuscator#obfuscateObject(Object, Supplier)} on the obfuscator that created this object, passing the
103+
* result of applying the given mapping function to the obfuscated value.
104+
*
105+
* @param <U> The result type of the mapping function.
106+
* @param mapper The mapping function to apply.
107+
* @param representation A supplier for the string representation that will be used to obfuscate the value.
108+
* This can be used for values that don't have a sensible {@link Object#toString() string representation} of their own.
109+
* @return An {@code Obfuscated} object wrapping the result of applying the given mapping function to this object's value.
110+
* @throws NullPointerException If the mapping function or supplier is {@code null},
111+
* or if the mapping function returns a {@code null} value when applied to this object's value.
112+
* @since 1.1
113+
*/
114+
public final <U> Obfuscated<U> map(Function<? super T, ? extends U> mapper, Supplier<? extends CharSequence> representation) {
115+
U mapped = mapper.apply(value);
116+
return obfuscator().obfuscateObject(mapped, representation);
117+
}
118+
119+
/**
120+
* Applies a mapping function to the obfuscating value.
121+
* Unlike {@link #map(Function)} and {@link #map(Function, Supplier)}, the result will use the same representation to obfuscate as this object.
122+
* If this object {@link #cached() caches} the results of obfuscating, so will the result.
123+
*
124+
* @param <U> The result type of the mapping function.
125+
* @param mapper The mapping function to apply.
126+
* @return An {@code Obfuscated} object wrapping the result of applying the given mapping function to this object's value.
127+
* @throws NullPointerException If the mapping function is {@code null},
128+
* or if the mapping function returns a {@code null} value when applied to this object's value.
129+
* @since 1.1
130+
*/
131+
public abstract <U> Obfuscated<U> mapWithSameRepresentation(Function<? super T, ? extends U> mapper);
132+
75133
/**
76134
* Returns an obfuscated object that caches the results of obfuscating.
77135
* This can be used when the result of obfuscation never changes, for example when obfuscating immutable objects.
@@ -82,18 +140,22 @@ public final int hashCode() {
82140

83141
private static final class Obfuscating<T> extends Obfuscated<T> {
84142

85-
private final Obfuscator obfuscator;
86143
private final Supplier<? extends CharSequence> representation;
87144

88-
Obfuscating(T obfuscated, Obfuscator obfuscator, Supplier<? extends CharSequence> representation) {
89-
super(obfuscated);
90-
this.obfuscator = Objects.requireNonNull(obfuscator);
145+
private Obfuscating(T obfuscated, Obfuscator obfuscator, Supplier<? extends CharSequence> representation) {
146+
super(obfuscated, obfuscator);
91147
this.representation = Objects.requireNonNull(representation);
92148
}
93149

94150
@Override
95151
public String toString() {
96-
return obfuscator.obfuscateText(representation.get()).toString();
152+
return obfuscator().obfuscateText(representation.get()).toString();
153+
}
154+
155+
@Override
156+
public <U> Obfuscated<U> mapWithSameRepresentation(Function<? super T, ? extends U> mapper) {
157+
U mapped = mapper.apply(value());
158+
return new Obfuscating<>(mapped, obfuscator(), representation);
97159
}
98160

99161
@Override
@@ -111,11 +173,22 @@ private Cached(Obfuscated<T> obfuscated, String stringValue) {
111173
this.stringValue = Objects.requireNonNull(stringValue);
112174
}
113175

176+
private Cached(T obfuscated, Obfuscator obfuscator, String stringValue) {
177+
super(obfuscated, obfuscator);
178+
this.stringValue = Objects.requireNonNull(stringValue);
179+
}
180+
114181
@Override
115182
public String toString() {
116183
return stringValue;
117184
}
118185

186+
@Override
187+
public <U> Obfuscated<U> mapWithSameRepresentation(Function<? super T, ? extends U> mapper) {
188+
U mapped = mapper.apply(value());
189+
return new Cached<>(mapped, obfuscator(), stringValue);
190+
}
191+
119192
@Override
120193
public Obfuscated<T> cached() {
121194
return this;

src/test/java/com/github/robtimus/obfuscation/ObfuscatedTest.java

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@
1919

2020
import static com.github.robtimus.obfuscation.Obfuscator.all;
2121
import static org.junit.jupiter.api.Assertions.assertEquals;
22+
import static org.junit.jupiter.api.Assertions.assertNotEquals;
2223
import static org.junit.jupiter.api.Assertions.assertNotSame;
2324
import static org.junit.jupiter.api.Assertions.assertSame;
2425
import static org.junit.jupiter.params.provider.Arguments.arguments;
2526
import org.junit.jupiter.api.DisplayName;
27+
import org.junit.jupiter.api.Nested;
2628
import org.junit.jupiter.api.Test;
2729
import org.junit.jupiter.params.ParameterizedTest;
2830
import org.junit.jupiter.params.provider.Arguments;
@@ -59,6 +61,57 @@ public void testHashCode() {
5961
assertEquals(obfuscated.hashCode(), all().obfuscateObject("foo").hashCode());
6062
}
6163

64+
@Test
65+
@DisplayName("map(Function<? super T, ? extends U>)")
66+
public void testMap() {
67+
Obfuscated<String> obfuscated = all('x').obfuscateObject("foo");
68+
Obfuscated<?> mapped = obfuscated.map(s -> s + s.toUpperCase());
69+
assertNotEquals(obfuscated, mapped);
70+
assertEquals("fooFOO", mapped.value());
71+
assertEquals("xxxxxx", mapped.toString());
72+
}
73+
74+
@Test
75+
@DisplayName("map(Function<? super T, ? extends U>, Supplier<? extends CharSequence>)")
76+
public void testMapWithRepresentation() {
77+
Obfuscated<String> obfuscated = all('x').obfuscateObject("foo");
78+
Obfuscated<?> mapped = obfuscated.map(s -> s + s.toUpperCase(), () -> "different representation");
79+
assertNotEquals(obfuscated, mapped);
80+
assertEquals("fooFOO", mapped.value());
81+
assertEquals("xxxxxxxxxxxxxxxxxxxxxxxx", mapped.toString());
82+
}
83+
84+
@Nested
85+
@DisplayName("mapWithSameRepresentation(Function<? super T, ? extends U>)")
86+
public class MapWithSameRepresentation {
87+
88+
@Test
89+
@DisplayName("non-cached")
90+
public void testNonCached() {
91+
Obfuscated<String> obfuscated = all('x').obfuscateObject("foo");
92+
Obfuscated<?> mapped = obfuscated.mapWithSameRepresentation(s -> s + s.toUpperCase());
93+
assertNotEquals(obfuscated, mapped);
94+
assertEquals(obfuscated.getClass(), mapped.getClass());
95+
assertEquals("fooFOO", mapped.value());
96+
assertEquals("xxx", mapped.toString());
97+
}
98+
99+
@Test
100+
@DisplayName("cached")
101+
public void testCached() {
102+
Obfuscated<String> obfuscated = all('x').obfuscateObject("foo");
103+
Obfuscated<String> cached = obfuscated.cached();
104+
Obfuscated<?> mapped = cached.mapWithSameRepresentation(s -> s + s.toUpperCase());
105+
assertNotEquals(cached, mapped);
106+
assertEquals(cached.getClass(), mapped.getClass());
107+
assertEquals("fooFOO", mapped.value());
108+
assertEquals("xxx", mapped.toString());
109+
assertSame(mapped.toString(), mapped.toString());
110+
assertSame(cached.toString(), mapped.toString());
111+
assertSame(mapped, mapped.cached());
112+
}
113+
}
114+
62115
@Test
63116
@DisplayName("cached()")
64117
public void testCached() {

0 commit comments

Comments
 (0)