diff --git a/.gitignore b/.gitignore index 21174e9..2e5cdaa 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,6 @@ hs_err_pid* # IntelliJ files -.idea/* +.idea/ *.iml -target/* \ No newline at end of file +target/ \ No newline at end of file diff --git a/statiflex/pom.xml b/statiflex/pom.xml new file mode 100644 index 0000000..9bae8d6 --- /dev/null +++ b/statiflex/pom.xml @@ -0,0 +1,25 @@ + + + 4.0.0 + + com.caffinc + statiflex + statiflex + 1.0 + + + + org.slf4j + slf4j-log4j12 + 1.7.12 + + + junit + junit + 4.12 + test + + + \ No newline at end of file diff --git a/statiflex/src/main/java/com/caffinc/statiflex/Statiflex.java b/statiflex/src/main/java/com/caffinc/statiflex/Statiflex.java new file mode 100644 index 0000000..d242645 --- /dev/null +++ b/statiflex/src/main/java/com/caffinc/statiflex/Statiflex.java @@ -0,0 +1,99 @@ +package com.caffinc.statiflex; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + + +/** + * Uses reflection to modify static final fields. + * User under extreme duress. + * + * uuuuuuu + * uu$$$$$$$$$$$uu + * uu$$$$$$$$$$$$$$$$$uu + * u$$$$$$$$$$$$$$$$$$$$$u + * u$$$$$$$$$$$$$$$$$$$$$$$u + * u$$$$$$$$$$$$$$$$$$$$$$$$$u + * u$$$$$$$$$$$$$$$$$$$$$$$$$u + * u$$$$$$" "$$$" "$$$$$$u + * "$$$$" u$u $$$$" + * $$$u u$u u$$$ + * $$$u u$$$u u$$$ + * "$$$$uu$$$ $$$uu$$$$" + * "$$$$$$$" "$$$$$$$" + * u$$$$$$$u$$$$$$$u + * u$"$"$"$"$"$"$u + * uuu $$u$ $ $ $ $u$$ uuu + * u$$$$ $$$$$u$u$u$$$ u$$$$ + * $$$$$uu "$$$$$$$$$" uu$$$$$$ + *u$$$$$$$$$$$uu """"" uuuu$$$$$$$$$$ + *$$$$"""$$$$$$$$$$uuu uu$$$$$$$$$"""$$$" + * """ ""$$$$$$$$$$$uu ""$""" + * uuuu ""$$$$$$$$$$uuu + * u$$$uuu$$$$$$$$$uu ""$$$$$$$$$$$uuu$$$ + * $$$$$$$$$$"""" ""$$$$$$$$$$$" + * "$$$$$" ""$$$$"" + * $$$" $$$$" + * + * @author Sriram + */ +public class Statiflex +{ + private static final Logger LOG = LoggerFactory.getLogger( Statiflex.class ); + + + /** + * Private constructor, no instantiation + */ + private Statiflex() + { + } + + + /** + * Changes the value of a private static final field in a class + * Note: Compiler optimization might inline static final fields which will break this, use with caution + * @param clazz Class to modify + * @param fieldName Field to modify + * @param value Value to set + * @return true if set succeeded, false otherwise + * @throws NoSuchFieldException Thrown if the field specified was not found + */ + public static boolean flex( Class clazz, String fieldName, Object value ) throws NoSuchFieldException + { + return flex( clazz.getDeclaredField( fieldName ), value ); + } + + + /** + * Changes the value of a private static final field + * @param field Field to modify + * @param value Value to set + * @return true if set succeeded, false otherwise + */ + private static boolean flex( Field field, Object value ) + { + try { + Field modifiersField = Field.class.getDeclaredField( "modifiers" ); + boolean isModifierAccessible = modifiersField.isAccessible(); + modifiersField.setAccessible( true ); + modifiersField.setInt( field, field.getModifiers() & ~Modifier.FINAL ); + + boolean isAccessible = field.isAccessible(); + field.setAccessible( true ); + field.set( null, value ); + + field.setAccessible( isAccessible ); + modifiersField.setAccessible( isModifierAccessible ); + return true; + } catch ( IllegalAccessException e ) { + LOG.error( "Could not access field {}", field.getName(), e ); + } catch ( NoSuchFieldException e ) { + LOG.error( "Could not find field, cannot modify value", e ); + } + return false; + } +} diff --git a/statiflex/src/main/resources/log4j.properties b/statiflex/src/main/resources/log4j.properties new file mode 100644 index 0000000..d42ce42 --- /dev/null +++ b/statiflex/src/main/resources/log4j.properties @@ -0,0 +1,8 @@ +# Root logger option +log4j.rootLogger=INFO, stdout + +# Direct log messages to stdout +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.Target=System.out +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n diff --git a/statiflex/src/test/java/com/caffinc/statiflex/StatiflexTest.java b/statiflex/src/test/java/com/caffinc/statiflex/StatiflexTest.java new file mode 100644 index 0000000..b908f5c --- /dev/null +++ b/statiflex/src/test/java/com/caffinc/statiflex/StatiflexTest.java @@ -0,0 +1,33 @@ +package com.caffinc.statiflex; + +import org.junit.Assert; +import org.junit.Test; + + +/** + * Tests the Statiflex class + * @author Sriram + */ +public class StatiflexTest +{ + static class DummyClass + { + private static final String DUMMY_FIELD = getDummyValue(); + + + private static String getDummyValue() + { + return "TEST"; + } + } + + + @Test + public void testFlex() throws Exception + { + Assert.assertEquals( "private static final value should be TEST", "TEST", DummyClass.DUMMY_FIELD ); + Statiflex.flex( DummyClass.class, "DUMMY_FIELD", "TESTED" ); + Assert.assertEquals( "private static final value should be TESTED after flexing", "TESTED", DummyClass + .DUMMY_FIELD ); + } +}