diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..8a1fa2a --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,23 @@ +name: Build + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + maven: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Temurin JDK 21 + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: '21' + cache: maven + + - name: Build with Maven + run: mvn -B -Dmaven.repo.local=.m2 clean verify diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..c2c3d45 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,30 @@ +# Repository Guidelines + +## Project Structure & Module Organization +- `src/main/java/org/azeckoski/reflectutils/` hosts the runtime code; key subpackages include `converters`, `transcoders` (Jackson-backed JSON/XML support), `annotations`, and `interfaces`. +- Caching and core helpers live alongside the public APIs; caches prefer `WeakHashMap`/`ConcurrentHashMap` implementations—new utilities should follow this pattern. +- Tests under `src/test/java` mirror the production layout; reuse fixtures in `classes` rather than inventing bespoke beans. +- Build outputs land in `target/`; always run `mvn clean` before committing to avoid stray artifacts. + +## Build, Test, and Development Commands +- `mvn clean verify` compiles against JDK 21, runs the JUnit 5 suite, and produces coverage via JaCoCo. +- `mvn -DskipTests package` is handy for packaging when tests are covered elsewhere. +- `mvn -P release deploy` signs and stages artifacts to OSSRH; ensure credentials exist in `~/.m2/settings.xml`. + +## Coding Style & Naming Conventions +- Use 4-space indentation with braces on the same line; prefer explicit types over `var` unless readability improves. +- Embrace modern Java 21 features (records, pattern matching) when they simplify code, but keep APIs source-compatibility friendly. +- New subpackages should have concise, descriptive names (e.g., `cache`, `transcoders.jackson`). +- Source files are UTF-8; group imports by domain and keep static imports separate. + +## Testing Guidelines +- Tests are JUnit 5 (`@Test`), using `org.junit.jupiter.api.Assertions` statics. +- For JSON/XML scenarios, assert using decoded `Map` representations rather than string equality. +- Favor focused unit tests over giant integration fixtures; extend or reuse helpers in `classes` and `annotations`. +- Run `mvn clean verify` before opening a PR; capture any CI-specific flakes in the PR description. + +## Commit & Pull Request Guidelines +- Write imperative, scoped commit messages (e.g., `Replace beanutils cache with WeakHashMap`). +- Reference GitHub issues in branch names or PR titles (e.g., `modernize/jdk21-cache`). +- Document behavior or API changes in the PR body; include sample payloads when serializer output changes. +- Keep `target/` and other build outputs out of commits; prefer smaller PRs that are easy to review. diff --git a/README.md b/README.md index 31ec2f2..9994936 100644 --- a/README.md +++ b/README.md @@ -1,97 +1,45 @@ # reflectutils -A set of reflection utilities and miscellaneous utilities related to working with classes and their fields with no dependencies which is compatible with java 1.5 and generics (and the higher versions of Java as well). -# Features: -These are built to be compatible with Apache Commons BeanUtils (http://commons.apache.org/proper/commons-beanutils/) and the nesting structure works the same, refer to the apache BeanUtils? project docs for details. Support for Apache DynaClass? / DynaBean? is included. Current users of beanutils should be able to drop in these utilities and gain the functionality with minimal code changes. - -Handles field operations for properties (getters and setters), partial properties (only getter or only setter), and fields. This is configurable to use the fields only, properties only, or the hybrid approach (default). This improves upon the BeanUtils? limitation of handling only properties or the Google utilities limitation of handling only fields. - -Getting and setting fields supports simple, nested, indexed, and mapped values - -**Simple:** Get/set a field in a bean (or map), Example: "title", "id" -**Nested:** Get/set a field in a bean which is contained in another bean, Example: "someBean.title", "someBean.id" -**Indexed:** Get/set a list/array item by index in a bean, Example: "myList1?", "anArray2?" -**Mapped:** Get/set a map entry by key in a bean, Example: "myMap(key)", "someMap(thing)" - -Includes support for dealing with annotations and working with fields which have annotations on them. Methods for finding fields with an annotation and finding all annotations in a class or on a fields are included. - -Includes support for deep cloning, deep copying, and populating objects using auto-conversion. Also includes support for fuzzy copies where object data can be copied from one object to another without the objects being the same type. - -Also includes an extendable conversion system for converting between java types. This system also handles conversions between arrays, maps, collections, enums, and scalars and improves upon the apache system by handling more types and handling object holders. Support for construction of any class and a set of utilities for determining what types of objects you are working with are also included. A method for executing a specific constructor can be used if more control is needed. - -Includes transcoders (encoder/decoder) for conversion of class data to and from JSON and XML. The transcoders are clean and simple and work with any type of object. They will default to converting the incoming data into maps of simple java objects but these can be converted to the correct objects using the reflection utilities if desired. - -The utilities cache reflection data for high performance operation but uses weak/soft caching to avoid holding open ClassLoaders? and causing the caches to exist in memory permanently. The ability to override the caching mechanism with your own is supported. - -The utilities are modular and are meant to be extendable and overridable. All methods are protected or public so that the various utility classes can be easily overridden if needed. - -Sample code: -Examples operate on the class at the bottom (TestEntity). There are more samples in the javadocs. - - Getting a value from an object field - TestEntity thing = new TestEntity(); - Object value = ReflectUtils.getInstance().getFieldValue(thing, "entityId"); - // value will be "33" - Setting a value on an object field - TestEntity thing = new TestEntity(); - ReflectUtils.getInstance().setFieldValue(thing, "entityId", 33); - // value of thing.getEntityId() will be "33", value is autoconverted into the right type - Setting a nested value on an object field - Object thing = new HashMap(); // using a hashmap for simplicity here, could easily be nested POJOs - ReflectUtils.getInstance().setFieldValue(thing, "person.contactInfo.name", "aaronz"); - // the value of the name field which is on the object in the contactInfo field which is on the object in the person field on the thing object is set to "aaronz" - Constructing classes - List l = ReflectUtils.getInstance().constructClass(List.class); - Class clazz = TestEntity.class; - Object o = ReflectUtils.getInstance().constructClass(clazz); - // o will be an instance of TestEntity - TestEntity?.class (comes directly from the test cases) - - public class TestEntity { - private Long id = new Long(3); - private String entityId = "33"; - @TestAnnote - private String extra = null; - private Boolean bool = null; - private String[] sArray = {"1","2"}; - - public String getPrefix() { - return "crud"; - } - public String createEntity(Object entity) { - return "1"; - } - @TestAnnote - public String getEntityId() { - return entityId; - } - public void setEntityId(String entityId) { - this.entityId = entityId; - } - public Long getId() { - return id; - } - public void setId(Long id) { - this.id = id; - } - @TestAnnoteField1 - public String getExtra() { - return extra; - } - @TestAnnoteField2("TEST") - public void setExtra(String extra) { - this.extra = extra; - } - public String[] getSArray() { - return sArray; - } - public void setSArray(String[] array) { - sArray = array; - } - public Boolean getBool() { - return bool; - } - public void setBool(Boolean bool) { - this.bool = bool; - } - } +Modern reflection utilities for Java 21+, providing convenient field/property access, deep cloning, conversion helpers, and lightweight JSON/XML transcoders powered by Jackson. The library is dependency-light, thread-safe, and designed to integrate with contemporary JVM applications. + +## Highlights +- Unified field access: read/write simple, nested, indexed, or mapped properties using `FieldUtils` and `ReflectUtils`. +- Pluggable caching: metadata caches default to `WeakHashMap` to avoid classloader leaks while keeping lookups fast. +- Type conversion: `ConversionUtils` covers primitives, collections, maps, enums, arrays, and common I/O types. +- Jackson-based transcoders: encode/decode arbitrary objects to JSON or XML via Jackson `ObjectMapper`/`XmlMapper`. +- Extensible annotations: helpers detect custom annotations (e.g., `@ReflectTransient`) when building metadata. + +## Requirements +- JDK 21 or newer +- Maven 3.9+ + +## Build & Test +```bash +mvn clean verify +``` +This runs the JUnit 5 suite and generates a JaCoCo coverage report in `target/site/jacoco`. + +For a quicker iteration cycle: +```bash +mvn -DskipTests package +``` + +## Quick Start +```java +ReflectUtils reflect = ReflectUtils.getInstance(); +TestBean bean = new TestBean(); +reflect.setFieldValue(bean, "address.city", "Lisbon"); +String city = (String) reflect.getFieldValue(bean, "address.city"); + +JSONTranscoder transcoder = new JSONTranscoder(true, true, true); +Map meta = Map.of("source", "demo"); +String json = transcoder.encode(bean, "bean", meta); +Map decoded = transcoder.decode(json); +``` + +## Contributing +- Follow the guidelines in `AGENTS.md` for style, testing, and PR expectations. +- Submit issues or PRs via GitHub; keep changes focused and well-tested (`mvn clean verify`). + +## License +Apache License 2.0. See `LICENSE` for details. diff --git a/pom.xml b/pom.xml index b2a27ed..3519ea5 100644 --- a/pom.xml +++ b/pom.xml @@ -1,356 +1,291 @@ - + 4.0.0 + org.azeckoski reflectutils + 0.10.0-SNAPSHOT jar - 0.9.21-SNAPSHOT + Reflection Utilities - http://code.google.com/p/reflectutils/ + + Modern reflection helpers for Java 21+, including conversion utilities and lightweight transcoders. + + https://github.com/azeckoski/reflectutils 2006 - A set of reflection utilities and miscellaneous utilities related to - working with classes and their fields with no dependencies which is compatible - with java 1.5 and generics. The package was originally created by Aaron Zeckoski - for the Sakai Project and Generic DAO project but was repackaged to make it - distributable by request. It is used in the RSF framework - (http://www2.caret.cam.ac.uk/rsfwiki/) and the EntityBroker among other things. - Note about the BeanUtils provided dependency: BeanUtils is not required if you are - not using it in your project. Note about the Hibernate provided dependency: - Hibernate is not required if you are not using it in your project. - - 1.8.0 - UTF-8 - + - Apache License 2 - http://www.apache.org/licenses/LICENSE-2.0 - For source code + Apache License, Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0 + repo Creative Commons Attribution 3.0 - http://creativecommons.org/licenses/by-sa/3.0/ - For documentation and other materials + https://creativecommons.org/licenses/by/3.0/ + repo + aaronz@vt.edu Aaron Zeckoski azeckoski@vt.edu - http://tinyurl.com/azprofile Zeckoski - http://zeckoski.org/ + https://zeckoski.org/ - Project Manager Architect Developer - 0 + UTC + + + https://github.com/azeckoski/reflectutils + scm:git:https://github.com/azeckoski/reflectutils.git + scm:git:git@github.com:azeckoski/reflectutils.git + HEAD + + ossrh - https://oss.sonatype.org/content/repositories/snapshots + https://s01.oss.sonatype.org/content/repositories/snapshots/ ossrh - https://oss.sonatype.org/service/local/staging/deploy/maven2/ + https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/ - - local - Local Test - file:///tmp/reflectutils/site - - - - https://github.com/azeckoski/reflectutils - scm:git:git@github.com:azeckoski/reflectutils.git - scm:git:git@github.com:azeckoski/reflectutils.git - HEAD - + + UTF-8 + UTF-8 + 21 + true + 3.12.1 + 3.2.5 + 3.2.5 + 3.6.0 + 3.3.0 + 3.3.0 + 3.5.0 + 0.8.12 + 5.11.0 + + + + + + org.junit + junit-bom + ${junit.jupiter.version} + pom + import + + + + - - commons-beanutils - commons-beanutils - ${beanutils.version} - provided + com.fasterxml.jackson.core + jackson-databind + 2.17.1 + + + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + 2.17.1 + - junit - junit - 3.8.1 + org.junit.jupiter + junit-jupiter test - - - - - release - - - - org.apache.maven.plugins - maven-source-plugin - - - attach-sources - - jar-no-fork - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - - - attach-javadocs - - jar - - - - - - org.apache.maven.plugins - maven-gpg-plugin - - - sign-artifacts - verify - - sign - - - - - - org.sonatype.plugins - nexus-staging-maven-plugin - true - - ossrh - https://oss.sonatype.org/ - true - - - - - - + - - - - ${basedir} - - *.txt - src/main/**/*.java - src/main/**/*.html - src/main/**/*.xml - src/main/**/*.properties - src/test/**/*.java - - - - org.apache.maven.plugins - maven-source-plugin - 2.2.1 - - - org.apache.maven.plugins - maven-javadoc-plugin - 2.9.1 - - ${basedir}/src/main/java/overview.html - - http://java.sun.com/j2se/1.5.0/docs/api/ - http://commons.apache.org/beanutils/apidocs/ - - true - true - -Xdoclint:none - - - - org.apache.maven.plugins - maven-release-plugin - 2.5 - - true - false - release - deploy - - - - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.3 - - - org.apache.maven.plugins - maven-gpg-plugin - 1.5 - - - org.codehaus.mojo - cobertura-maven-plugin - 2.0 + maven-compiler-plugin + ${maven.compiler.plugin.version} org.apache.maven.plugins maven-surefire-plugin - 2.18.1 + ${maven.surefire.plugin.version} org.apache.maven.plugins - maven-pmd-plugin - 3.4 + maven-failsafe-plugin + ${maven.failsafe.plugin.version} org.apache.maven.plugins - maven-changelog-plugin - 2.3 + maven-javadoc-plugin + ${maven.javadoc.plugin.version} org.apache.maven.plugins - maven-jxr-plugin - 2.5 - - - org.codehaus.mojo - jdepend-maven-plugin - 2.0 + maven-source-plugin + ${maven.source.plugin.version} org.apache.maven.plugins - maven-project-info-reports-plugin - 2.8 - - - org.codehaus.mojo - taglist-maven-plugin - 2.4 + maven-jar-plugin + ${maven.jar.plugin.version} - + org.apache.maven.plugins - maven-surefire-plugin - 2.18.1 - - - **/Test*.java - - - **/*Test.java - - + maven-enforcer-plugin + ${maven.enforcer.plugin.version} + + + enforce-java + + enforce + + + + + [21,) + + + + + + - - - - - - + org.apache.maven.plugins maven-compiler-plugin - 1.5 - 1.5 + ${maven.compiler.release} + ${maven.compiler.parameters} - - - org.apache.maven.plugins - maven-javadoc-plugin - - - org.codehaus.mojo - cobertura-maven-plugin - - - org.apache.maven.plugins - maven-pmd-plugin + maven-jar-plugin - 1.5 - - /rulesets/java/basic.xml - /rulesets/java/codesize.xml - /rulesets/java/design.xml - /rulesets/java/finalizers.xml - /rulesets/java/imports.xml - /rulesets/java/logging-java.xml - /rulesets/java/migrating.xml - /rulesets/java/strings.xml - - /rulesets/java/unusedcode.xml - - xml - true - utf-8 - 100 + + + true + + + - org.apache.maven.plugins - maven-changelog-plugin + maven-surefire-plugin - range - 90 + false + - - org.codehaus.mojo - taglist-maven-plugin + org.apache.maven.plugins + maven-failsafe-plugin - - TODO - FIXME - @deprecated - + false + - - org.codehaus.mojo - jdepend-maven-plugin + org.jacoco + jacoco-maven-plugin + ${jacoco.version} + + + + prepare-agent + + + + report + verify + + report + + + + - org.apache.maven.plugins - maven-jxr-plugin + maven-javadoc-plugin - true - apidocs + false + ${project.build.sourceEncoding} + none + + https://docs.oracle.com/en/java/javase/21/docs/api/ + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar-no-fork + + + + - + + + + + release + + + + org.apache.maven.plugins + maven-gpg-plugin + 3.2.4 + + + sign-artifacts + verify + + sign + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.13 + true + + ossrh + https://s01.oss.sonatype.org/ + true + + + + + + diff --git a/readme.txt b/readme.txt deleted file mode 100644 index 27081ba..0000000 --- a/readme.txt +++ /dev/null @@ -1,61 +0,0 @@ -These are the reflection utilities for java 1.5 written by Aaron Zeckoski (aaronz@vt.edu) - -Building this project and putting it in your repository (maven2: http://maven.apache.org/): -Maven2: run "mvn clean install" from the root source directory of this project - -See the javadocs and source code (included in the jar and online) and the project website. -http://code.google.com/p/reflectutils/ - -A set of reflection utilities and miscellaneous utilities related to working with classes and their fields with no dependencies which is compatible with java 1.5 and generics. - -Features: -These are built to be compatible with Apache Commons BeanUtils and the nesting structure works the same, refer to the apache BeanUtils? project docs for details. Support for Apache DynaClass? / DynaBean? is included. Current users of beanutils should be able to drop in these utilities and gain the functionality with minimal code changes. - -Handles field operations for properties (getters and setters), partial properties (only getter or only setter), and fields. This is configurable to use the fields only, properties only, or the hybrid approach (default). This improves upon the BeanUtils? limitation of handling only properties or the Google utilities limitation of handling only fields. - -Getting and setting fields supports simple, nested, indexed, and mapped values - - * Simple: Get/set a field in a bean (or map), Example: "title", "id" - * Nested: Get/set a field in a bean which is contained in another bean, Example: "someBean.title", "someBean.id" - * Indexed: Get/set a list/array item by index in a bean, Example: "myList1?", "anArray2?" - * Mapped: Get/set a map entry by key in a bean, Example: "myMap(key)", "someMap(thing)" - -Includes support for dealing with annotations and working with fields which have annotations on them. Methods for finding fields with an annotation and finding all annotations in a class or on a fields are included. - -Includes support for deep cloning, deep copying, and populating objects using auto-conversion. Also includes support for fuzzy copies where object data can be copied from one object to another without the objects being the same type. - -Also includes an extendable conversion system for converting between java types. This system also handles conversions between arrays, maps, collections, enums, and scalars and improves upon the apache system by handling more types and handling object holders. Support for construction of any class and a set of utilities for determining what types of objects you are working with are also included. A method for executing a specific constructor can be used if more control if needed. - -Includes transcoders (encoder/decoder) for conversion of class data to and from JSON and XML. The transcoders are clean and simple and work with any type of object. They will default to converting the incoming data into maps of simple java objects but these can be converted to the correct objects using the reflection utilities if desired. - -The utilities cache reflection data for high performance operation but uses weak/soft caching to avoid holding open ClassLoaders? and causing the caches to exist in memory permanently. The ability to override the caching mechanism with your own is supported. - -The utilities are modular and are meant to be extendable and overridable. All methods are protected or public so that the various utility classes can be easily overridden if needed. -Sample code: - -Examples operate on the class at the bottom (TestEntity?). There are more samples in the guide. - - * Getting a value from an object field - - TestEntity thing = new TestEntity(); - Object value = ReflectUtils.getInstance().getFieldValue(thing, "entityId"); - // value will be "33" - - * Setting a value on an object field - - TestEntity thing = new TestEntity(); - ReflectUtils.getInstance().setFieldValue(thing, "entityId", 33); - // value of thing.getEntityId() will be "33", value is autoconverted into the right type - - * Setting a nested value on an object field - - Object thing = new HashMap(); // using a hashmap for simplicity here, could easily be nested POJOs - ReflectUtils.getInstance().setFieldValue(thing, "person.contactInfo.name", "aaronz"); - // the value of the name field which is on the object in the contactInfo field which is on the object in the person field on the thing object is set to "aaronz" - - * Constructing classes - - List l = ReflectUtils.getInstance().constructClass(List.class); - Class clazz = TestEntity.class; - Object o = ReflectUtils.getInstance().constructClass(clazz); - // o will be an instance of TestEntity diff --git a/src/main/java/org/azeckoski/reflectutils/ClassData.java b/src/main/java/org/azeckoski/reflectutils/ClassData.java index dc8fcf1..a52d454 100644 --- a/src/main/java/org/azeckoski/reflectutils/ClassData.java +++ b/src/main/java/org/azeckoski/reflectutils/ClassData.java @@ -16,8 +16,10 @@ import java.io.Serializable; import java.lang.annotation.Annotation; +import java.lang.reflect.AccessibleObject; import java.lang.reflect.Constructor; import java.lang.reflect.Field; +import java.lang.reflect.InaccessibleObjectException; import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -135,20 +137,8 @@ protected void getAllThings(final Class type, final List fList, final for (final Field field : fields) { if (field != null) { int modifiers = field.getModifiers(); - if (Modifier.isPublic(modifiers)) { + if (Modifier.isPublic(modifiers) || trySetAccessible(field)) { fList.add(field); - } else { - try { - AccessController.doPrivileged(new PrivilegedAction() { - public T run() { - field.setAccessible(true); - return null; - } - }); - fList.add(field); - } catch (SecurityException e) { - // oh well, this does not get added then - } } } } @@ -156,20 +146,8 @@ public T run() { for (final Method method : methods) { if (method != null) { int modifiers = method.getModifiers(); - if (Modifier.isPublic(modifiers)) { + if (Modifier.isPublic(modifiers) || trySetAccessible(method)) { mList.add(method); - } else { - try { - AccessController.doPrivileged(new PrivilegedAction() { - public T run() { - method.setAccessible(true); - return null; - } - }); - mList.add(method); - } catch (SecurityException e) { - // oh well, this does not get added then - } } } } @@ -178,20 +156,8 @@ public T run() { // need to avoid the Object constructor if (!Object.class.equals(type) && constructor != null) { int modifiers = constructor.getModifiers(); - if (Modifier.isPublic(modifiers)) { + if (Modifier.isPublic(modifiers) || trySetAccessible(constructor)) { cList.add((Constructor)constructor); - } else { - try { - AccessController.doPrivileged(new PrivilegedAction() { - public T run() { - constructor.setAccessible(true); - return null; - } - }); - cList.add((Constructor)constructor); - } catch (SecurityException e) { - // oh well, this does not get added then - } } } } @@ -210,6 +176,23 @@ public T run() { } } + private boolean trySetAccessible(final AccessibleObject object) { + try { + return AccessController.doPrivileged(new PrivilegedAction() { + public Boolean run() { + try { + object.setAccessible(true); + return Boolean.TRUE; + } catch (InaccessibleObjectException ex) { + return Boolean.FALSE; + } + } + }); + } catch (SecurityException e) { + return false; + } + } + /** * @return the type of the class this data represents */ @@ -289,4 +272,3 @@ public static final String getModifierPrefix(int modifier) { } } - diff --git a/src/main/java/org/azeckoski/reflectutils/ClassDataCacher.java b/src/main/java/org/azeckoski/reflectutils/ClassDataCacher.java index 8a9eed8..b8b38f0 100644 --- a/src/main/java/org/azeckoski/reflectutils/ClassDataCacher.java +++ b/src/main/java/org/azeckoski/reflectutils/ClassDataCacher.java @@ -15,11 +15,10 @@ package org.azeckoski.reflectutils; import org.azeckoski.reflectutils.ClassFields.FieldFindMode; -import org.azeckoski.reflectutils.refmap.ReferenceMap; -import org.azeckoski.reflectutils.refmap.ReferenceType; - import java.lang.ref.SoftReference; +import java.util.Collections; import java.util.Map; +import java.util.WeakHashMap; /** * Class which provides access to the analysis objects and the cached reflection data @@ -117,9 +116,7 @@ public boolean isIncludeClassField() { @SuppressWarnings("unchecked") protected Map, ClassFields> getReflectionCache() { if (reflectionCache == null) { - // internally we are using the ReferenceMap (from the Guice codebase) - // modeled after the groovy reflection caching (weak -> soft) - reflectionCache = new ReferenceMap,ClassFields>(ReferenceType.WEAK, ReferenceType.SOFT); + reflectionCache = Collections.synchronizedMap(new WeakHashMap, ClassFields>()); } return reflectionCache; } @@ -134,7 +131,9 @@ protected Map, ClassFields> getReflectionCache() { @SuppressWarnings("unchecked") public void setReflectionCache(Map, ClassFields> reflectionCache) { if (reflectionCache != null) { - this.reflectionCache.clear(); + if (this.reflectionCache != null) { + this.reflectionCache.clear(); + } this.reflectionCache = reflectionCache; } else { getReflectionCache(); diff --git a/src/main/java/org/azeckoski/reflectutils/ClassFields.java b/src/main/java/org/azeckoski/reflectutils/ClassFields.java index 4ef737b..3269906 100644 --- a/src/main/java/org/azeckoski/reflectutils/ClassFields.java +++ b/src/main/java/org/azeckoski/reflectutils/ClassFields.java @@ -18,8 +18,6 @@ import org.azeckoski.reflectutils.annotations.ReflectIncludeStaticFields; import org.azeckoski.reflectutils.annotations.ReflectTransientClassFields; import org.azeckoski.reflectutils.exceptions.FieldnameNotFoundException; -import org.azeckoski.reflectutils.map.ArrayOrderedMap; -import org.azeckoski.reflectutils.map.OrderedMap; import java.beans.*; import java.lang.annotation.Annotation; @@ -188,7 +186,7 @@ public List getFieldNames() { */ public List getFieldNames(FieldsFilter filter) { List names = new ArrayList(); - for (Entry entry : namesToProperties.getEntries()) { + for (Entry entry : namesToProperties.entrySet()) { String name = entry.getKey(); ClassProperty cp = entry.getValue(); if ( isFieldInFilter(cp, filter) ) { @@ -212,9 +210,8 @@ public Map> getFieldTypes() { * @return the map of fieldName -> field type */ public Map> getFieldTypes(FieldsFilter filter) { - OrderedMap> fieldTypes = new ArrayOrderedMap>(); - fieldTypes.setName(getStoredClass().getName()); - for (Entry entry : namesToProperties.getEntries()) { + Map> fieldTypes = new LinkedHashMap>(); + for (Entry entry : namesToProperties.entrySet()) { String name = entry.getKey(); ClassProperty cp = entry.getValue(); if ( isFieldInFilter(cp, filter) ) { @@ -475,7 +472,7 @@ public ClassData getClassData() { private final Set transientFieldNames = new HashSet(); // WARNING: all these things can hold open a ClassLoader private final ClassData classData; - private final OrderedMap namesToProperties; // this contains all properties data (includes partials) + private final Map namesToProperties; // this contains all properties data (includes partials) // PUBLIC constructors @@ -508,7 +505,7 @@ public ClassFields(Class fieldClass, Method[] getterMethods, Method[] setterM classData = new ClassData(fieldClass); fieldFindMode = FieldFindMode.HYBRID; // set the properties - namesToProperties = new ArrayOrderedMap(getterMethods.length + namesToProperties = new LinkedHashMap(getterMethods.length + publicFields.length); for (int i = 0; i < getterMethods.length; i++) { if (getterMethods[i] != null && setterMethods[i] != null) { @@ -544,7 +541,7 @@ public ClassFields(Class fieldClass, PropertyDescriptor[] descriptors, Field[ } classData = new ClassData(fieldClass); fieldFindMode = FieldFindMode.HYBRID; - namesToProperties = new ArrayOrderedMap(descriptors.length + publicFields.length); + namesToProperties = new LinkedHashMap(descriptors.length + publicFields.length); populateProperties(descriptors); populateFields(publicFields); populateAnnotationsFields(); @@ -611,7 +608,7 @@ public ClassFields(Class fieldClass, FieldFindMode findMode, boolean useIntro classData = new ClassData(fieldClass); fieldFindMode = findMode; includeClassField = includeClassFields; - namesToProperties = new ArrayOrderedMap(); + namesToProperties = new LinkedHashMap(); // check for reflect annotations on the class List annotations = classData.getAnnotations(); @@ -892,7 +889,7 @@ private String checkPropertyMethods(Method getter, Method setter) { @SuppressWarnings("SameParameterValue") private List findProperties(boolean includePartial) { // find the property methods from all public methods - Map propertyMap = new ArrayOrderedMap(); + Map propertyMap = new LinkedHashMap(); for (Method method : classData.getPublicMethods()) { Class[] paramTypes = method.getParameterTypes(); String name = method.getName(); diff --git a/src/main/java/org/azeckoski/reflectutils/ClassProperty.java b/src/main/java/org/azeckoski/reflectutils/ClassProperty.java index 453fadd..35148b6 100644 --- a/src/main/java/org/azeckoski/reflectutils/ClassProperty.java +++ b/src/main/java/org/azeckoski/reflectutils/ClassProperty.java @@ -20,12 +20,11 @@ import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collection; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.azeckoski.reflectutils.annotations.ReflectTransient; -import org.azeckoski.reflectutils.map.ArrayOrderedMap; -import org.azeckoski.reflectutils.map.OrderedMap; /** @@ -56,11 +55,11 @@ public class ClassProperty { protected boolean indexed = false; protected boolean arrayed = false; - private OrderedMap, Annotation> propertyAnnotations; // contains all annotations on this property + private Map, Annotation> propertyAnnotations; // contains all annotations on this property protected void addAnnotation(Annotation annotation) { if (annotation != null) { if (propertyAnnotations == null) { - propertyAnnotations = new ArrayOrderedMap, Annotation>(); + propertyAnnotations = new LinkedHashMap, Annotation>(); } Class c = annotation.annotationType(); if (! propertyAnnotations.containsKey(c)) { diff --git a/src/main/java/org/azeckoski/reflectutils/ConstructorUtils.java b/src/main/java/org/azeckoski/reflectutils/ConstructorUtils.java index 8d51b0a..5c8e061 100644 --- a/src/main/java/org/azeckoski/reflectutils/ConstructorUtils.java +++ b/src/main/java/org/azeckoski/reflectutils/ConstructorUtils.java @@ -34,6 +34,8 @@ import java.util.Date; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -41,9 +43,6 @@ import java.util.SortedSet; import java.util.TreeMap; import java.util.TreeSet; -import java.util.Vector; - -import org.azeckoski.reflectutils.map.ArrayOrderedMap; /** * Class which provides methods for dealing with class constructors, @@ -332,7 +331,7 @@ public static boolean isClassList(Class type) { /** * @param type any class - * @return true if this class is a collection (e.g. {@link Collection}, {@link HashSet}, {@link Vector}) + * @return true if this class is a collection (e.g. {@link Collection}, {@link HashSet}, {@link ArrayList}) */ public static boolean isClassCollection(Class type) { checkNull(type); @@ -440,14 +439,13 @@ public static Class getClassFromInterface(Class type) { } else if (SortedMap.class.isAssignableFrom(type)) { toType = (Class) TreeMap.class; } else if ( isClassList(type) ) { - // we use the thread safe version of list by default - toType = (Class) Vector.class; + toType = (Class) ArrayList.class; } else if (Set.class.isAssignableFrom(type)) { - toType = (Class) HashSet.class; + toType = (Class) LinkedHashSet.class; } else if ( isClassMap(type) ) { - toType = (Class) ArrayOrderedMap.class; + toType = (Class) LinkedHashMap.class; } else if ( isClassCollection(type) ) { - toType = (Class) Vector.class; + toType = (Class) ArrayList.class; // Serializable should stay at the end } else if (Serializable.class.isAssignableFrom(type)) { // if it is serializable then it is probably a string right? @@ -640,10 +638,19 @@ public T constructClass(Class type) { } } if (newC == null) { + Throwable fallbackFailure = null; try { - // this should work 99% of the time - newC = (T) type.newInstance(); - } catch (Exception e) { + Constructor declaredConstructor = type.getDeclaredConstructor(); + if (!declaredConstructor.canAccess(null)) { + declaredConstructor.setAccessible(true); + } + newC = declaredConstructor.newInstance(); + } catch (NoSuchMethodException ignored) { + // continue to constructor iteration below + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { + fallbackFailure = e; + } + if (newC == null) { // now we will try to use the various constructors by giving them null values to construct the object List> constructors = null; if ( ConstructorUtils.isClassBean(type) ) { @@ -661,24 +668,24 @@ public T constructClass(Class type) { for (Constructor constructor : constructors) { Object[] params = new Object[ constructor.getParameterTypes().length ]; try { - newC = (T) constructor.newInstance(params); + if (!constructor.canAccess(null)) { + constructor.setAccessible(true); + } + newC = constructor.newInstance(params); break; - } catch (IllegalArgumentException e1) { - // oh well - } catch (InstantiationException e1) { - // tough cookies - } catch (IllegalAccessException e1) { - // them's the breaks - } catch (InvocationTargetException e1) { - // life's tough - } catch (ExceptionInInitializerError e1) { - // meh + } catch (IllegalArgumentException | InstantiationException | IllegalAccessException | + InvocationTargetException | ExceptionInInitializerError e1) { + // ignore and continue + if (fallbackFailure == null) { + fallbackFailure = e1; + } } - // ignore any exceptions and keep trying } if (newC == null) { - // all attempts failed - throw new IllegalArgumentException("Could not construct object for class (" + type.getName() + ") using newInstance or using any of the constructors: " + e.getMessage(), e); + if (fallbackFailure == null) { + fallbackFailure = new IllegalArgumentException("No accessible constructors found for class " + type.getName()); + } + throw new IllegalArgumentException("Could not construct object for class (" + type.getName() + ")", fallbackFailure); } } } diff --git a/src/main/java/org/azeckoski/reflectutils/ConversionUtils.java b/src/main/java/org/azeckoski/reflectutils/ConversionUtils.java index 6103d79..c9ec15e 100644 --- a/src/main/java/org/azeckoski/reflectutils/ConversionUtils.java +++ b/src/main/java/org/azeckoski/reflectutils/ConversionUtils.java @@ -23,9 +23,9 @@ import java.util.Calendar; import java.util.Collection; import java.util.Date; +import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.Vector; import java.util.Map.Entry; import org.azeckoski.reflectutils.converters.ArrayConverter; @@ -56,8 +56,8 @@ import org.azeckoski.reflectutils.converters.api.Converter; import org.azeckoski.reflectutils.converters.api.InterfaceConverter; import org.azeckoski.reflectutils.converters.api.VariableConverter; -import org.azeckoski.reflectutils.refmap.ReferenceMap; -import org.azeckoski.reflectutils.refmap.ReferenceType; + +import java.util.concurrent.ConcurrentHashMap; /** * Class which provides methods for converting between object types, @@ -116,7 +116,7 @@ protected Map, Converter> getConverters() { */ protected void loadDefaultConverters() { if (converters == null) { - converters = new ReferenceMap, Converter>(ReferenceType.WEAK, ReferenceType.STRONG); + converters = new ConcurrentHashMap, Converter>(); } else { converters.clear(); } @@ -183,7 +183,7 @@ protected List getVariableConverters() { protected void loadDefaultVariableConverters() { if (variableConverters == null) { - variableConverters = new Vector(); + variableConverters = new ArrayList(); } else { clearVariableConverters(); } diff --git a/src/main/java/org/azeckoski/reflectutils/DeepUtils.java b/src/main/java/org/azeckoski/reflectutils/DeepUtils.java index 739610e..1fdf195 100644 --- a/src/main/java/org/azeckoski/reflectutils/DeepUtils.java +++ b/src/main/java/org/azeckoski/reflectutils/DeepUtils.java @@ -23,13 +23,12 @@ import java.util.Map; import java.util.Set; import java.util.Map.Entry; +import java.util.LinkedHashMap; import org.azeckoski.reflectutils.ClassFields.FieldsFilter; -import org.azeckoski.reflectutils.beanutils.FieldAdapter; import org.azeckoski.reflectutils.exceptions.FieldGetValueException; import org.azeckoski.reflectutils.exceptions.FieldSetValueException; import org.azeckoski.reflectutils.exceptions.FieldnameNotFoundException; -import org.azeckoski.reflectutils.map.ArrayOrderedMap; /** * Class which provides methods for handling deep operations:
@@ -67,10 +66,6 @@ protected FieldUtils getFieldUtils() { return FieldUtils.getInstance(); } - protected FieldAdapter getFieldAdapter() { - return getFieldUtils().getFieldAdapter(); - } - /** * Deep clone an object and all the values in it into a brand new object of the same type, * this will traverse the bean and will make new objects for all non-null values contained in the object @@ -311,7 +306,7 @@ protected Object internalDeepClone(Object bean, CopyDestination dest, int maxDep if ( ConstructorUtils.isClassBean(componentType) && CopyDestination.MAP.equals(dest)) { // special array component type for arrays of objects when map converting - componentType = ArrayOrderedMap.class; + componentType = LinkedHashMap.class; } copy = ArrayUtils.create(componentType, length); // now copy the stuff into it @@ -347,40 +342,11 @@ protected Object internalDeepClone(Object bean, CopyDestination dest, int maxDep continue; } } - } else if (getFieldAdapter().isAdaptableClass(beanClass)) { - // special handling for dynabeans - if (CopyDestination.MAP.equals(dest)) { - copy = new ArrayOrderedMap(); - } else { - copy = getFieldAdapter().newInstance(bean); // make new dynabean - } - List propertyNames = getFieldAdapter().getPropertyNames(bean); - for (String name : propertyNames) { - if ( fieldNamesToSkip != null - && fieldNamesToSkip.contains(name) ) { - continue; // skip to next - } - try { - Object value = getFieldAdapter().getSimpleValue(bean, name); - if (value == null && ignoreNulls) { - continue; - } - if (CopyDestination.MAP.equals(dest)) { - ((Map) copy).put(name, - internalDeepClone(value, dest, maxDepth, null, currentDepth, ignoreNulls, ignoreTransient) ); - } else { - getFieldUtils().setFieldValue(copy, name, - internalDeepClone(value, dest, maxDepth, null, currentDepth, ignoreNulls, ignoreTransient) ); - } - } catch (IllegalArgumentException e) { - // this is ok, field might not be readable so we will not clone it, continue on - } - } } else { // regular javabean FieldsFilter filter = FieldsFilter.COMPLETE; if (CopyDestination.MAP.equals(dest)) { - copy = new ArrayOrderedMap(); + copy = new LinkedHashMap(); // maps should pick up all readable fields if (ignoreTransient) { filter = FieldsFilter.SERIALIZABLE; @@ -523,27 +489,6 @@ protected void internalDeepCopy(Object orig, Object dest, int maxDepth, Set propertyNames = getFieldAdapter().getPropertyNames(orig); - for (String name : propertyNames) { - if ( fieldNamesToSkip != null - && fieldNamesToSkip.contains(name) ) { - continue; // skip to next - } - try { - Object value = getFieldAdapter().getSimpleValue(orig, name); - if (ignoreNulls && value == null) { - // don't copy this null over the existing value - } else { - getFieldUtils().setFieldValue(dest, name, - internalDeepClone(value, CopyDestination.ORIGINAL, maxDepth, null, currentDepth, ignoreNulls, false)); - } - } catch (FieldnameNotFoundException e) { - // it is ok for the objects to not be the same - } catch (IllegalArgumentException e) { - // it is ok for the objects to not be the same - } - } } else { // regular javabean Map values = getFieldUtils().getFieldValues(orig, FieldsFilter.READABLE, false); diff --git a/src/main/java/org/azeckoski/reflectutils/FieldUtils.java b/src/main/java/org/azeckoski/reflectutils/FieldUtils.java index 4457580..f4cf04e 100644 --- a/src/main/java/org/azeckoski/reflectutils/FieldUtils.java +++ b/src/main/java/org/azeckoski/reflectutils/FieldUtils.java @@ -18,19 +18,17 @@ import org.azeckoski.reflectutils.ClassProperty.IndexedProperty; import org.azeckoski.reflectutils.ClassProperty.MappedProperty; import org.azeckoski.reflectutils.beanutils.DefaultResolver; -import org.azeckoski.reflectutils.beanutils.FieldAdapter; -import org.azeckoski.reflectutils.beanutils.FieldAdapterManager; import org.azeckoski.reflectutils.beanutils.Resolver; import org.azeckoski.reflectutils.exceptions.FieldGetValueException; import org.azeckoski.reflectutils.exceptions.FieldSetValueException; import org.azeckoski.reflectutils.exceptions.FieldnameNotFoundException; -import org.azeckoski.reflectutils.map.ArrayOrderedMap; import java.lang.ref.SoftReference; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -66,8 +64,6 @@ protected FieldUtils() { public FieldUtils(Resolver resolver) { setResolver(resolver); - fieldAdapterManager = new FieldAdapterManager(); - FieldUtils.setInstance(this); } @@ -98,18 +94,6 @@ protected Resolver getResolver() { } return nameResolver; } - - - protected FieldAdapterManager fieldAdapterManager; - /** - * INTERNAL USAGE - * @return the field adapter being used by this set of field utils - */ - public FieldAdapter getFieldAdapter() { - return fieldAdapterManager.getFieldAdapter(); - } - - /** * Analyze a class and produce an object which contains information about it and its fields * @param @@ -253,9 +237,7 @@ public Class getFieldType(Object obj, String name) { String targetName = getResolver().getProperty(name); // simple name of target field // get the type Class fieldType; - if (fieldAdapterManager.isAdaptableObject(obj)) { - fieldType = fieldAdapterManager.getFieldAdapter().getFieldType(obj, targetName); - } else if ( ConstructorUtils.isClassObjectHolder(obj.getClass()) + if ( ConstructorUtils.isClassObjectHolder(obj.getClass()) || Object.class.equals(obj.getClass()) ) { // special handling for the holder types, needed because attempting to analyze a map or other container will cause a failure fieldType = Object.class; @@ -350,26 +332,22 @@ public Map getFieldValues(Object obj, FieldsFilter filter, boole if (obj == null) { throw new IllegalArgumentException("obj cannot be null"); } - Map values = new ArrayOrderedMap(); + Map values = new LinkedHashMap(); if (includeClassField) { // add as the first field values.put(ClassFields.FIELD_CLASS, obj.getClass()); } - if (fieldAdapterManager.isAdaptableObject(obj)) { - values.putAll( fieldAdapterManager.getFieldAdapter().getFieldValues(obj, filter) ); - } else { - Map> types = getFieldTypes(obj.getClass(), filter); - if (FieldsFilter.WRITEABLE.equals(filter)) { - types.clear(); - } - for (String name : types.keySet()) { - try { - Object o = getFieldValue(obj, name); - values.put(name, o); - } catch (RuntimeException e) { - // failed to get the value so we will skip this one - continue; - } + Map> types = getFieldTypes(obj.getClass(), filter); + if (FieldsFilter.WRITEABLE.equals(filter)) { + types.clear(); + } + for (String name : types.keySet()) { + try { + Object o = getFieldValue(obj, name); + values.put(name, o); + } catch (RuntimeException e) { + // failed to get the value so we will skip this one + continue; } } return values; @@ -588,7 +566,7 @@ protected Holder unpackNestedName(final String fullName, final Object object, bo Class type = getFieldType(obj, next); if (Object.class.equals(type)) { // indeterminate type so we will make a map - type = ArrayOrderedMap.class; + type = LinkedHashMap.class; } nestedBean = getConstructorUtils().constructClass(type); setFieldValue(obj, next, nestedBean, false); // need to put this new object into the parent @@ -629,29 +607,24 @@ protected Object getSimpleValue(Object obj, String name) { } Object value; - // Handle DynaBean instances specially - if (fieldAdapterManager.isAdaptableObject(obj)) { - value = fieldAdapterManager.getFieldAdapter().getSimpleValue(obj, name); - } else { - // normal bean - ClassFields cf = analyzeObject(obj); + // normal bean + ClassFields cf = analyzeObject(obj); + try { + // use the class property + ClassProperty cp = cf.getClassProperty(name); + value = findFieldValue(obj, cp); + } catch (FieldnameNotFoundException fnfe) { + // could not find this as a standard field so handle as internal lookup + ClassData cd = cf.getClassData(); + Field field = getFieldIfPossible(cd, name); + if (field == null) { + throw new FieldnameNotFoundException("Could not find field with name ("+name+") on object (" + obj + ") after extended look into non-visible fields", fnfe); + } try { - // use the class property - ClassProperty cp = cf.getClassProperty(name); - value = findFieldValue(obj, cp); - } catch (FieldnameNotFoundException fnfe) { - // could not find this as a standard field so handle as internal lookup - ClassData cd = cf.getClassData(); - Field field = getFieldIfPossible(cd, name); - if (field == null) { - throw new FieldnameNotFoundException("Could not find field with name ("+name+") on object (" + obj + ") after extended look into non-visible fields", fnfe); - } - try { - value = field.get(obj); - } catch (Exception e) { - // catching the general exception is correct here, translate the exception - throw new FieldGetValueException("Field get failure getting value for field ("+name+") from non-visible field in object: " + obj, name, obj, e); - } + value = field.get(obj); + } catch (Exception e) { + // catching the general exception is correct here, translate the exception + throw new FieldGetValueException("Field get failure getting value for field ("+name+") from non-visible field in object: " + obj, name, obj, e); } } return value; @@ -694,68 +667,55 @@ protected Object getIndexedValue(Object obj, String name) { } boolean indexedProperty = false; - // Handle DynaBean instances specially - if (fieldAdapterManager.isAdaptableObject(obj)) { - value = fieldAdapterManager.getFieldAdapter().getIndexedValue(obj, name, index); + boolean isArray = false; + Object indexedObject = null; + + if (obj.getClass().isArray()) { + indexedObject = obj; + isArray = true; + } else if (List.class.isAssignableFrom(obj.getClass())) { + indexedObject = obj; } else { - boolean isArray = false; - Object indexedObject = null; - if (obj.getClass().isArray()) { - indexedObject = obj; - isArray = true; - } else if (List.class.isAssignableFrom(obj.getClass())) { - indexedObject = obj; - } else { - // normal bean - ClassFields cf = analyzeObject(obj); - ClassProperty cp = cf.getClassProperty(name); - if (! cp.isIndexed()) { - throw new IllegalArgumentException("This field ("+name+") is not an indexed field"); - } - isArray = cp.isArray(); - // try to get the indexed getter and use that first - if (cp instanceof IndexedProperty) { - indexedProperty = true; - IndexedProperty icp = (IndexedProperty) cp; - try { - Method getter = icp.getIndexGetter(); - //noinspection RedundantArrayCreation - value = getter.invoke(obj, new Object[] {index}); - } catch (Exception e) { - // catching the general exception is correct here, translate the exception - throw new FieldGetValueException("Indexed getter method failure getting indexed (" - +index+") value for name ("+cp.getFieldName()+") from: " + obj, cp.getFieldName(), obj, e); - } - } else { - indexedObject = findFieldValue(obj, cp); + ClassFields cf = analyzeObject(obj); + ClassProperty cp = cf.getClassProperty(name); + if (!cp.isIndexed()) { + throw new IllegalArgumentException("This field (" + name + ") is not an indexed field"); + } + isArray = cp.isArray(); + if (cp instanceof IndexedProperty) { + indexedProperty = true; + IndexedProperty icp = (IndexedProperty) cp; + try { + Method getter = icp.getIndexGetter(); + value = getter.invoke(obj, index); + } catch (Exception e) { + throw new FieldGetValueException("Indexed getter method failure getting indexed (" + index + ") value for name (" + cp.getFieldName() + ") from: " + obj, cp.getFieldName(), obj, e); } } if (!indexedProperty) { - // now get the indexed value if possible - if (indexedObject != null) { - if (isArray) { - // this is an array - try { - // get value from array - value = Array.get(indexedObject, index); - } catch (ArrayIndexOutOfBoundsException e) { - throw new IllegalArgumentException("Index ("+index+") is out of bounds ("+Array.getLength(indexedObject)+") for the array: " + indexedObject, e); - } - } else { - // this better be a list - if (! List.class.isAssignableFrom(indexedObject.getClass())) { - throw new IllegalArgumentException("Field (" + name + ") does not appear to be indexed (not an array or a list)"); - } else { - // get value from list - try { - value = ((List)indexedObject).get(index); - } catch (IndexOutOfBoundsException e) { - throw new IllegalArgumentException("Index ("+index+") is out of bounds ("+((List)indexedObject).size()+") for the list: " + indexedObject, e); - } - } - } - } else { - throw new IllegalArgumentException("Indexed object is null, cannot retrieve index ("+index+") value from field ("+name+")"); + indexedObject = findFieldValue(obj, cp); + } + } + + if (!indexedProperty) { + if (indexedObject == null) { + throw new IllegalArgumentException("Indexed object is null, cannot retrieve index (" + index + ") value from field (" + name + ")"); + } + if (isArray) { + try { + value = Array.get(indexedObject, index); + } catch (ArrayIndexOutOfBoundsException e) { + throw new IllegalArgumentException("Index (" + index + ") is out of bounds (" + Array.getLength(indexedObject) + ") for the array: " + indexedObject, e); + } + } else { + if (!List.class.isAssignableFrom(indexedObject.getClass())) { + throw new IllegalArgumentException("Field (" + name + ") does not appear to be indexed (not an array or a list)"); + } + List list = (List) indexedObject; + try { + value = list.get(index); + } catch (IndexOutOfBoundsException e) { + throw new IllegalArgumentException("Index (" + index + ") is out of bounds (" + list.size() + ") for the list: " + indexedObject, e); } } } @@ -797,52 +757,47 @@ protected Object getMappedValue(Object obj, String name) { } boolean mappedProperty = false; - // Handle DynaBean instances specially - if (fieldAdapterManager.isAdaptableObject(obj)) { - value = fieldAdapterManager.getFieldAdapter().getMappedValue(obj, name, key); + Map map = null; + if (Map.class.isAssignableFrom(obj.getClass())) { + map = (Map) obj; } else { - Map map = null; - if (Map.class.isAssignableFrom(obj.getClass())) { - map = (Map) obj; - } else { - // normal bean - ClassFields cf = analyzeObject(obj); - ClassProperty cp = cf.getClassProperty(name); - if (! cp.isMapped()) { - throw new IllegalArgumentException("This field ("+name+") is not an mapped field"); + // normal bean + ClassFields cf = analyzeObject(obj); + ClassProperty cp = cf.getClassProperty(name); + if (! cp.isMapped()) { + throw new IllegalArgumentException("This field ("+name+") is not an mapped field"); + } + // try to get the mapped getter and use that first + if (cp instanceof MappedProperty) { + mappedProperty = true; + MappedProperty mcp = (MappedProperty) cp; + try { + Method getter = mcp.getMapGetter(); + //noinspection RedundantArrayCreation + value = getter.invoke(obj, new Object[] {key}); + } catch (Exception e) { + // catching the general exception is correct here, translate the exception + throw new FieldGetValueException("Mapped getter method failure getting mapped (" + +key+") value for name ("+cp.getFieldName()+") from: " + obj, cp.getFieldName(), obj, e); } - // try to get the mapped getter and use that first - if (cp instanceof MappedProperty) { - mappedProperty = true; - MappedProperty mcp = (MappedProperty) cp; - try { - Method getter = mcp.getMapGetter(); - //noinspection RedundantArrayCreation - value = getter.invoke(obj, new Object[] {key}); - } catch (Exception e) { - // catching the general exception is correct here, translate the exception - throw new FieldGetValueException("Mapped getter method failure getting mapped (" - +key+") value for name ("+cp.getFieldName()+") from: " + obj, cp.getFieldName(), obj, e); - } - } else { - Object o = findFieldValue(obj, cp); - if (! Map.class.isAssignableFrom(o.getClass())) { - throw new IllegalArgumentException("Field (" + name + ") does not appear to be a map (not instance of Map)"); - } - map = (Map) o; + } else { + Object o = findFieldValue(obj, cp); + if (! Map.class.isAssignableFrom(o.getClass())) { + throw new IllegalArgumentException("Field (" + name + ") does not appear to be a map (not instance of Map)"); } + map = (Map) o; } - // get the value from the map - if (!mappedProperty) { - if (map != null) { - try { - value = map.get(key); - } catch (Exception e) { - throw new IllegalArgumentException("Key ("+key+") is invalid ("+map.size()+") for the map: " + map, e); - } - } else { - throw new IllegalArgumentException("Mapped object is null, cannot retrieve key ("+key+") value from field ("+name+")"); + } + // get the value from the map + if (!mappedProperty) { + if (map != null) { + try { + value = map.get(key); + } catch (Exception e) { + throw new IllegalArgumentException("Key ("+key+") is invalid ("+map.size()+") for the map: " + map, e); } + } else { + throw new IllegalArgumentException("Mapped object is null, cannot retrieve key ("+key+") value from field ("+name+")"); } } return value; @@ -928,29 +883,24 @@ protected void setSimpleValue(Object obj, String name, Object value) { throw new IllegalArgumentException("field name cannot be null or blank"); } - // Handle DynaBean instances specially - if (fieldAdapterManager.isAdaptableObject(obj)) { - fieldAdapterManager.getFieldAdapter().setSimpleValue(obj, name, value); - } else { - // normal bean - ClassFields cf = analyzeObject(obj); + // normal bean + ClassFields cf = analyzeObject(obj); + try { + ClassProperty cp = cf.getClassProperty(name); + assignFieldValue(obj, cp, value); + } catch (FieldnameNotFoundException fnfe) { + // could not find this as a standard field so handle as internal lookup + ClassData cd = cf.getClassData(); + Field field = getFieldIfPossible(cd, name); + if (field == null) { + throw new FieldnameNotFoundException("Could not find field with name ("+name+") on object (" + obj + ") after extended look into non-visible fields", fnfe); + } try { - ClassProperty cp = cf.getClassProperty(name); - assignFieldValue(obj, cp, value); - } catch (FieldnameNotFoundException fnfe) { - // could not find this as a standard field so handle as internal lookup - ClassData cd = cf.getClassData(); - Field field = getFieldIfPossible(cd, name); - if (field == null) { - throw new FieldnameNotFoundException("Could not find field with name ("+name+") on object (" + obj + ") after extended look into non-visible fields", fnfe); - } - try { - value = getConversionUtils().convert(value, field.getType()); - field.set(obj, value); - } catch (Exception e) { - // catching the general exception is correct here, translate the exception - throw new FieldSetValueException("Field set failure setting value ("+value+") for field ("+name+") from non-visible field in object: " + obj, name, obj, e); - } + value = getConversionUtils().convert(value, field.getType()); + field.set(obj, value); + } catch (Exception e) { + // catching the general exception is correct here, translate the exception + throw new FieldSetValueException("Field set failure setting value ("+value+") for field ("+name+") from non-visible field in object: " + obj, name, obj, e); } } } @@ -988,111 +938,87 @@ protected void setIndexedValue(Object obj, String name, Object value) { } boolean indexedProperty = false; - // Handle DynaBean instances specially - if (fieldAdapterManager.isAdaptableObject(obj)) { - fieldAdapterManager.getFieldAdapter().setIndexedValue(obj, name, index, value); + boolean isArray = false; + Object indexedObject = null; + + if (ConstructorUtils.isClassArray(obj.getClass())) { + indexedObject = obj; + isArray = true; + } else if (ConstructorUtils.isClassList(obj.getClass())) { + indexedObject = obj; } else { - boolean isArray = false; - Object indexedObject = null; - if ( ConstructorUtils.isClassArray(obj.getClass()) ) { - indexedObject = obj; - isArray = true; - } else if ( ConstructorUtils.isClassList(obj.getClass()) ) { - indexedObject = obj; - } else { - // normal bean - ClassFields cf = analyzeObject(obj); - ClassProperty cp = cf.getClassProperty(name); - if (! cp.isIndexed()) { - throw new IllegalArgumentException("This field ("+name+") is not an indexed field"); + ClassFields cf = analyzeObject(obj); + ClassProperty cp = cf.getClassProperty(name); + if (!cp.isIndexed()) { + throw new IllegalArgumentException("This field (" + name + ") is not an indexed field"); + } + isArray = cp.isArray(); + if (cp instanceof IndexedProperty) { + indexedProperty = true; + IndexedProperty icp = (IndexedProperty) cp; + try { + Method setter = icp.getIndexSetter(); + setter.invoke(obj, index, value); + } catch (Exception e) { + throw new FieldSetValueException("Indexed setter method failure setting indexed (" + index + ") value for name (" + cp.getFieldName() + ") on: " + obj, cp.getFieldName(), obj, e); } - isArray = cp.isArray(); - // try to get the indexed setter and use that first - if (cp instanceof IndexedProperty) { - indexedProperty = true; - IndexedProperty icp = (IndexedProperty) cp; + } + if (!indexedProperty) { + indexedObject = findFieldValue(obj, cp); + if (indexedObject == null) { try { - Method setter = icp.getIndexSetter(); - //noinspection RedundantArrayCreation - setter.invoke(obj, new Object[] {index, value}); - } catch (Exception e) { - // catching the general exception is correct here, translate the exception - throw new FieldSetValueException("Indexed setter method failure setting indexed (" - +index+") value for name ("+cp.getFieldName()+") on: " + obj, cp.getFieldName(), obj, e); - } - } else { - // get the field value out and work with it directly - indexedObject = findFieldValue(obj, cp); - if (indexedObject == null) { - // handle nulls by creating if possible - try { - if (isArray) { - // create the array if it is null - Class type = value.getClass(); - indexedObject = ArrayUtils.create(type, index+1); - } else { // List - // create the list if it is null, back-fill it, and assign it back to the object - Class type = cp.getType(); - if (type.isInterface()) { - indexedObject = new ArrayList(index+1); - } else { - indexedObject = type.newInstance(); - } + if (isArray) { + Class type = value.getClass(); + indexedObject = ArrayUtils.create(type, index + 1); + } else { + Class type = cp.getType(); + if (type.isInterface()) { + indexedObject = new ArrayList<>(index + 1); + } else { + indexedObject = getConstructorUtils().constructClass(type); } - setSimpleValue(obj, name, indexedObject); - } catch (Exception e) { - throw new IllegalArgumentException("Indexed object is null, attempt to create list failed, cannot set value for index ("+index+") on field ("+name+")", e); } + setSimpleValue(obj, name, indexedObject); + } catch (Exception e) { + throw new IllegalArgumentException("Indexed object is null, attempt to create list failed, cannot set value for index (" + index + ") on field (" + name + ")", e); } } } - if (!indexedProperty) { - // set the indexed value - if (isArray) { - // this is an array - try { - // set the value on the array - int length = ArrayUtils.size((Object[])indexedObject); - if (index >= length) { - // automatically expand the array - indexedObject = ArrayUtils.resize((Object[])indexedObject, index+1); - setSimpleValue(obj, name, indexedObject); // need to put the array back into the object - } - // convert this value to the type for the array - Class componentType = ArrayUtils.type((Object[])indexedObject); - Object convert = ReflectUtils.getInstance().convert(value, componentType); - Array.set(indexedObject, index, convert); - } catch (Exception e) { - throw new IllegalArgumentException("Failed to set index ("+index+") for array of size ("+Array.getLength(indexedObject)+") to value: " + value, e); + } + + if (!indexedProperty) { + if (indexedObject == null) { + throw new IllegalArgumentException("Indexed object is null, cannot set value for index (" + index + ") on field (" + name + ")"); + } + if (isArray) { + try { + int length = ArrayUtils.size((Object[]) indexedObject); + if (index >= length) { + indexedObject = ArrayUtils.resize((Object[]) indexedObject, index + 1); + setSimpleValue(obj, name, indexedObject); } - } else { - // this better be a list - if (indexedObject == null - || ! List.class.isAssignableFrom(indexedObject.getClass())) { - throw new IllegalArgumentException("Field (" + name + ") does not appear to be indexed (not an array or a list): " - + (indexedObject == null ? "NULL" : indexedObject.getClass()) ); + Class componentType = ArrayUtils.type((Object[]) indexedObject); + Object convert = ReflectUtils.getInstance().convert(value, componentType); + Array.set(indexedObject, index, convert); + } catch (Exception e) { + throw new IllegalArgumentException("Failed to set index (" + index + ") for array of size (" + Array.getLength(indexedObject) + ") to value: " + value, e); + } + } else { + if (!List.class.isAssignableFrom(indexedObject.getClass())) { + throw new IllegalArgumentException("Field (" + name + ") does not appear to be indexed (not an array or a list): " + indexedObject.getClass()); + } + List list = (List) indexedObject; + try { + if (index < 0) { + list.add(value); } else { - // this is a list - List l = (List) indexedObject; - try { - // set value on list - if (index < 0) { - l.add(value); - } else { - if (index >= l.size()) { - // automatically expand the list - int start = l.size(); - for (int i = start; i < (index+1); i++) { - l.add(i, null); - } - } - l.set(index, value); - } - } catch (Exception e) { - // catching the general exception is correct here, translate the exception - throw new IllegalArgumentException("Failed to set index ("+index+") for list of size ("+l.size()+") to value: " + value, e); + while (index >= list.size()) { + list.add(null); } + list.set(index, value); } + } catch (Exception e) { + throw new IllegalArgumentException("Failed to set index (" + index + ") for list of size (" + list.size() + ") to value: " + value, e); } } } @@ -1131,14 +1057,10 @@ protected void setMappedValue(Object obj, String name, Object value) { } boolean mappedProperty = false; - // Handle DynaBean instances specially - if (fieldAdapterManager.isAdaptableObject(obj)) { - fieldAdapterManager.getFieldAdapter().setMappedValue(obj, name, key, value); + Map map = null; + if (Map.class.isAssignableFrom(obj.getClass())) { + map = (Map) obj; } else { - Map map = null; - if (Map.class.isAssignableFrom(obj.getClass())) { - map = (Map) obj; - } else { // normal bean ClassFields cf = analyzeObject(obj); ClassProperty cp = cf.getClassProperty(name); @@ -1165,9 +1087,9 @@ protected void setMappedValue(Object obj, String name, Object value) { try { Class type = cp.getType(); if (type.isInterface()) { - map = new ArrayOrderedMap(5); + map = new LinkedHashMap(5); } else { - map = (Map) type.newInstance(); + map = (Map) getConstructorUtils().constructClass(type); } setSimpleValue(obj, name, map); } catch (Exception e) { @@ -1181,18 +1103,17 @@ protected void setMappedValue(Object obj, String name, Object value) { map = (Map) o; } } + } + if (!mappedProperty) { + // set value in map + if (map == null) { + throw new IllegalArgumentException("Mapped object is null, cannot set value for key ("+key+") on field ("+name+")"); } - if (!mappedProperty) { - // set value in map - if (map == null) { - throw new IllegalArgumentException("Mapped object is null, cannot set value for key ("+key+") on field ("+name+")"); - } - // set value on map - try { - map.put(key, value); - } catch (Exception e) { - throw new IllegalArgumentException("Value ("+value+") cannot be put for key ("+key+") for the map: " + map, e); - } + // set value on map + try { + map.put(key, value); + } catch (Exception e) { + throw new IllegalArgumentException("Value ("+value+") cannot be put for key ("+key+") for the map: " + map, e); } } } diff --git a/src/main/java/org/azeckoski/reflectutils/Lifecycle.java b/src/main/java/org/azeckoski/reflectutils/Lifecycle.java deleted file mode 100644 index 0e55260..0000000 --- a/src/main/java/org/azeckoski/reflectutils/Lifecycle.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.azeckoski.reflectutils; - -/** - * Interface for objects that wish to participate in lifecycle events. - */ -public interface Lifecycle -{ - void shutdown(); -} diff --git a/src/main/java/org/azeckoski/reflectutils/LifecycleManager.java b/src/main/java/org/azeckoski/reflectutils/LifecycleManager.java deleted file mode 100644 index de5fac8..0000000 --- a/src/main/java/org/azeckoski/reflectutils/LifecycleManager.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.azeckoski.reflectutils; - -import java.util.List; -import java.util.ArrayList; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -/** - * Simple LifecycleManager for the reflection utilities. This is provided to allow - * cleanup under certain conditions (ie. the background thread that is run by the ReferenceMap) - * - * Initially, the LifecycleManager is not active, and the reflection utilities will attempt - * to clean themselves up. To use an explicit lifecycle, first call setActive() to start the manager - * (before anything uses the reflection utilities - ie. in the context initiliser of a web application!), - * and then call 'shutdown()' during termination. - */ -public class LifecycleManager -{ - private static boolean isActive = false; - private static List managedObjects = new ArrayList(); - private static Lock moLock = new ReentrantLock(); - - /** - * Test to see if the manager is active - * @return true if active - */ - public static boolean isActive() { - return isActive; - } - - /** - * Activate the lifecycle manager - * @param active - */ - public static void setActive(boolean active) { - isActive = active; - } - - /** - * Register an object to receive lifecycle events - * @param object - */ - public static void register(Lifecycle object) { - if (isActive) { - moLock.lock(); - try { - if (managedObjects == null) { - throw new RuntimeException("Unable to register - manager already shut down"); - } - - managedObjects.add(object); - } finally { - moLock.unlock(); - } - } - } - - /** - * Request shutdown for any objects registered with the lifecycle manager - */ - public synchronized static void shutdown() { - moLock.lock(); - try { - if (managedObjects != null) { - while (managedObjects.size() > 0) { - Lifecycle obj = managedObjects.remove(managedObjects.size() - 1); - obj.shutdown(); - } - - managedObjects = null; - } - } finally { - moLock.unlock(); - } - } -} diff --git a/src/main/java/org/azeckoski/reflectutils/ReflectUtils.java b/src/main/java/org/azeckoski/reflectutils/ReflectUtils.java index 0366823..3040c19 100644 --- a/src/main/java/org/azeckoski/reflectutils/ReflectUtils.java +++ b/src/main/java/org/azeckoski/reflectutils/ReflectUtils.java @@ -695,8 +695,6 @@ public String toString() { // STATIC access protected static SoftReference instanceStorage; - // protected static Map utilByClassLoader = - // new ReferenceMap(ReferenceType.WEAK, ReferenceType.STRONG); /** * Get a singleton instance of this class to work with (stored statically)
* WARNING: do not hold onto this object or cache it yourself, call this method again if you need it again diff --git a/src/main/java/org/azeckoski/reflectutils/annotations/package.html b/src/main/java/org/azeckoski/reflectutils/annotations/package.html deleted file mode 100644 index aee9d98..0000000 --- a/src/main/java/org/azeckoski/reflectutils/annotations/package.html +++ /dev/null @@ -1,5 +0,0 @@ - - -Marker annotations which are used to control the way the reflect utils work with classes - - \ No newline at end of file diff --git a/src/main/java/org/azeckoski/reflectutils/beanutils/DefaultFieldAdapter.java b/src/main/java/org/azeckoski/reflectutils/beanutils/DefaultFieldAdapter.java deleted file mode 100644 index ea04f36..0000000 --- a/src/main/java/org/azeckoski/reflectutils/beanutils/DefaultFieldAdapter.java +++ /dev/null @@ -1,107 +0,0 @@ -/** - * $Id: DefaultFieldAdapter.java 2 2008-10-01 10:04:26Z azeckoski $ - * $URL: http://reflectutils.googlecode.com/svn/trunk/src/main/java/org/azeckoski/reflectutils/beanutils/DefaultFieldAdapter.java $ - * DefaultFieldAdapter.java - genericdao - Sep 20, 2008 10:38:59 AM - azeckoski - ************************************************************************** - * Copyright (c) 2008 Aaron Zeckoski - * Licensed under the Apache License, Version 2.0 - * - * A copy of the Apache License has been included in this - * distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt - * - * Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk) - */ - -package org.azeckoski.reflectutils.beanutils; - -import java.util.List; -import java.util.Map; - -import org.azeckoski.reflectutils.ClassFields.FieldsFilter; - - -/** - * Does nothing but implement with the defaults, used when the normal adapter is not available - * - * @author Aaron Zeckoski (azeckoski @ gmail.com) - */ -public class DefaultFieldAdapter implements FieldAdapter { - - /* (non-Javadoc) - * @see org.azeckoski.reflectutils.beanutils.FieldAdapter#isAdaptableObject(java.lang.Object) - */ - public boolean isAdaptableObject(Object obj) { - return false; - } - - /* (non-Javadoc) - * @see org.azeckoski.reflectutils.beanutils.FieldAdapter#isAdaptableClass(java.lang.Class) - */ - public boolean isAdaptableClass(Class beanClass) { - return false; - } - - // NOTE: nothing below here should ever get called - - /* (non-Javadoc) - * @see org.azeckoski.reflectutils.beanutils.FieldAdapter#getFieldType(java.lang.Object, java.lang.String) - */ - public Class getFieldType(Object obj, String name) { - return null; - } - - /* (non-Javadoc) - * @see org.azeckoski.reflectutils.beanutils.FieldAdapter#getFieldValues(java.lang.Object, org.azeckoski.reflectutils.ClassFields.FieldsFilter) - */ - public Map getFieldValues(Object obj, FieldsFilter filter) { - return null; - } - - /* (non-Javadoc) - * @see org.azeckoski.reflectutils.beanutils.FieldAdapter#getIndexedValue(java.lang.Object, java.lang.String, int) - */ - public Object getIndexedValue(Object obj, String name, int index) { - return null; - } - - /* (non-Javadoc) - * @see org.azeckoski.reflectutils.beanutils.FieldAdapter#getMappedValue(java.lang.Object, java.lang.String, java.lang.String) - */ - public Object getMappedValue(Object obj, String name, String key) { - return null; - } - - /* (non-Javadoc) - * @see org.azeckoski.reflectutils.beanutils.FieldAdapter#getSimpleValue(java.lang.Object, java.lang.String) - */ - public Object getSimpleValue(Object obj, String name) { - return null; - } - - /* (non-Javadoc) - * @see org.azeckoski.reflectutils.beanutils.FieldAdapter#setIndexedValue(java.lang.Object, java.lang.String, int, java.lang.Object) - */ - public void setIndexedValue(Object obj, String name, int index, Object value) { - } - - /* (non-Javadoc) - * @see org.azeckoski.reflectutils.beanutils.FieldAdapter#setMappedValue(java.lang.Object, java.lang.String, java.lang.String, java.lang.Object) - */ - public void setMappedValue(Object obj, String name, String key, Object value) { - } - - /* (non-Javadoc) - * @see org.azeckoski.reflectutils.beanutils.FieldAdapter#setSimpleValue(java.lang.Object, java.lang.String, java.lang.Object) - */ - public void setSimpleValue(Object obj, String name, Object value) { - } - - public List getPropertyNames(Object bean) { - return null; - } - - public Object newInstance(Object bean) { - return null; - } - -} diff --git a/src/main/java/org/azeckoski/reflectutils/beanutils/DynaBeanAdapter.java b/src/main/java/org/azeckoski/reflectutils/beanutils/DynaBeanAdapter.java deleted file mode 100644 index aabb7fe..0000000 --- a/src/main/java/org/azeckoski/reflectutils/beanutils/DynaBeanAdapter.java +++ /dev/null @@ -1,176 +0,0 @@ -/** - * $Id: DynaBeanAdapter.java 2 2008-10-01 10:04:26Z azeckoski $ - * $URL: http://reflectutils.googlecode.com/svn/trunk/src/main/java/org/azeckoski/reflectutils/beanutils/DynaBeanAdapter.java $ - * DynaBeanAdapter.java - genericdao - Sep 20, 2008 10:08:01 AM - azeckoski - ************************************************************************** - * Copyright (c) 2008 Aaron Zeckoski - * Licensed under the Apache License, Version 2.0 - * - * A copy of the Apache License has been included in this - * distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt - * - * Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk) - */ - -package org.azeckoski.reflectutils.beanutils; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.azeckoski.reflectutils.ClassFields.FieldsFilter; -import org.azeckoski.reflectutils.exceptions.FieldnameNotFoundException; - -import org.apache.commons.beanutils.DynaBean; -import org.apache.commons.beanutils.DynaClass; -import org.apache.commons.beanutils.DynaProperty; - - -/** - * This allows dynabeans to work with the field utils, - * should only be loaded by reflection if the DynaBean class can be found - * - * @author Aaron Zeckoski (azeckoski @ gmail.com) - */ -public class DynaBeanAdapter implements FieldAdapter { - - public boolean isAdaptableObject(Object obj) { - boolean adaptable = false; - if (obj instanceof DynaBean) { - adaptable = true; - } - return adaptable; - } - - public boolean isAdaptableClass(Class beanClass) { - boolean adaptable = false; - if (DynaBean.class.isAssignableFrom(beanClass)) { - adaptable = true; - } - return adaptable; - } - - /* (non-Javadoc) - * @see org.azeckoski.reflectutils.beanutils.FieldAdapter#getFieldType(java.lang.Object, java.lang.String) - */ - public Class getFieldType(Object obj, String name) { - DynaClass dynaClass = ((DynaBean) obj).getDynaClass(); - DynaProperty dynaProperty = dynaClass.getDynaProperty(name); - if (dynaProperty == null) { - throw new FieldnameNotFoundException("DynaBean: Could not find this fieldName ("+name+") on the target object: " + obj, name, null); - } - return dynaProperty.getType(); - } - - /* (non-Javadoc) - * @see org.azeckoski.reflectutils.beanutils.FieldAdapter#getFieldValues(java.lang.Object, org.azeckoski.reflectutils.ClassFields.FieldsFilter) - */ - public Map getFieldValues(Object obj, FieldsFilter filter) { - Map values = new HashMap(); - DynaProperty[] descriptors = - ((DynaBean) obj).getDynaClass().getDynaProperties(); - for (int i = 0; i < descriptors.length; i++) { - String name = descriptors[i].getName(); - // cannot filter the values for dynabeans -AZ - Object o = getSimpleValue(obj, name); - values.put(name, o); - } - return values; - } - - /* (non-Javadoc) - * @see org.azeckoski.reflectutils.beanutils.FieldAdapter#getSimpleValue(java.lang.Object, java.lang.String) - */ - public Object getSimpleValue(Object obj, String name) { - DynaProperty descriptor = - ((DynaBean) obj).getDynaClass().getDynaProperty(name); - if (descriptor == null) { - throw new FieldnameNotFoundException(name); - } - Object value = (((DynaBean) obj).get(name)); - return value; - } - - /* (non-Javadoc) - * @see org.azeckoski.reflectutils.beanutils.FieldAdapter#getIndexedValue(java.lang.Object, java.lang.String, int) - */ - public Object getIndexedValue(Object obj, String name, int index) { - DynaProperty descriptor = - ((DynaBean) obj).getDynaClass().getDynaProperty(name); - if (descriptor == null) { - throw new FieldnameNotFoundException(name); - } - Object value = ((DynaBean) obj).get(name, index); - return value; - } - - /* (non-Javadoc) - * @see org.azeckoski.reflectutils.beanutils.FieldAdapter#getMappedValue(java.lang.Object, java.lang.String, java.lang.String) - */ - public Object getMappedValue(Object obj, String name, String key) { - DynaProperty descriptor = - ((DynaBean) obj).getDynaClass().getDynaProperty(name); - if (descriptor == null) { - throw new FieldnameNotFoundException(name); - } - Object value = ((DynaBean) obj).get(name, key); - return value; - } - - /* (non-Javadoc) - * @see org.azeckoski.reflectutils.beanutils.FieldAdapter#setIndexedValue(java.lang.Object, java.lang.String, int, java.lang.Object) - */ - public void setIndexedValue(Object obj, String name, int index, Object value) { - DynaProperty descriptor = - ((DynaBean) obj).getDynaClass().getDynaProperty(name); - if (descriptor == null) { - throw new FieldnameNotFoundException(name); - } - ((DynaBean) obj).set(name, index, value); - } - - /* (non-Javadoc) - * @see org.azeckoski.reflectutils.beanutils.FieldAdapter#setMappedValue(java.lang.Object, java.lang.String, java.lang.String, java.lang.Object) - */ - public void setMappedValue(Object obj, String name, String key, Object value) { - DynaProperty descriptor = - ((DynaBean) obj).getDynaClass().getDynaProperty(name); - if (descriptor == null) { - throw new FieldnameNotFoundException(name); - } - ((DynaBean) obj).set(name, key, value); - } - - /* (non-Javadoc) - * @see org.azeckoski.reflectutils.beanutils.FieldAdapter#setSimpleValue(java.lang.Object, java.lang.String, java.lang.Object) - */ - public void setSimpleValue(Object obj, String name, Object value) { - DynaProperty descriptor = - ((DynaBean) obj).getDynaClass().getDynaProperty(name); - if (descriptor == null) { - throw new FieldnameNotFoundException(name); - } - ((DynaBean) obj).set(name, value); - } - - public Object newInstance(Object bean) { - try { - return ((DynaBean) bean).getDynaClass().newInstance(); - } catch (Exception e) { - throw new RuntimeException("Could not instantiate DynaBean: " + bean, e); - } // make new dynabean - } - - public List getPropertyNames(Object bean) { - List names = new ArrayList(); - DynaProperty origDescriptors[] = - ((DynaBean) bean).getDynaClass().getDynaProperties(); - for (DynaProperty dynaProperty : origDescriptors) { - String name = dynaProperty.getName(); - names.add(name); - } - return names; - } - -} diff --git a/src/main/java/org/azeckoski/reflectutils/beanutils/FieldAdapter.java b/src/main/java/org/azeckoski/reflectutils/beanutils/FieldAdapter.java deleted file mode 100644 index 6584e1d..0000000 --- a/src/main/java/org/azeckoski/reflectutils/beanutils/FieldAdapter.java +++ /dev/null @@ -1,143 +0,0 @@ -/** - * $Id: FieldAdapter.java 2 2008-10-01 10:04:26Z azeckoski $ - * $URL: http://reflectutils.googlecode.com/svn/trunk/src/main/java/org/azeckoski/reflectutils/beanutils/FieldAdapter.java $ - * FieldAdapter.java - genericdao - Sep 20, 2008 8:15:36 AM - azeckoski - ************************************************************************** - * Copyright (c) 2008 Aaron Zeckoski - * Licensed under the Apache License, Version 2.0 - * - * A copy of the Apache License has been included in this - * distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt - * - * Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk) - */ - -package org.azeckoski.reflectutils.beanutils; - -import java.util.List; -import java.util.Map; - -import org.azeckoski.reflectutils.ClassFields.FieldsFilter; -import org.azeckoski.reflectutils.exceptions.FieldGetValueException; -import org.azeckoski.reflectutils.exceptions.FieldSetValueException; -import org.azeckoski.reflectutils.exceptions.FieldnameNotFoundException; - - -/** - * Interface that allows us to adapt to special class types like the apache dynabeans without - * requiring them to be a dependency unless they happen to be in the ClassLoader - * - * @author Aaron Zeckoski (azeckoski @ gmail.com) - */ -public interface FieldAdapter { - - /** - * @param obj any object - * @return true if this object is part of the set this adapter is made to handle, false otherwise - */ - public boolean isAdaptableObject(Object obj); - - /** - * @param beanClass any class - * @return true if this class is adaptable, false otherwise - */ - public boolean isAdaptableClass(Class beanClass); - - /** - * @return a new instance of the adapted class type based on a sample - */ - public Object newInstance(Object bean); - - /** - * @param bean any bean of the adaptable class type - * @return the list of property names for that bean - */ - public List getPropertyNames(Object bean); - - /** - * Finds the type for a field based on the containing object and the field name - * @param obj any object - * @param name the name of a field in this object (can be nested, indexed, mapped, etc.) - * @return the type of the field (will be {@link Object} if the type is indeterminate) - * @throws FieldnameNotFoundException if the name is invalid for this obj - * @throws IllegalArgumentException if the params are null - */ - public Class getFieldType(Object obj, String name); - - /** - * Get the values of all fields on an object but optionally filter the fields used - * @param obj any object - * @param filter (optional) indicates the fields to return the values for, can be null for defaults
- * WARNING: getting the field values from settable only fields works as expected (i.e. you will an empty map) - * @return a map of field name -> value - * @throws IllegalArgumentException if the obj is null - */ - public Map getFieldValues(Object obj, FieldsFilter filter); - - /** - * For getting a value out of a bean based on a field name, - * mostly for internal usage, use getFieldValue - *
- * WARNING: Cannot handle a nested/mapped/indexed name - * - * @throws FieldnameNotFoundException if this field name is invalid for this object - * @throws IllegalArgumentException if there is failure - */ - public Object getSimpleValue(Object obj, String name); - - /** - * For getting an indexed value out of an object based on field name, - * mostly for internal usage, use getFieldValue - *
- * WARNING: Cannot handle a nested/mapped/indexed name - * - * @throws FieldnameNotFoundException if this field name is invalid for this object - * @throws IllegalArgumentException if there is a failure - * @throws FieldGetValueException if there is an internal failure getting the field - */ - public Object getIndexedValue(Object obj, String name, int index); - - /** - * For getting a mapped value out of an object based on field name, - * mostly for internal usage, use getFieldValue - *
- * WARNING: Cannot handle a nested/mapped/indexed name - * @throws FieldnameNotFoundException if this field name is invalid for this object - * @throws IllegalArgumentException if there are invalid arguments - * @throws FieldGetValueException if there is an internal failure getting the field - */ - public Object getMappedValue(Object obj, String name, String key); - - /** - * Set a value on a field of an object, the types must match and the name must be identical - *
- * WARNING: Cannot handle a nested/mapped/indexed name - * @throws FieldnameNotFoundException if this field name is invalid for this object - * @throws IllegalArgumentException if there is failure - * @throws FieldSetValueException if there is an internal failure setting the field - */ - public void setSimpleValue(Object obj, String name, Object value); - - /** - * For getting an indexed value out of an object based on field name, - * mostly for internal usage, use getFieldValue - *
- * WARNING: Cannot handle a nested/mapped/indexed name - * @throws FieldnameNotFoundException if this field name is invalid for this object - * @throws IllegalArgumentException if there is failure - * @throws FieldSetValueException if there is an internal failure setting the field - */ - public void setIndexedValue(Object obj, String name, int index, Object value); - - /** - * For getting a mapped value out of an object based on field name, - * mostly for internal usage, use getFieldValue - *
- * WARNING: Cannot handle a nested/mapped/indexed name - * @throws FieldnameNotFoundException if this field name is invalid for this object - * @throws IllegalArgumentException if there is failure - * @throws FieldSetValueException if there is an internal failure setting the field - */ - public void setMappedValue(Object obj, String name, String key, Object value); - -} diff --git a/src/main/java/org/azeckoski/reflectutils/beanutils/FieldAdapterManager.java b/src/main/java/org/azeckoski/reflectutils/beanutils/FieldAdapterManager.java deleted file mode 100644 index f29736f..0000000 --- a/src/main/java/org/azeckoski/reflectutils/beanutils/FieldAdapterManager.java +++ /dev/null @@ -1,93 +0,0 @@ -/** - * $Id: FieldAdapterManager.java 54 2009-05-18 15:29:27Z azeckoski $ - * $URL: http://reflectutils.googlecode.com/svn/trunk/src/main/java/org/azeckoski/reflectutils/beanutils/FieldAdapterManager.java $ - * FieldAdapterManager.java - reflectutils - Oct 2, 2008 10:31:44 PM - azeckoski - ************************************************************************** - * Copyright (c) 2008 Aaron Zeckoski - * Licensed under the Apache License, Version 2.0 - * - * A copy of the Apache License has been included in this - * distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt - * - * Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk) - */ - -package org.azeckoski.reflectutils.beanutils; - -import org.azeckoski.reflectutils.ClassLoaderUtils; - - -/** - * This manager ensures that the field adapter keeps working even if the class it is adapting goes away - * - * @author Aaron Zeckoski (azeckoski @ gmail.com) - */ -public class FieldAdapterManager { - - public static final String DYNABEAN_CLASSNAME = "org.apache.commons.beanutils.DynaBean"; - public static final String DYNABEAN_ADAPTER = "DynaBeanAdapter"; - - protected FieldAdapter fieldAdapter; - - public FieldAdapterManager() { - /* - * loads up the field adapter if the right classes exist, - * this allows us to support DynaBeans even though they may not be available - */ - Class dynaBean = ClassLoaderUtils.getClassFromString(DYNABEAN_CLASSNAME); - if (dynaBean != null) { - // assumes the adapter impl is in the same path as the interface - String path = FieldAdapter.class.getName(); - path = path.replace(FieldAdapter.class.getSimpleName(), DYNABEAN_ADAPTER); - Class adapterClass = ClassLoaderUtils.getClassFromString(path); - if (adapterClass == null) { - System.err.println("WARN: Could not find adapter class: " + path + ", will continue without the dynabean adapter"); - //throw new IllegalStateException("Could not find adapter class: " + DYNABEAN_ADAPTER); - } else { - // found the adapter class - try { - fieldAdapter = (FieldAdapter) adapterClass.newInstance(); - } catch (Exception e) { - System.err.println("WARN: Failed to instantiate field adapter ("+adapterClass+"), will continue without the dynabean adapter: "+e); - //throw new RuntimeException("Failed to instantiate field adapter ("+adapterClass+"): "+e, e); - } - } - } else { - // no dynabean so use default - fieldAdapter = new DefaultFieldAdapter(); - } - if (fieldAdapter == null) { - // failure with dynabean so use default - fieldAdapter = new DefaultFieldAdapter(); - } - } - - public FieldAdapter getFieldAdapter() { - return fieldAdapter; - } - - public boolean isAdaptableObject(Object obj) { - boolean adaptable = false; - try { - adaptable = fieldAdapter.isAdaptableObject(obj); - } catch (NoClassDefFoundError e) { - // invalid field adapter, back to the default one - fieldAdapter = new DefaultFieldAdapter(); - adaptable = false; - } - return adaptable; - } - - public boolean isAdaptableClass(Class beanClass) { - boolean adaptable = false; - try { - adaptable = fieldAdapter.isAdaptableClass(beanClass); - } catch (NoClassDefFoundError e) { - // invalid field adapter, back to the default one - fieldAdapter = new DefaultFieldAdapter(); - adaptable = false; - } - return adaptable; - } - -} diff --git a/src/main/java/org/azeckoski/reflectutils/beanutils/package.html b/src/main/java/org/azeckoski/reflectutils/beanutils/package.html deleted file mode 100644 index c515cc7..0000000 --- a/src/main/java/org/azeckoski/reflectutils/beanutils/package.html +++ /dev/null @@ -1,5 +0,0 @@ - - -The beanutils compatibility classes that add support for dynabeans and dynaclasses - - \ No newline at end of file diff --git a/src/main/java/org/azeckoski/reflectutils/converters/CollectionConverter.java b/src/main/java/org/azeckoski/reflectutils/converters/CollectionConverter.java index 020181d..17feaf7 100644 --- a/src/main/java/org/azeckoski/reflectutils/converters/CollectionConverter.java +++ b/src/main/java/org/azeckoski/reflectutils/converters/CollectionConverter.java @@ -15,9 +15,9 @@ package org.azeckoski.reflectutils.converters; import java.lang.reflect.Array; +import java.util.ArrayList; import java.util.Collection; import java.util.Map; -import java.util.Vector; import org.azeckoski.reflectutils.ConstructorUtils; import org.azeckoski.reflectutils.converters.api.InterfaceConverter; @@ -33,7 +33,7 @@ public class CollectionConverter implements InterfaceConverter { public Collection convert(Object value) { - return convertInterface(value, Vector.class); + return convertInterface(value, ArrayList.class); } protected ConstructorUtils getConstructorUtils() { @@ -45,7 +45,7 @@ public Collection convertInterface(Object value, Class imp Class fromType = value.getClass(); Object toConvert = value; if (implementationType == null) { - implementationType = Vector.class; + implementationType = ArrayList.class; } else if (implementationType.isInterface()) { implementationType = ConstructorUtils.getClassFromInterface(implementationType); } diff --git a/src/main/java/org/azeckoski/reflectutils/converters/DateConverter.java b/src/main/java/org/azeckoski/reflectutils/converters/DateConverter.java index e421d41..52fe58d 100644 --- a/src/main/java/org/azeckoski/reflectutils/converters/DateConverter.java +++ b/src/main/java/org/azeckoski/reflectutils/converters/DateConverter.java @@ -130,7 +130,7 @@ public static T convertToType(Class targetType, Object value, DateFormat[ } else { // try to get the long value out of the string try { - long num = new Long(stringValue); + long num = Long.parseLong(stringValue); if (num > 30000000l) { // must be a UTC time code, also, we only lost a week since 1970 so whatever return (T) toDate(targetType, num); @@ -157,7 +157,7 @@ public static T convertToType(Class targetType, Object value, DateFormat[ // Parse the Date/Time Calendar calendar = parse(stringValue, dateFormats); if (calendar != null) { - long time = ((Calendar)value).getTimeInMillis(); + long time = calendar.getTimeInMillis(); return (T) toDate(targetType, time); } diff --git a/src/main/java/org/azeckoski/reflectutils/converters/MapConverter.java b/src/main/java/org/azeckoski/reflectutils/converters/MapConverter.java index 67204b6..d0401ed 100644 --- a/src/main/java/org/azeckoski/reflectutils/converters/MapConverter.java +++ b/src/main/java/org/azeckoski/reflectutils/converters/MapConverter.java @@ -16,13 +16,13 @@ import java.lang.reflect.Array; import java.util.Collection; +import java.util.LinkedHashMap; import java.util.Map; import org.azeckoski.reflectutils.ConstructorUtils; import org.azeckoski.reflectutils.FieldUtils; import org.azeckoski.reflectutils.ClassFields.FieldsFilter; import org.azeckoski.reflectutils.converters.api.InterfaceConverter; -import org.azeckoski.reflectutils.map.ArrayOrderedMap; /** @@ -35,7 +35,7 @@ public class MapConverter implements InterfaceConverter { public Map convert(Object value) { - return convertInterface(value, ArrayOrderedMap.class); + return convertInterface(value, LinkedHashMap.class); } protected ConstructorUtils getConstructorUtils() { @@ -51,7 +51,7 @@ public Map convertInterface(Object value, Class implementationTyp Class fromType = value.getClass(); Object toConvert = value; if (implementationType == null || implementationType.isInterface()) { - implementationType = ArrayOrderedMap.class; + implementationType = LinkedHashMap.class; } convert = (Map) getConstructorUtils().constructClass(implementationType); if ( ConstructorUtils.isClassArray(fromType) ) { diff --git a/src/main/java/org/azeckoski/reflectutils/converters/NumberConverter.java b/src/main/java/org/azeckoski/reflectutils/converters/NumberConverter.java index 6b931d8..7894a24 100644 --- a/src/main/java/org/azeckoski/reflectutils/converters/NumberConverter.java +++ b/src/main/java/org/azeckoski/reflectutils/converters/NumberConverter.java @@ -142,7 +142,7 @@ private static Number toNumber(Class sourceType, Class targetType, Number throw new UnsupportedOperationException("source (" + sourceType + ") value (" + value + ") is too small for target (" + targetType + ")"); } - return new Byte(value.byteValue()); + return Byte.valueOf(value.byteValue()); } // Short @@ -156,7 +156,7 @@ private static Number toNumber(Class sourceType, Class targetType, Number throw new UnsupportedOperationException("source (" + sourceType + ") value (" + value + ") is too small for target (" + targetType + ")"); } - return new Short(value.shortValue()); + return Short.valueOf(value.shortValue()); } // Integer @@ -170,12 +170,12 @@ private static Number toNumber(Class sourceType, Class targetType, Number throw new UnsupportedOperationException("source (" + sourceType + ") value (" + value + ") is too small for target (" + targetType + ")"); } - return new Integer(value.intValue()); + return Integer.valueOf(value.intValue()); } // Long if (targetType.equals(Long.class)) { - return new Long(value.longValue()); + return Long.valueOf(value.longValue()); } // Float @@ -184,12 +184,12 @@ private static Number toNumber(Class sourceType, Class targetType, Number throw new UnsupportedOperationException("source (" + sourceType + ") value (" + value + ") is too large for target (" + targetType + ")"); } - return new Float(value.floatValue()); + return Float.valueOf(value.floatValue()); } // Double if (targetType.equals(Double.class)) { - return new Double(value.doubleValue()); + return Double.valueOf(value.doubleValue()); } // BigDecimal diff --git a/src/main/java/org/azeckoski/reflectutils/converters/package.html b/src/main/java/org/azeckoski/reflectutils/converters/package.html deleted file mode 100644 index ccc975a..0000000 --- a/src/main/java/org/azeckoski/reflectutils/converters/package.html +++ /dev/null @@ -1,5 +0,0 @@ - - -The converters which convert various java objects into other java objects (e.g. string => int, array => string, etc.) - - \ No newline at end of file diff --git a/src/main/java/org/azeckoski/reflectutils/map/ArrayOrderedMap.java b/src/main/java/org/azeckoski/reflectutils/map/ArrayOrderedMap.java deleted file mode 100644 index ee19eba..0000000 --- a/src/main/java/org/azeckoski/reflectutils/map/ArrayOrderedMap.java +++ /dev/null @@ -1,386 +0,0 @@ -/** - * $Id: ArrayOrderedMap.java 128 2014-03-18 22:27:33Z azeckoski $ - * $URL: http://reflectutils.googlecode.com/svn/trunk/src/main/java/org/azeckoski/reflectutils/map/ArrayOrderedMap.java $ - * ArrayOrderedMap.java - genericdao - May 5, 2008 2:16:35 PM - azeckoski - ************************************************************************** - * Copyright (c) 2008 Aaron Zeckoski - * Licensed under the Apache License, Version 2 - * - * A copy of the Apache License, Version 2 has been included in this - * distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt - * - * Aaron Zeckoski (azeckoski@gmail.com) (aaronz@vt.edu) (aaron@caret.cam.ac.uk) - */ - -package org.azeckoski.reflectutils.map; - -import java.util.AbstractCollection; -import java.util.AbstractSet; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.NoSuchElementException; -import java.util.Set; - -/** - * A map which keeps track of the order the entries are added - * and allows retrieval of entries in the order they were entered as well, - * this is NOT safe for multi-threaded access, - * this is backed by a {@link HashMap} and {@link ArrayList} - * - * @author Aaron Zeckoski (azeckoski @ gmail.com) - */ -public class ArrayOrderedMap extends HashMap implements OrderedMap { - public static final long serialVersionUID = 1l; - - private ArrayList list; - - public ArrayOrderedMap() { - this(10); - } - - public ArrayOrderedMap(int initialCapacity) { - super(initialCapacity); - list = new ArrayList(initialCapacity); - } - - public ArrayOrderedMap(Map map) { - this(map.size()); - for (Entry entry : map.entrySet()) { - this.put(entry.getKey(), entry.getValue()); - } - } - - - private String name = "entity"; - public String getName() { - return name; - } - /** - * @param name the name to use when encoding this map of entities - */ - public void setName(String name) { - this.name = name; - } - - /** - * @return a list of all the keys in this map in the order they were entered - */ - public List getKeys() { - return new ArrayList(list); - } - - /* (non-Javadoc) - * @see org.azeckoski.reflectutils.map.OrderedMap#getValues() - */ - public List getValues() { - return new ArrayList( values() ); - } - - /** - * @return a list of all the entries in this map in the order they were created - */ - public List> getEntries() { - ArrayList> entries = new ArrayList>(); - for (K key : list) { - Entry entry = new SimpleEntry(key, this.get(key)); - entries.add(entry); - } - return entries; - } - - /** - * Get an entry based on the position it is in the map (based on the order entries were created) - * @param position the position in the map (must be less that the size) - * @return the entry at that position - * @throws IllegalArgumentException if the position is greater than the map size - */ - public Entry getEntry(int position) { - if (position >= list.size()) { - throw new IllegalArgumentException("Value is too large for the map size: " + list.size()); - } - K key = list.get(position); - Entry entry = new SimpleEntry(key, this.get(key)); - return entry; - } - - @Override - public V put(K key, V value) { - V v = super.put(key, value); - if (v != null) { - // displaced - list.remove(key); - } - list.add(key); - return v; - } - - @Override - public void putAll(Map m) { - for (Map.Entry entry : m.entrySet()) { - put(entry.getKey(), entry.getValue()); - } - } - - @Override - public V remove(Object key) { - V v = super.remove(key); - if (v != null) { - list.remove(key); - } - return v; - } - - @Override - public void clear() { - super.clear(); - list.clear(); - } - - public Enumeration keys() { - return new KeyIterator(); - } - - public Enumeration elements() { - return new ValueIterator(); - } - - transient Set keySet; - transient Set> entrySet; - transient Collection values; - - @Override - public Set keySet() { - Set ks = keySet; - return (ks != null) ? ks : (keySet = new KeySet()); - } - - @Override - public Collection values() { - Collection vs = values; - return (vs != null) ? vs : (values = new Values()); - } - - @Override - @SuppressWarnings("unchecked") - public Set> entrySet() { - Set> es = entrySet; - return (es != null) ? es : (entrySet = (Set>) (Set) new EntrySet()); - } - - // Iterator support - - abstract class CoreIterator { - - int currentPos = -1; - Entry lastReturned = null; - private List> entries = ArrayOrderedMap.this.getEntries(); - - public boolean hasMore() { - if ((currentPos + 1) < entries.size()) { - return true; - } - return false; - } - - public Entry getNext() { - currentPos++; - try { - lastReturned = entries.get(currentPos); - } catch (RuntimeException e) { - throw new NoSuchElementException("There are no more items available to get, the last one was reached"); - } - return lastReturned; - } - - public void removeCurrent() { - if (currentPos < 0) { - throw new IllegalArgumentException("Have not called next yet, cannot remove from this iterator"); - } - entries.remove(currentPos); - ArrayOrderedMap.this.remove(lastReturned.getKey()); - } - - // shared methods - public boolean hasNext() { return hasMore(); } - public boolean hasMoreElements() { return hasMore(); } - public void remove() { removeCurrent(); } - - } - - final class KeyIterator extends CoreIterator implements Iterator, Enumeration { - public K next() { return super.getNext().getKey(); } - public K nextElement() { return next(); } - } - - final class ValueIterator extends CoreIterator implements Iterator, Enumeration { - public V next() { return super.getNext().getValue(); } - public V nextElement() { return next(); } - } - - final class EntryIterator extends CoreIterator implements Iterator>, Enumeration> { - public Entry next() { return super.getNext(); } - public Entry nextElement() { return next(); } - } - - // All below copied from CHM - - final class KeySet extends AbstractSet { - public Iterator iterator() { - return new KeyIterator(); - } - public int size() { - return ArrayOrderedMap.this.size(); - } - public boolean contains(Object o) { - return ArrayOrderedMap.this.containsKey(o); - } - public boolean remove(Object o) { - return ArrayOrderedMap.this.remove(o) != null; - } - public void clear() { - ArrayOrderedMap.this.clear(); - } - public Object[] toArray() { - Collection c = new ArrayList(); - for (Iterator i = iterator(); i.hasNext(); ) - c.add(i.next()); - return c.toArray(); - } - public T[] toArray(T[] a) { - Collection c = new ArrayList(); - for (Iterator i = iterator(); i.hasNext(); ) - c.add(i.next()); - return c.toArray(a); - } - } - - final class Values extends AbstractCollection { - public Iterator iterator() { - return new ValueIterator(); - } - public int size() { - return ArrayOrderedMap.this.size(); - } - public boolean contains(Object o) { - return ArrayOrderedMap.this.containsValue(o); - } - public void clear() { - ArrayOrderedMap.this.clear(); - } - public Object[] toArray() { - Collection c = new ArrayList(); - for (Iterator i = iterator(); i.hasNext(); ) - c.add(i.next()); - return c.toArray(); - } - public T[] toArray(T[] a) { - Collection c = new ArrayList(); - for (Iterator i = iterator(); i.hasNext(); ) - c.add(i.next()); - return c.toArray(a); - } - } - - @SuppressWarnings("unchecked") - final class EntrySet extends AbstractSet> { - public Iterator> iterator() { - return new EntryIterator(); - } - public boolean contains(Object o) { - if (!(o instanceof Map.Entry)) - return false; - Map.Entry e = (Map.Entry)o; - V v = ArrayOrderedMap.this.get(e.getKey()); - return v != null && v.equals(e.getValue()); - } - public boolean remove(Object o) { - if (!(o instanceof Map.Entry)) - return false; - Map.Entry e = (Map.Entry)o; - return ArrayOrderedMap.this.remove(e.getKey()) != null; - } - public int size() { - return ArrayOrderedMap.this.size(); - } - public void clear() { - ArrayOrderedMap.this.clear(); - } - public Object[] toArray() { - // Since we don't ordinarily have distinct Entry objects, we - // must pack elements using exportable SimpleEntry - Collection> c = new ArrayList>(size()); - for (Iterator> i = iterator(); i.hasNext(); ) - c.add(new SimpleEntry(i.next())); - return c.toArray(); - } - public T[] toArray(T[] a) { - Collection> c = new ArrayList>(size()); - for (Iterator> i = iterator(); i.hasNext(); ) - c.add(new SimpleEntry(i.next())); - return c.toArray(a); - } - - } - - - /** - * This duplicates java.util.AbstractMap.SimpleEntry until this class - * is made accessible. - */ - static final class SimpleEntry implements Entry { - K key; - V value; - - public SimpleEntry(K key, V value) { - this.key = key; - this.value = value; - } - - public SimpleEntry(Entry e) { - this.key = e.getKey(); - this.value = e.getValue(); - } - - public K getKey() { - return key; - } - - public V getValue() { - return value; - } - - public V setValue(V value) { - V oldValue = this.value; - this.value = value; - return oldValue; - } - - @SuppressWarnings("unchecked") - public boolean equals(Object o) { - if (!(o instanceof Map.Entry)) - return false; - Map.Entry e = (Map.Entry)o; - return eq(key, e.getKey()) && eq(value, e.getValue()); - } - - public int hashCode() { - return ((key == null) ? 0 : key.hashCode()) ^ - ((value == null) ? 0 : value.hashCode()); - } - - public String toString() { - return key + "=" + value; - } - - static boolean eq(Object o1, Object o2) { - return (o1 == null ? o2 == null : o1.equals(o2)); - } - } - -} diff --git a/src/main/java/org/azeckoski/reflectutils/map/OrderedMap.java b/src/main/java/org/azeckoski/reflectutils/map/OrderedMap.java deleted file mode 100644 index 4e484b8..0000000 --- a/src/main/java/org/azeckoski/reflectutils/map/OrderedMap.java +++ /dev/null @@ -1,63 +0,0 @@ -/** - * $Id: OrderedMap.java 2 2008-10-01 10:04:26Z azeckoski $ - * $URL: http://reflectutils.googlecode.com/svn/trunk/src/main/java/org/azeckoski/reflectutils/map/OrderedMap.java $ - * OrderedMap.java - genericdao - May 5, 2008 2:16:35 PM - azeckoski - ************************************************************************** - * Copyright (c) 2008 Aaron Zeckoski - * Licensed under the Apache License, Version 2 - * - * A copy of the Apache License, Version 2 has been included in this - * distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt - * - * Aaron Zeckoski (azeckoski@gmail.com) (aaronz@vt.edu) (aaron@caret.cam.ac.uk) - */ - -package org.azeckoski.reflectutils.map; - -import java.util.List; -import java.util.Map; - -/** - * A map which keeps track of the order the entries are added - * and allows retrieval of entries in the order they were entered as well
- * Use {@link ArrayOrderedMap} or {@link ConcurrentOrderedMap} depending on your needs
- * - * @author Aaron Zeckoski (azeckoski @ gmail.com) - */ -public interface OrderedMap extends Map { - - /** - * @param name (optional) the name to use when encoding this map of data, may be null - */ - public String getName(); - /** - * @param name (optional) the name to use when encoding this map of data - */ - public void setName(String name); - - /** - * @return a list of all the keys in this map in the order they were entered, - * this list is a copy and manipulating it has no effect on the map - */ - public List getKeys(); - - /** - * @return a list of all the values in this map in the order they were entered, - * this list is a copy and manipulating it has no effect on the map - */ - public List getValues(); - - /** - * @return a list of all the entries in this map in the order they were created - */ - public List> getEntries(); - - /** - * Get an entry based on the position it is in the map (based on the order entries were created) - * @param position the position in the map (must be less that the size) - * @return the entry at that position - * @throws IllegalArgumentException if the position is greater than the map size - */ - public Entry getEntry(int position); - -} diff --git a/src/main/java/org/azeckoski/reflectutils/map/package.html b/src/main/java/org/azeckoski/reflectutils/map/package.html deleted file mode 100644 index 875b0f0..0000000 --- a/src/main/java/org/azeckoski/reflectutils/map/package.html +++ /dev/null @@ -1,5 +0,0 @@ - - -A map implementation which supports insertion order retrieval of the keys and values, fully supports removal and interation - - \ No newline at end of file diff --git a/src/main/java/org/azeckoski/reflectutils/package.html b/src/main/java/org/azeckoski/reflectutils/package.html deleted file mode 100644 index 2aa3b48..0000000 --- a/src/main/java/org/azeckoski/reflectutils/package.html +++ /dev/null @@ -1,35 +0,0 @@ - - -

A set of reflection utilities and miscellaneous utilities related -to working with classes and their fields with no dependencies which is -compatible with java 1.5 and generics.

-

Features:

-

These are built to be compatible with Apache -Commons BeanUtils and the nesting structure works the same, refer to the -apache BeanUtils project docs for details. Support for Apache DynaClass -/ DynaBean is included. Current users of beanutils should be able to -drop in these utilities and gain the functionality with minimal code -changes.

-

Handles field operations for properties (getters and setters), -partial properties (only getter or only setter), and fields. This is -configurable to use the fields only, properties only, or the hybrid -approach (default). This improves upon the BeanUtils limitation of -handling only properties or the Google utilities limitation of handling -only fields.

-

Getting and setting fields supports simple, nested, indexed, and -mapped values -

    -
  • Simple: Get/set a field in a bean (or map), - Example: "title", "id"
  • -
  • Nested: Get/set a field in a bean which is - contained in another bean, Example: "someBean.title", - "someBean.id"
  • -
  • Indexed: Get/set a list/array item by index - in a bean, Example: "myList1", "anArray2"
  • -
  • Mapped: Get/set a map entry by key in a bean, - Example: "myMap(key)", "someMap(thing)"
  • -
-

- - \ No newline at end of file diff --git a/src/main/java/org/azeckoski/reflectutils/refmap/FinalizableReference.java b/src/main/java/org/azeckoski/reflectutils/refmap/FinalizableReference.java deleted file mode 100644 index d4ef1e5..0000000 --- a/src/main/java/org/azeckoski/reflectutils/refmap/FinalizableReference.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2007 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.azeckoski.reflectutils.refmap; - -/** - * Implemented by references that have code to run after garbage collection of - * their referents. - * - * @see FinalizableReferenceQueue - * @author Bob Lee - */ -public interface FinalizableReference { - - /** - * Invoked on a background thread after the referent has been garbage - * collected. - */ - void finalizeReferent(); -} diff --git a/src/main/java/org/azeckoski/reflectutils/refmap/FinalizableReferenceQueue.java b/src/main/java/org/azeckoski/reflectutils/refmap/FinalizableReferenceQueue.java deleted file mode 100644 index 01b566f..0000000 --- a/src/main/java/org/azeckoski/reflectutils/refmap/FinalizableReferenceQueue.java +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Copyright (C) 2007 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.azeckoski.reflectutils.refmap; - -import org.azeckoski.reflectutils.LifecycleManager; - -import java.lang.ref.ReferenceQueue; -import java.lang.reflect.Method; -import java.lang.reflect.InvocationTargetException; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.net.URL; -import java.net.URLClassLoader; -import java.net.URISyntaxException; -import java.io.IOException; -import java.io.FileNotFoundException; - -/** - * A reference queue with an associated background thread that dequeues - * references and invokes {@link FinalizableReference#finalizeReferent()} on - * them. - * - *

Keep a strong reference to this object until all of the associated - * referents have been finalized. If this object is garbage collected earlier, - * the backing thread will not invoke {@code finalizeReferent()} on the - * remaining references. - * - * @author Bob Lee - */ -public class FinalizableReferenceQueue { - - /* - * The Finalizer thread keeps a phantom reference to this object. When the - * client (ReferenceMap, for example) no longer has a strong reference to - * this object, the garbage collector will reclaim it and enqueue the - * phantom reference. The enqueued reference will trigger the Finalizer to - * stop. - * - * If this library is loaded in the system class loader, - * FinalizableReferenceQueue can load Finalizer directly with no problems. - * - * If this library is loaded in an application class loader, it's important - * that Finalizer not have a strong reference back to the class loader. - * Otherwise, you could have a graph like this: - * - * Finalizer Thread - * runs instance of -> Finalizer.class - * loaded by -> Application class loader - * which loaded -> ReferenceMap.class - * which has a static -> FinalizableReferenceQueue instance - * - * Even if no other references to classes from the application class loader - * remain, the Finalizer thread keeps an indirect strong reference to the - * queue in ReferenceMap, which keeps the Finalizer running, and as a result, - * the application class loader can never be reclaimed. - * - * This means that dynamically loaded web applications and OSGi bundles can't - * be unloaded. - * - * If the library is loaded in an application class loader, we try to break - * the cycle by loading Finalizer in its own independent class loader: - * - * System class loader - * -> Application class loader - * -> ReferenceMap - * -> FinalizableReferenceQueue - * -> etc. - * -> Decoupled class loader - * -> Finalizer - * - * Now, Finalizer no longer keeps an indirect strong reference to the - * static FinalizableReferenceQueue field in ReferenceMap. The application - * class loader can be reclaimed at which point the Finalizer thread will - * stop and its decoupled class loader can also be reclaimed. - * - * If any of this fails along the way, we fall back to loading Finalizer - * directly in the application class loader. - */ - - private static final Logger logger - = Logger.getLogger(FinalizableReferenceQueue.class.getName()); - - private static final String FINALIZER_CLASS_NAME - = "org.azeckoski.reflectutils.refmap.Finalizer"; - - /** Reference to Finalizer.startFinalizer(). */ - private static final Method startFinalizer; - static { - Class finalizer; - - // If the LifeCycleManager has been activated, then load the Finalizer in the current ClassLoader - // so that the Finalizer thread can register to receive shutdown notification - if (LifecycleManager.isActive()) { - finalizer = loadFinalizer(new DirectLoader()); - } else { - finalizer = loadFinalizer( - new SystemLoader(), new DecoupledLoader(), new DirectLoader()); - } - - startFinalizer = getStartFinalizer(finalizer); - } - - /** - * The actual reference queue that our background thread will poll. - */ - final ReferenceQueue queue; - - /** - * Constructs a new queue. - */ - @SuppressWarnings("unchecked") - public FinalizableReferenceQueue() { - // We could start the finalizer lazily, but I'd rather it blow up early. - try { - this.queue = (ReferenceQueue) startFinalizer.invoke(null, - FinalizableReference.class, this, LifecycleManager.isActive()); - } catch (IllegalAccessException e) { - // Finalizer.startFinalizer() is public. - throw new AssertionError(e); - } catch (InvocationTargetException e) { - throw new RuntimeException(e); - } - } - - /** - * Iterates through the given loaders until it finds one that can load - * Finalizer. - * - * @return Finalizer.class - */ - private static Class loadFinalizer(FinalizerLoader... loaders) { - for (FinalizerLoader loader : loaders) { - Class finalizer = loader.loadFinalizer(); - if (finalizer != null) { - return finalizer; - } - } - - throw new AssertionError(); - } - - /** - * Loads Finalizer.class. - */ - interface FinalizerLoader { - - /** - * Returns Finalizer.class or null if this loader shouldn't or can't load - * it. - * - * @throws SecurityException if we don't have the appropriate priveleges - */ - Class loadFinalizer(); - } - - /** - * Tries to load Finalizer from the system class loader. If Finalizer is - * in the system class path, we needn't create a separate loader. - */ - static class SystemLoader implements FinalizerLoader { - public Class loadFinalizer() { - ClassLoader systemLoader; - try { - systemLoader = ClassLoader.getSystemClassLoader(); - } catch (SecurityException e) { - logger.info("Not allowed to access system class loader."); - return null; - } - if (systemLoader != null) { - try { - return systemLoader.loadClass(FINALIZER_CLASS_NAME); - } catch (ClassNotFoundException e) { - // Ignore. Finalizer is simply in a child class loader. - return null; - } - } else { - return null; - } - } - } - - /** - * Try to load Finalizer in its own class loader. If Finalizer's thread - * had a direct reference to our class loader (which could be that of - * a dynamically loaded web application or OSGi bundle), it would prevent - * our class loader from getting garbage collected. - */ - static class DecoupledLoader implements FinalizerLoader { - - private static final String LOADING_ERROR = "Could not load Finalizer in" - + " its own class loader. Loading Finalizer in the current class loader" - + " instead. As a result, you will not be able to garbage collect this" - + " class loader. To support reclaiming this class loader, either" - + " resolve the underlying issue, or move Google Collections to your" - + " system class path."; - - public Class loadFinalizer() { - try { - /* - * We use URLClassLoader because it's the only concrete class loader - * implementation in the JDK. If we used our own ClassLoader subclass, - * Finalizer would indirectly reference this class loader: - * - * Finalizer.class -> - * CustomClassLoader -> - * CustomClassLoader.class -> - * This class loader - * - * System class loader will (and must) be the parent. - */ - ClassLoader finalizerLoader = newLoader(getBaseUrl()); - return finalizerLoader.loadClass(FINALIZER_CLASS_NAME); - } catch (Exception e) { - logger.log(Level.WARNING, LOADING_ERROR, e); - return null; - } - } - - /** - * Gets URL for base of path containing Finalizer.class. - */ - URL getBaseUrl() throws IOException, URISyntaxException { - // Find URL pointing to Finalizer.class file. - String finalizerPath = FINALIZER_CLASS_NAME.replace('.', '/') + ".class"; - URL finalizerUrl = getClass().getClassLoader().getResource(finalizerPath); - if (finalizerUrl == null) { - throw new FileNotFoundException(finalizerPath); - } - - // Find URL pointing to base of class path. - String urlString = finalizerUrl.toString(); - if (!urlString.endsWith(finalizerPath)) { - throw new IOException("Unsupported path style: " + urlString); - } - urlString = urlString.substring(0, - urlString.length() - finalizerPath.length()); - return new URL(urlString); - } - - /** Creates a class loader with the given base URL as its classpath. */ - URLClassLoader newLoader(URL base) { - return new URLClassLoader(new URL[] { base }); - } - } - - /** - * Loads Finalizer directly using the current class loader. We won't be - * able to garbage collect this class loader, but at least the world - * doesn't end. - */ - static class DirectLoader implements FinalizerLoader { - public Class loadFinalizer() { - try { - return Class.forName(FINALIZER_CLASS_NAME); - } catch (ClassNotFoundException e) { - throw new AssertionError(e); - } - } - } - - /** - * Looks up Finalizer.startFinalizer(). - */ - static Method getStartFinalizer(Class finalizer) { - try { - return finalizer.getMethod("startFinalizer", Class.class, Object.class, boolean.class); - } catch (NoSuchMethodException e) { - throw new AssertionError(e); - } - } -} - diff --git a/src/main/java/org/azeckoski/reflectutils/refmap/FinalizableSoftReference.java b/src/main/java/org/azeckoski/reflectutils/refmap/FinalizableSoftReference.java deleted file mode 100644 index 64f39f2..0000000 --- a/src/main/java/org/azeckoski/reflectutils/refmap/FinalizableSoftReference.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2007 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.azeckoski.reflectutils.refmap; - -import java.lang.ref.SoftReference; - -/** - * Soft reference with a {@code finalizeReferent()} method which a background - * thread invokes after the garbage collector reclaims the referent. This is a - * simpler alternative to using a {@link java.lang.ref.ReferenceQueue}. - * - * @author Bob Lee - */ -public abstract class FinalizableSoftReference extends SoftReference - implements FinalizableReference { - - /** - * Consructs a new finalizable soft reference. - * - * @param referent to softly reference - * @param queue that should finalize the referent - */ - protected FinalizableSoftReference(T referent, - FinalizableReferenceQueue queue) { - super(referent, queue.queue); - } -} diff --git a/src/main/java/org/azeckoski/reflectutils/refmap/FinalizableWeakReference.java b/src/main/java/org/azeckoski/reflectutils/refmap/FinalizableWeakReference.java deleted file mode 100644 index ca792a3..0000000 --- a/src/main/java/org/azeckoski/reflectutils/refmap/FinalizableWeakReference.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2007 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.azeckoski.reflectutils.refmap; - -import java.lang.ref.WeakReference; - -/** - * Weak reference with a {@code finalizeReferent()} method which a background - * thread invokes after the garbage collector reclaims the referent. This is a - * simpler alternative to using a {@link java.lang.ref.ReferenceQueue}. - * - * @author Bob Lee - */ -public abstract class FinalizableWeakReference extends WeakReference - implements FinalizableReference { - - /** - * Consructs a new finalizable weak reference. - * - * @param referent to weakly reference - * @param queue that should finalize the referent - */ - protected FinalizableWeakReference(T referent, - FinalizableReferenceQueue queue) { - super(referent, queue.queue); - } -} diff --git a/src/main/java/org/azeckoski/reflectutils/refmap/Finalizer.java b/src/main/java/org/azeckoski/reflectutils/refmap/Finalizer.java deleted file mode 100644 index 7727c9a..0000000 --- a/src/main/java/org/azeckoski/reflectutils/refmap/Finalizer.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright (C) 2008 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.azeckoski.reflectutils.refmap; - -import org.azeckoski.reflectutils.Lifecycle; -import org.azeckoski.reflectutils.LifecycleManager; - -import java.util.logging.Logger; -import java.util.logging.Level; -import java.lang.ref.ReferenceQueue; -import java.lang.ref.Reference; -import java.lang.ref.WeakReference; -import java.lang.ref.PhantomReference; -import java.lang.reflect.Method; - -/** - * Thread that finalizes referents. All references should implement - * {@code com.google.common.base.FinalizableReference}. - * - *

While this class is public, we consider it to be *internal* and not part - * of our published API. It is public so we can access it reflectively across - * class loaders in secure environments. - * - *

This class can't depend on other Google Collections code. If we were - * to load this class in the same class loader as the rest of - * Google Collections, this thread would keep an indirect strong reference - * to the class loader and prevent it from being garbage collected. This - * poses a problem for environments where you want to throw away the class - * loader. For example, dynamically reloading a web application or unloading - * an OSGi bundle. - * - *

{@code com.google.common.base.FinalizableReferenceQueue} loads this class - * in its own class loader. That way, this class doesn't prevent the main - * class loader from getting garbage collected, and this class can detect when - * the main class loader has been garbage collected and stop itself. - */ -public class Finalizer extends Thread implements Lifecycle { - - private static final Logger logger - = Logger.getLogger(Finalizer.class.getName()); - - /** Name of FinalizableReference.class. */ - private static final String FINALIZABLE_REFERENCE - = "org.azeckoski.reflectutils.refmap.FinalizableReference"; - - /** - * Starts the Finalizer thread. FinalizableReferenceQueue calls this method - * reflectively. - * - * @param finalizableReferenceClass FinalizableReference.class - * @param frq reference to instance of FinalizableReferenceQueue that started - * this thread - * @return ReferenceQueue which Finalizer will poll - */ - public static ReferenceQueue startFinalizer( - Class finalizableReferenceClass, Object frq, boolean registerForLifecycle) { - /* - * We use FinalizableReference.class for two things: - * - * 1) To invoke FinalizableReference.finalizeReferent() - * - * 2) To detect when FinalizableReference's class loader has to be garbage - * collected, at which point, Finalizer can stop running - */ - if (!finalizableReferenceClass.getName().equals(FINALIZABLE_REFERENCE)) { - throw new IllegalArgumentException( - "Expected " + FINALIZABLE_REFERENCE + "."); - } - - Finalizer finalizerThread = new Finalizer(finalizableReferenceClass, frq); - finalizerThread.start(); - - // If we are running under the LifeCycleManager, register the created Thread - try { - if (registerForLifecycle) { - LifecycleManager.register(finalizerThread); - } - } catch (Exception e) { - System.err.println("Unable to register for lifecycle events: " + e.getMessage()); - // Ignore - } - - return finalizerThread.queue; - } - - private final WeakReference> finalizableReferenceClassReference; - private final PhantomReference frqReference; - private final ReferenceQueue queue = new ReferenceQueue(); - - /** Constructs a new finalizer thread. */ - private Finalizer(Class finalizableReferenceClass, Object frq) { - super(Finalizer.class.getName()); - - this.finalizableReferenceClassReference - = new WeakReference>(finalizableReferenceClass); - - // Keep track of the FRQ that started us so we know when to stop. - this.frqReference = new PhantomReference(frq, queue); - - setDaemon(true); - - // TODO: Priority? - } - - /** - * Loops continuously, pulling references off the queue and cleaning them up. - */ - @Override - public void run() { - try { - while (true) { - try { - cleanUp(queue.remove()); - } catch (InterruptedException e) { - // Thread has been interrupted, so do local cleanup - frqReference.clear(); - - // Ensure that anything that may be remaining on the queue is cleaned up - Reference reference = queue.poll(); - while (reference != null) { - cleanUp(reference); - reference = queue.poll(); - } - - // Shut down the current thread - throw new ShutDown(); - } - } - } catch (ShutDown shutDown) { /* ignore */ } - } - - /** - * Cleans up a single reference. Catches and logs all throwables. - */ - private void cleanUp(Reference reference) throws ShutDown { - Method finalizeReferentMethod = getFinalizeReferentMethod(); - do { - /* - * This is for the benefit of phantom references. Weak and soft - * references will have already been cleared by this point. - */ - reference.clear(); - - if (reference == frqReference) { - /* - * The client no longer has a reference to the - * FinalizableReferenceQueue. We can stop. - */ - throw new ShutDown(); - } - - try { - finalizeReferentMethod.invoke(reference); - } catch (Throwable t) { - logger.log(Level.SEVERE, "Error cleaning up after reference.", t); - } - - /* - * Loop as long as we have references available so as not to waste - * CPU looking up the Method over and over again. - */ - } while ((reference = queue.poll()) != null); - } - - /** - * Looks up FinalizableReference.finalizeReferent() method. - */ - private Method getFinalizeReferentMethod() throws ShutDown { - Class finalizableReferenceClass - = finalizableReferenceClassReference.get(); - if (finalizableReferenceClass == null) { - /* - * FinalizableReference's class loader was reclaimed. While there's a - * chance that other finalizable references could be enqueued - * subsequently (at which point the class loader would be resurrected - * by virtue of us having a strong reference to it), we should pretty - * much just shut down and make sure we don't keep it alive any longer - * than necessary. - */ - throw new ShutDown(); - } - try { - return finalizableReferenceClass.getMethod("finalizeReferent"); - } catch (NoSuchMethodException e) { - throw new AssertionError(e); - } - } - - /** - * Lifecycle method to destroy the finalizer thread - */ - public void shutdown() { - // Thread will shut itself down when interrupted - this.interrupt(); - } - - /** Indicates that it's time to shut down the Finalizer. */ - private class ShutDown extends Exception {} -} diff --git a/src/main/java/org/azeckoski/reflectutils/refmap/ReferenceMap.java b/src/main/java/org/azeckoski/reflectutils/refmap/ReferenceMap.java deleted file mode 100644 index 3973a1e..0000000 --- a/src/main/java/org/azeckoski/reflectutils/refmap/ReferenceMap.java +++ /dev/null @@ -1,648 +0,0 @@ -/** - * Copyright (C) 2006 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.azeckoski.reflectutils.refmap; - -import static org.azeckoski.reflectutils.refmap.ReferenceType.STRONG; - -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.Serializable; -import java.lang.ref.Reference; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.IdentityHashMap; -import java.util.Map; -import java.util.Set; -import java.util.WeakHashMap; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -/** - * Concurrent hash map that wraps keys and/or values in soft or weak - * references. Does not support null keys or values. Uses identity equality - * for weak and soft keys. - * - *

The concurrent semantics of {@link ConcurrentHashMap} combined with the - * fact that the garbage collector can asynchronously reclaim and clean up - * after keys and values at any time can lead to some racy semantics. For - * example, {@link #size()} returns an upper bound on the size, i.e. the actual - * size may be smaller in cases where the key or value has been reclaimed but - * the map entry has not been cleaned up yet. - * - *

Another example: If {@link #get(Object)} cannot find an existing entry - * for a key, it will try to create one. This operation is not atomic. One - * thread could {@link #put(Object, Object)} a value between the time another - * thread running {@code get()} checks for an entry and decides to create one. - * In this case, the newly created value will replace the put value in the - * map. Also, two threads running {@code get()} concurrently can potentially - * create duplicate values for a given key. - * - *

In other words, this class is great for caching but not atomicity. - * - *

To determine equality to a key, this implementation uses - * {@link Object#equals} for strong references, and identity-based equality for - * soft and weak references. In other words, for a map with weak or soft key - * references, {@link #get} returns {@code null} when passed an object that - * equals a map key, but isn't the same instance. This behavior is similar to - * the way {@link IdentityHashMap} handles key lookups. However, to determine - * value equality, as occurs when {@link #containsValue} is called, the - * {@code ReferenceMap} always uses {@code equals}, regardless of the value - * reference type. - * - *

Note: {@code new ReferenceMap(WEAK, STRONG)} is very nearly a - * drop-in replacement for {@link WeakHashMap}, but improves upon this by using - * only identity-based equality for keys. When possible, {@code ReferenceMap} - * should be preferred over the JDK collection, for its concurrency and greater - * flexibility. - * - * @author crazybob@google.com (Bob Lee) - */ -@SuppressWarnings("unchecked") -public class ReferenceMap implements Map, Serializable { - - private static final long serialVersionUID = 0; - - transient ConcurrentMap delegate; - - final ReferenceType keyReferenceType; - final ReferenceType valueReferenceType; - - /** - * Concurrent hash map that wraps keys and/or values based on specified - * reference types. - * - * @param keyReferenceType key reference type - * @param valueReferenceType value reference type - */ - public ReferenceMap(ReferenceType keyReferenceType, - ReferenceType valueReferenceType) { - ensureNotNull(keyReferenceType, valueReferenceType); - - if (keyReferenceType == ReferenceType.PHANTOM - || valueReferenceType == ReferenceType.PHANTOM) { - throw new IllegalArgumentException("Phantom references not supported."); - } - - this.delegate = new ConcurrentHashMap(); - this.keyReferenceType = keyReferenceType; - this.valueReferenceType = valueReferenceType; - } - - V internalGet(K key) { - Object valueReference = delegate.get(makeKeyReferenceAware(key)); - return valueReference == null - ? null - : (V) dereferenceValue(valueReference); - } - - public V get(final Object key) { - ensureNotNull(key); - return internalGet((K) key); - } - - V execute(Strategy strategy, K key, V value) { - ensureNotNull(key, value); - Object keyReference = referenceKey(key); - Object valueReference = strategy.execute( - this, - keyReference, - referenceValue(keyReference, value) - ); - return valueReference == null ? null - : (V) dereferenceValue(valueReference); - } - - public V put(K key, V value) { - return execute(putStrategy(), key, value); - } - - public V remove(Object key) { - ensureNotNull(key); - Object referenceAwareKey = makeKeyReferenceAware(key); - Object valueReference = delegate.remove(referenceAwareKey); - return valueReference == null ? null - : (V) dereferenceValue(valueReference); - } - - public int size() { - return delegate.size(); - } - - public boolean isEmpty() { - return delegate.isEmpty(); - } - - public boolean containsKey(Object key) { - ensureNotNull(key); - Object referenceAwareKey = makeKeyReferenceAware(key); - return delegate.containsKey(referenceAwareKey); - } - - public boolean containsValue(Object value) { - ensureNotNull(value); - for (Object valueReference : delegate.values()) { - if (value.equals(dereferenceValue(valueReference))) { - return true; - } - } - return false; - } - - public void putAll(Map t) { - for (Map.Entry entry : t.entrySet()) { - put(entry.getKey(), entry.getValue()); - } - } - - public void clear() { - delegate.clear(); - } - - /** - * Returns an unmodifiable set view of the keys in this map. As this method - * creates a defensive copy, the performance is O(n). - */ - public Set keySet() { - return Collections.unmodifiableSet( - dereferenceKeySet(delegate.keySet())); - } - - /** - * Returns an unmodifiable set view of the values in this map. As this - * method creates a defensive copy, the performance is O(n). - */ - public Collection values() { - return Collections.unmodifiableCollection( - dereferenceValues(delegate.values())); - } - - public V putIfAbsent(K key, V value) { - // TODO (crazybob) if the value has been gc'ed but the entry hasn't been - // cleaned up yet, this put will fail. - return execute(putIfAbsentStrategy(), key, value); - } - - public boolean remove(Object key, Object value) { - ensureNotNull(key, value); - Object referenceAwareKey = makeKeyReferenceAware(key); - Object referenceAwareValue = makeValueReferenceAware(value); - return delegate.remove(referenceAwareKey, referenceAwareValue); - } - - public boolean replace(K key, V oldValue, V newValue) { - ensureNotNull(key, oldValue, newValue); - Object keyReference = referenceKey(key); - - Object referenceAwareOldValue = makeValueReferenceAware(oldValue); - return delegate.replace( - keyReference, - referenceAwareOldValue, - referenceValue(keyReference, newValue) - ); - } - - public V replace(K key, V value) { - // TODO (crazybob) if the value has been gc'ed but the entry hasn't been - // cleaned up yet, this will succeed when it probably shouldn't. - return execute(replaceStrategy(), key, value); - } - - /** - * Returns an unmodifiable set view of the entries in this map. As this - * method creates a defensive copy, the performance is O(n). - */ - public Set> entrySet() { - Set> entrySet = new HashSet>(); - for (Map.Entry entry : delegate.entrySet()) { - Map.Entry dereferenced = dereferenceEntry(entry); - if (dereferenced != null) { - entrySet.add(dereferenced); - } - } - return Collections.unmodifiableSet(entrySet); - } - - /** - * Dereferences an entry. Returns null if the key or value has been gc'ed. - */ - Entry dereferenceEntry(Map.Entry entry) { - K key = dereferenceKey(entry.getKey()); - V value = dereferenceValue(entry.getValue()); - return (key == null || value == null) - ? null - : new Entry(key, value); - } - - /** - * Creates a reference for a key. - */ - Object referenceKey(K key) { - switch (keyReferenceType) { - case STRONG: return key; - case SOFT: return new SoftKeyReference(key); - case WEAK: return new WeakKeyReference(key); - default: throw new AssertionError(); - } - } - - /** - * Converts a reference to a key. - */ - K dereferenceKey(Object o) { - return (K) dereference(keyReferenceType, o); - } - - /** - * Converts a reference to a value. - */ - V dereferenceValue(Object o) { - return (V) dereference(valueReferenceType, o); - } - - /** - * Returns the refererent for reference given its reference type. - */ - Object dereference(ReferenceType referenceType, Object reference) { - return referenceType == STRONG ? reference : ((Reference) reference).get(); - } - - /** - * Creates a reference for a value. - */ - Object referenceValue(Object keyReference, Object value) { - switch (valueReferenceType) { - case STRONG: return value; - case SOFT: return new SoftValueReference(keyReference, value); - case WEAK: return new WeakValueReference(keyReference, value); - default: throw new AssertionError(); - } - } - - /** - * Dereferences a set of key references. - */ - Set dereferenceKeySet(Set keyReferences) { - return keyReferenceType == STRONG - ? keyReferences - : dereferenceCollection(keyReferenceType, keyReferences, new HashSet()); - } - - /** - * Dereferences a collection of value references. - */ - Collection dereferenceValues(Collection valueReferences) { - return valueReferenceType == STRONG - ? valueReferences - : dereferenceCollection(valueReferenceType, valueReferences, - new ArrayList(valueReferences.size())); - } - - /** - * Wraps key so it can be compared to a referenced key for equality. - */ - Object makeKeyReferenceAware(Object o) { - return keyReferenceType == STRONG ? o : new KeyReferenceAwareWrapper(o); - } - - /** - * Wraps value so it can be compared to a referenced value for equality. - */ - Object makeValueReferenceAware(Object o) { - return valueReferenceType == STRONG ? o : new ReferenceAwareWrapper(o); - } - - /** - * Dereferences elements in {@code in} using - * {@code referenceType} and puts them in {@code out}. Returns - * {@code out}. - */ - > T dereferenceCollection( - ReferenceType referenceType, T in, T out) { - for (Object reference : in) { - out.add(dereference(referenceType, reference)); - } - return out; - } - - static int keyHashCode(Object key) { - return System.identityHashCode(key); - } - - /** - * Tests weak and soft references for identity equality. Compares references - * to other references and wrappers. If o is a reference, this returns true - * if r == o or if r and o reference the same non null object. If o is a - * wrapper, this returns true if r's referent is identical to the wrapped - * object. - */ - static boolean referenceEquals(Reference r, Object o) { - // compare reference to reference. - if (o instanceof InternalReference) { - // are they the same reference? used in cleanup. - if (o == r) { - return true; - } - - // do they reference identical values? used in conditional puts. - Object referent = ((Reference) o).get(); - return referent != null && referent == r.get(); - } - - // is the wrapped object identical to the referent? used in lookups. - return ((ReferenceAwareWrapper) o).unwrap() == r.get(); - } - - /** - * Big hack. Used to compare keys and values to referenced keys and values - * without creating more references. - */ - static class ReferenceAwareWrapper { - - final Object wrapped; - - ReferenceAwareWrapper(Object wrapped) { - this.wrapped = wrapped; - } - - Object unwrap() { - return wrapped; - } - - public int hashCode() { - return wrapped.hashCode(); - } - - public boolean equals(Object obj) { - // defer to reference's equals() logic. - return obj == null ? false : obj.equals(this); - } - } - - /** - * Used for keys. Overrides hash code to use identity hash code. - */ - static class KeyReferenceAwareWrapper extends ReferenceAwareWrapper { - - public KeyReferenceAwareWrapper(Object wrapped) { - super(wrapped); - } - - @Override public int hashCode() { - return System.identityHashCode(wrapped); - } - @Override public boolean equals(Object arg0) { - return super.equals(arg0); - } - } - /** - * Lazy initialization holder for finalizable reference queue. - */ - private static class ReferenceQueue { - private static final FinalizableReferenceQueue instance - = new FinalizableReferenceQueue(); - } - - /* - * Marker interface to differentiate external and internal references. Also - * duplicates finalizeReferent() and Reference.get() for internal use. - */ - private interface InternalReference { - void finalizeReferent(); - Object get(); - } - - private class SoftKeyReference extends FinalizableSoftReference - implements InternalReference { - final int hashCode; - - SoftKeyReference(Object key) { - super(key, ReferenceQueue.instance); - hashCode = System.identityHashCode(key); - } - public void finalizeReferent() { - delegate.remove(this); - } - @Override public int hashCode() { - return hashCode; - } - @Override public boolean equals(Object object) { - return referenceEquals(this, object); - } - } - - private class SoftValueReference extends FinalizableSoftReference - implements InternalReference { - final Object keyReference; - - SoftValueReference(Object keyReference, Object value) { - super(value, ReferenceQueue.instance); - this.keyReference = keyReference; - } - public void finalizeReferent() { - delegate.remove(keyReference, this); - } - @Override public int hashCode() { - // It's hard to define a useful hash code, so we're careful not to use it. - throw new AssertionError("don't hash me"); - } - @Override public boolean equals(Object obj) { - return referenceEquals(this, obj); - } - } - - /* - * WeakKeyReference/WeakValueReference are absolutely identical to - * SoftKeyReference/SoftValueReference except for which classes they extend. - */ - - private class WeakKeyReference extends FinalizableWeakReference - implements InternalReference { - final int hashCode; - - WeakKeyReference(Object key) { - super(key, ReferenceQueue.instance); - hashCode = System.identityHashCode(key); - } - public void finalizeReferent() { - delegate.remove(this); - } - @Override public int hashCode() { - return hashCode; - } - @Override public boolean equals(Object object) { - return referenceEquals(this, object); - } - } - - private class WeakValueReference extends FinalizableWeakReference - implements InternalReference { - final Object keyReference; - - WeakValueReference(Object keyReference, Object value) { - super(value, ReferenceQueue.instance); - this.keyReference = keyReference; - } - public void finalizeReferent() { - delegate.remove(keyReference, this); - } - @Override public int hashCode() { - // It's hard to define a useful hash code, so we're careful not to use it. - throw new AssertionError("don't hash me"); - } - @Override public boolean equals(Object obj) { - return referenceEquals(this, obj); - } - } - - protected interface Strategy { - public Object execute(ReferenceMap map, Object keyReference, - Object valueReference); - } - - protected Strategy putStrategy() { - return PutStrategy.PUT; - } - - protected Strategy putIfAbsentStrategy() { - return PutStrategy.PUT_IF_ABSENT; - } - - protected Strategy replaceStrategy() { - return PutStrategy.REPLACE; - } - - protected enum PutStrategy implements Strategy { - PUT { - public Object execute(ReferenceMap map, Object keyReference, - Object valueReference) { - return map.delegate.put(keyReference, valueReference); - } - }, - - REPLACE { - public Object execute(ReferenceMap map, Object keyReference, - Object valueReference) { - return map.delegate.replace(keyReference, valueReference); - } - }, - - PUT_IF_ABSENT { - public Object execute(ReferenceMap map, Object keyReference, - Object valueReference) { - return map.delegate.putIfAbsent(keyReference, valueReference); - } - }; - }; - - private static PutStrategy defaultPutStrategy; - public static void setDefaultPutStrategy(PutStrategy defaultPutStrategy) { - ReferenceMap.defaultPutStrategy = defaultPutStrategy; - } - protected PutStrategy getPutStrategy() { - return defaultPutStrategy; - } - - - class Entry implements Map.Entry { - - final K key; - final V value; - - public Entry(K key, V value) { - this.key = key; - this.value = value; - } - - public K getKey() { - return this.key; - } - - public V getValue() { - return this.value; - } - - public V setValue(V value) { - return put(key, value); - } - - public int hashCode() { - return key.hashCode() * 31 + value.hashCode(); - } - - public boolean equals(Object o) { - if (!(o instanceof ReferenceMap.Entry)) { - return false; - } - - Entry entry = (Entry) o; - return key.equals(entry.key) && value.equals(entry.value); - } - - public String toString() { - return key + "=" + value; - } - } - - static void ensureNotNull(Object o) { - if (o == null) { - throw new NullPointerException(); - } - } - - static void ensureNotNull(Object... array) { - for (int i = 0; i < array.length; i++) { - if (array[i] == null) { - throw new NullPointerException("Argument #" + i + " is null."); - } - } - } - - private void writeObject(ObjectOutputStream out) throws IOException { - out.defaultWriteObject(); - out.writeInt(size()); - for (Map.Entry entry : delegate.entrySet()) { - Object key = dereferenceKey(entry.getKey()); - Object value = dereferenceValue(entry.getValue()); - - // don't persist gc'ed entries. - if (key != null && value != null) { - out.writeObject(key); - out.writeObject(value); - } - } - out.writeObject(null); - } - - private void readObject(ObjectInputStream in) throws IOException, - ClassNotFoundException { - in.defaultReadObject(); - int size = in.readInt(); - this.delegate = new ConcurrentHashMap(size); - while (true) { - K key = (K) in.readObject(); - if (key == null) { - break; - } - V value = (V) in.readObject(); - put(key, value); - } - } - -} diff --git a/src/main/java/org/azeckoski/reflectutils/refmap/ReferenceType.java b/src/main/java/org/azeckoski/reflectutils/refmap/ReferenceType.java deleted file mode 100644 index 59b59a9..0000000 --- a/src/main/java/org/azeckoski/reflectutils/refmap/ReferenceType.java +++ /dev/null @@ -1,55 +0,0 @@ -/** - * Copyright (C) 2006 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.azeckoski.reflectutils.refmap; - -/** - * Reference type. Used to specify what type of reference to keep to a - * referent. - * - * @see java.lang.ref.Reference - * @author crazybob@google.com (Bob Lee) - */ -public enum ReferenceType { - - /** - * Prevents referent from being reclaimed by the garbage collector. - */ - STRONG, - - /** - * Referent reclaimed in an LRU fashion when the VM runs low on memory and - * no strong references exist. - * - * @see java.lang.ref.SoftReference - */ - SOFT, - - /** - * Referent reclaimed when no strong or soft references exist. - * - * @see java.lang.ref.WeakReference - */ - WEAK, - - /** - * Similar to weak references except the garbage collector doesn't actually - * reclaim the referent. More flexible alternative to finalization. - * - * @see java.lang.ref.PhantomReference - */ - PHANTOM; -} diff --git a/src/main/java/org/azeckoski/reflectutils/refmap/package.html b/src/main/java/org/azeckoski/reflectutils/refmap/package.html deleted file mode 100644 index 7c6ee8e..0000000 --- a/src/main/java/org/azeckoski/reflectutils/refmap/package.html +++ /dev/null @@ -1,5 +0,0 @@ - - -A map for holding soft/weak references to objects (key and values) - - \ No newline at end of file diff --git a/src/main/java/org/azeckoski/reflectutils/transcoders/HTMLTranscoder.java b/src/main/java/org/azeckoski/reflectutils/transcoders/HTMLTranscoder.java deleted file mode 100644 index 96d78e6..0000000 --- a/src/main/java/org/azeckoski/reflectutils/transcoders/HTMLTranscoder.java +++ /dev/null @@ -1,378 +0,0 @@ -/** - * $Id: HTMLTranscoder.java 81 2011-12-19 17:03:40Z azeckoski $ - * $URL: http://reflectutils.googlecode.com/svn/trunk/src/main/java/org/azeckoski/reflectutils/transcoders/HTMLTranscoder.java $ - * HTMLTranscoder.java - entity-broker - Sep 15, 2008 6:36:42 PM - azeckoski - ************************************************************************** - * Copyright (c) 2008 Aaron Zeckoski - * Licensed under the Apache License, Version 2.0 - * - * A copy of the Apache License has been included in this - * distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt - * - * Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk) - */ - -package org.azeckoski.reflectutils.transcoders; - -import java.lang.reflect.Array; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import org.azeckoski.reflectutils.ArrayUtils; -import org.azeckoski.reflectutils.ConstructorUtils; -import org.azeckoski.reflectutils.ReflectUtils; -import org.azeckoski.reflectutils.ClassFields.FieldsFilter; - - -/** - * Provides methods for encoding and decoding HTML
- * Note that the HTML parser is not supported - * - * @author Aaron Zeckoski (azeckoski @ gmail.com) - */ -@SuppressWarnings({ "unchecked", "rawtypes" }) -public class HTMLTranscoder implements Transcoder { - - public String getHandledFormat() { - return "html"; - } - - public String encode(Object object, String name, Map properties) { - return encode(object, name, properties, this.maxLevel); - } - - public String encode(Object object, String name, Map properties, int maxDepth) { - String encoded = ""; - if (object != null) { - if (name == null || "".equals(name)) { - name = DATA_KEY; - } - } - encoded = HTMLTranscoder.makeHTML(object, name, properties, this.humanOutput, this.includeNulls, this.includeClassField, maxDepth, this.encoders); - return encoded; - } - - public Map decode(String string) { - throw new UnsupportedOperationException("Decoding from HTML is not supported"); - } - - /** - * Default constructor: - * See other constructors for options - */ - public HTMLTranscoder() {} - - private List encoders = null; - public void setEncoders(List encoders) { - this.encoders = encoders; - } - public List getEncoders() { - return encoders; - } - public void addEncoder(ObjectEncoder objectEncoder) { - if (this.encoders == null) { - this.encoders = new ArrayList(); - } - this.encoders.add(objectEncoder); - } - - private boolean humanOutput = true; - private boolean includeNulls = true; - private boolean includeClassField = false; - /** - * @param humanOutput if true then enable human readable output (includes indentation and line breaks) - * @param includeNulls if true then create output tags for null values - * @param includeClassField if true then include the value from the "getClass()" method as "class" when encoding beans and maps - */ - public HTMLTranscoder(boolean humanOutput, boolean includeNulls, boolean includeClassField) { - this.humanOutput = humanOutput; - this.includeNulls = includeNulls; - this.includeClassField = includeClassField; - } - - private int maxLevel = 7; - /** - * @param maxLevel the number of objects to follow when traveling through the object, - * 0 means only the fields in the initial object, default is 7 - */ - public void setMaxLevel(int maxLevel) { - this.maxLevel = maxLevel; - } - - - public static final char SPACE = ' '; - public static final char AMP = '&'; - /** - * single quote (') - */ - public static final char APOS = '\''; - public static final char BANG = '!'; - public static final char EQ = '='; - public static final char GT = '>'; - public static final char LT = '<'; - public static final char QUEST = '?'; - public static final char QUOT = '"'; - public static final char SLASH = '/'; - public static final char EOL = '\n'; - - - /** - * Convert an object into a well-formed, element-normal HTML string. - * @param object any object - * @return the HTML string version of the object - */ - public static String makeHTML(Object object) { - return makeHTML(object, null, null, false, true, false, 7, null); - } - - /** - * Convert an object into a well-formed, element-normal HTML string. - * @param object any object - * @param tagName (optional) enclosing root tag - * @param humanOutput true of human readable output - * @param includeNulls true to include null values when generating tags - * @param maxLevel TODO - * @return the HTML string version of the object - */ - public static String makeHTML(Object object, String tagName, Map properties, boolean humanOutput, boolean includeNulls, boolean includeClassField, int maxLevel, List encoders) { - return "\n" - + toHTML(object, tagName, 0, maxLevel, humanOutput, includeNulls, includeClassField, properties, encoders) - + "
\n"; - } - - protected static String toHTML(Object object, String tagName, int level, int maxLevel, boolean humanOutput, boolean includeNulls, boolean includeClassField, Map properties, List encoders) { - StringBuilder sb = new StringBuilder(); - - if (object == null) { - if (includeNulls) { - // nulls are empty tags always - tagName = validate(tagName == null ? "null" : tagName); - makeLevelSpaces(sb, level, humanOutput); - sb.append(""); - sb.append(tagName); - sb.append(""); - sb.append("NULL"); - sb.append(""); - makeEOL(sb, humanOutput); - } - } else { - Class type = ConstructorUtils.getWrapper(object.getClass()); - if ( ConstructorUtils.isClassSimple(type) ) { - // Simple (String, Number, etc.) - tagName = validate(tagName == null ? makeElementName(type) : tagName); - makeLevelSpaces(sb, level, humanOutput); - String value = escapeForXML( object.toString() ); - sb.append(""); - sb.append(tagName); - sb.append(""); - sb.append(value); - sb.append(""); - makeEOL(sb, humanOutput); - } else if ( ConstructorUtils.isClassArray(type) ) { - // ARRAY - tagName = validate(tagName == null ? "array" : tagName); - int length = ArrayUtils.size((Object[])object); - Class elementType = ArrayUtils.type((Object[])object); - makeLevelSpaces(sb, level, humanOutput); - sb.append(""); - sb.append(tagName); - sb.append(" type=array"); - sb.append(" length="+length); - sb.append(""); - makeEOL(sb, humanOutput); - makeLevelSpaces(sb, level+1, humanOutput); - sb.append(""); - makeEOL(sb, humanOutput); - for (int i = 0; i < length; ++i) { - sb.append( toHTML(Array.get(object, i), makeElementName(elementType), level+2, maxLevel, humanOutput, includeNulls, includeClassField, properties, encoders) ); - } - makeLevelSpaces(sb, level+1, humanOutput); - sb.append("
"); - makeEOL(sb, humanOutput); - makeLevelSpaces(sb, level, humanOutput); - sb.append(""); - makeEOL(sb, humanOutput); - } else if ( ConstructorUtils.isClassCollection(type) ) { - // COLLECTION - tagName = validate(tagName == null ? "collection" : tagName); - Collection collection = (Collection) object; - makeLevelSpaces(sb, level, humanOutput); - sb.append(""); - sb.append(tagName); - sb.append(" type=collection"); - sb.append(" size="+collection.size()); - sb.append(""); - makeEOL(sb, humanOutput); - makeLevelSpaces(sb, level+1, humanOutput); - sb.append(""); - makeEOL(sb, humanOutput); - for (Object element : collection) { - Class elementType = null; - if (element != null) { - elementType = element.getClass(); - } - sb.append( toHTML(element, makeElementName(elementType), level+2, maxLevel, humanOutput, includeNulls, includeClassField, properties, encoders) ); - } - makeLevelSpaces(sb, level+1, humanOutput); - sb.append("
"); - makeEOL(sb, humanOutput); - makeLevelSpaces(sb, level, humanOutput); - sb.append(""); - makeEOL(sb, humanOutput); - } else { - // must be a bean or map, make sure it is a map - tagName = validate(tagName == null ? makeElementName(type) : tagName); - // special handling for certain object types - String special = TranscoderUtils.checkObjectSpecial(object); - if (special != null) { - if ("".equals(special)) { - // skip this one entirely - } else { - // just use the value in special to represent this - makeLevelSpaces(sb, level, humanOutput); - String value = escapeForXML( special ); - sb.append(""); - sb.append(tagName); - sb.append(""); - sb.append(value); - sb.append(""); - makeEOL(sb, humanOutput); - } - } else { - // normal handling - if ((maxLevel*2) <= level) { - // if the max level was reached then stop - sb.append(""); - sb.append(tagName); - sb.append(""); - sb.append( "MAX level reached (" ); - sb.append( level ); - sb.append( "):" ); - sb.append( escapeForXML(object.toString()) ); - sb.append(""); - makeEOL(sb, humanOutput); - } else { - String xmlType = "bean"; - Map map = null; - if (Map.class.isAssignableFrom(type)) { - xmlType = "map"; - map = (Map) object; - } else { - // reflect over objects - map = ReflectUtils.getInstance().getObjectValues(object, FieldsFilter.SERIALIZABLE, includeClassField); - } - makeLevelSpaces(sb, level, humanOutput); - sb.append(""); - sb.append(tagName); - sb.append(" type="+xmlType); - sb.append(" size="+map.size()); - sb.append(""); - makeEOL(sb, humanOutput); - makeLevelSpaces(sb, level+1, humanOutput); - sb.append(""); - makeEOL(sb, humanOutput); - for (Entry entry : map.entrySet()) { - if (entry.getKey() != null) { - sb.append( toHTML(entry.getValue(), entry.getKey().toString(), level+2, maxLevel, humanOutput, includeNulls, includeClassField, properties, encoders) ); - } - } - makeLevelSpaces(sb, level+1, humanOutput); - sb.append("
"); - makeEOL(sb, humanOutput); - makeLevelSpaces(sb, level, humanOutput); - sb.append(""); - makeEOL(sb, humanOutput); - } - } - } - } - return sb.toString(); - } - - protected static String makeElementName(Class type) { - String name = "element"; - if (type != null) { - if (! Map.class.isAssignableFrom(type)) { - name = type.getSimpleName(); - } - } - return name; - } - - protected static void makeEOL(StringBuilder sb, boolean includeEOL) { - if (includeEOL) { - sb.append(EOL); - } - } - - protected static final String SPACES = " "; - protected static void makeLevelSpaces(StringBuilder sb, int level, boolean includeEOL) { - level++; - if (includeEOL) { - for (int i = 0; i < level; i++) { - sb.append(SPACES); - } - } - } - - /** - * Escape a string for XML encoding: replace special characters with XML escapes: - *
-     * & (ampersand) is replaced by &amp;
-     * < (less than) is replaced by &lt;
-     * > (greater than) is replaced by &gt;
-     * " (double quote) is replaced by &quot;
-     * 
- * @param string The string to be escaped. - * @return The escaped string. - */ - public static String escapeForXML(String string) { - StringBuilder sb = new StringBuilder(); - for (int i = 0, len = string.length(); i < len; i++) { - char c = string.charAt(i); - switch (c) { - case AMP: - sb.append("&"); - break; - case LT: - sb.append("<"); - break; - case GT: - sb.append(">"); - break; - case QUOT: - sb.append("""); - break; - default: - sb.append(c); - } - } - return sb.toString(); - } - - /** - * Validates that a string contains no spaces and is non-null/non-empty - * Throw an exception if the string contains whitespace. - * Whitespace is not allowed in tagNames and attributes. - * @param string any string - * @throws IllegalArgumentException - */ - public static String validate(String string) { - if (string == null) { - throw new IllegalArgumentException("string is NULL"); - } - int i, length = string.length(); - if (length == 0) { - throw new IllegalArgumentException("Empty string."); - } - for (i = 0; i < length; i += 1) { - if (Character.isWhitespace(string.charAt(i))) { - throw new IllegalArgumentException("'" + string + "' contains a space character."); - } - } - return string; - } -} diff --git a/src/main/java/org/azeckoski/reflectutils/transcoders/JSONTranscoder.java b/src/main/java/org/azeckoski/reflectutils/transcoders/JSONTranscoder.java index 9b01a40..4a13131 100644 --- a/src/main/java/org/azeckoski/reflectutils/transcoders/JSONTranscoder.java +++ b/src/main/java/org/azeckoski/reflectutils/transcoders/JSONTranscoder.java @@ -1,655 +1,92 @@ -/** - * $Id: JSONTranscoder.java 110 2013-05-03 13:30:13Z azeckoski $ - * $URL: http://reflectutils.googlecode.com/svn/trunk/src/main/java/org/azeckoski/reflectutils/transcoders/JSONTranscoder.java $ - * JSONTranscoder.java - entity-broker - Sep 16, 2008 3:19:29 PM - azeckoski - ************************************************************************** - * Copyright (c) 2008 Aaron Zeckoski - * Licensed under the Apache License, Version 2.0 - * - * A copy of the Apache License has been included in this - * distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt - * - * Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk) - */ - package org.azeckoski.reflectutils.transcoders; -import java.lang.reflect.Array; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.sql.Timestamp; -import java.text.CharacterIterator; -import java.text.StringCharacterIterator; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import org.azeckoski.reflectutils.ArrayUtils; -import org.azeckoski.reflectutils.ConstructorUtils; -import org.azeckoski.reflectutils.ConversionUtils; -import org.azeckoski.reflectutils.ReflectUtils; -import org.azeckoski.reflectutils.ClassFields.FieldsFilter; -import org.azeckoski.reflectutils.map.ArrayOrderedMap; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Objects; /** - * Provides methods for encoding and decoding JSON - * - * @author Aaron Zeckoski (azeckoski @ gmail.com) + * Jackson-backed implementation for JSON encoding/decoding. */ -@SuppressWarnings({ "unchecked", "rawtypes" }) public class JSONTranscoder implements Transcoder { - public String getHandledFormat() { - return "json"; - } - - public String encode(Object object, String name, Map properties) { - return encode(object, name, properties, this.maxLevel); - } - - public String encode(Object object, String name, Map properties, int maxDepth) { -// Object data = object; -// String encoded = ""; -// if (object != null) { -// Map mapData = ReflectUtils.getInstance().map(object, 10, null, false, true, Transcoder.DATA_KEY); -// // for JSON we can get out the "data" field and convert that only -// if (mapData.size() == 1 && mapData.containsKey(Transcoder.DATA_KEY)) { -// data = mapData.get(Transcoder.DATA_KEY); -// } else { -// data = mapData; -// } -// } - // allow the transcoder to deal with the data directly, no need to convert it to a map first - String encoded = JSONTranscoder.makeJSON(object, properties, humanOutput, includeNulls, includeClassField, maxDepth, null); - return encoded; - } - - public Map decode(String string) { - Map decoded = null; - Object decode = new JsonReader().read(string); - if (decode instanceof Map) { - decoded = (Map) decode; - } else { - // for JSON if the result is not a map then simply put the result into a map - decoded = new ArrayOrderedMap(); - decoded.put(Transcoder.DATA_KEY, decode); - } - return decoded; - } - - /** - * Default constructor: - * See other constructors for options - */ - public JSONTranscoder() {} + private final ObjectMapper mapper; + private final boolean includeClassField; - private List encoders = null; - public void setEncoders(List encoders) { - this.encoders = encoders; - } - public List getEncoders() { - return encoders; - } - public void addEncoder(ObjectEncoder objectEncoder) { - if (this.encoders == null) { - this.encoders = new ArrayList(); - } - this.encoders.add(objectEncoder); + public JSONTranscoder() { + this(false, true, false); } - private boolean humanOutput = false; - private boolean includeNulls = true; - private boolean includeClassField = false; - /** - * @param humanOutput if true then enable human readable output (includes indentation and line breaks) - * @param includeNulls if true then create output tags for null values - * @param includeClassField if true then include the value from the "getClass()" method as "class" when encoding beans and maps - */ public JSONTranscoder(boolean humanOutput, boolean includeNulls, boolean includeClassField) { - this.humanOutput = humanOutput; - this.includeNulls = includeNulls; this.includeClassField = includeClassField; - } - - private int maxLevel = 7; - /** - * @param maxLevel the number of objects to follow when traveling through the object, - * 0 means only the fields in the initial object, default is 7 - */ - public void setMaxLevel(int maxLevel) { - this.maxLevel = maxLevel; - } - - - // Encoder - - public static final char OBJ_BEG = '{'; - public static final char OBJ_END = '}'; - public static final char OBJ_SEP = ':'; - public static final char ARRAY_BEG = '['; - public static final char ARRAY_END = ']'; - public static final char JSON_SEP = ','; - - // based on code from: http://www.json.org/java/org/json/XML.java - - public static final char SPACE = ' '; - public static final char AMP = '&'; - /** - * single quote (') - */ - public static final char APOS = '\''; - public static final char BANG = '!'; - public static final char BACK = '\\'; - public static final char EOL = '\n'; - public static final char EQ = '='; - public static final char GT = '>'; - public static final char LT = '<'; - public static final char QUEST = '?'; - public static final char QUOT = '"'; - public static final char SLASH = '/'; - - public static final String BOOLEAN_TRUE = "true"; - public static final String BOOLEAN_FALSE = "false"; - public static final String NULL = "null"; - - /** - * Convert an object into a well-formed, element-normal XML string. - * @param object any object - * @return the JSON string version of the object - */ - public static String makeJSON(Object object) { - return makeJSON(object, null, false, true, false, 10, null); - } - - /** - * Convert an object into a well-formed, element-normal XML string. - * @param object any object - * @param humanOutput true of human readable output - * @param includeNulls true to include null values when generating tags - * @param includeClassField if true then include the value from the "getClass()" method as "class" when encoding beans and maps - * @param maxLevel maximum level to traverse the objects before stopping - * @param encoders the external encoders to allow to process complex objects - * @return the JSON string version of the object - */ - public static String makeJSON(Object object, Map properties, boolean humanOutput, boolean includeNulls, boolean includeClassField, int maxLevel, List encoders) { - return toJSON(object, 0, maxLevel, humanOutput, includeNulls, includeClassField, properties, encoders); - } - - protected static String toJSON(Object object, int level, int maxLevel, boolean humanOutput, boolean includeNulls, boolean includeClassField, Map properties, List encoders) { - StringBuilder sb = new StringBuilder(); - - if (object == null) { - if (includeNulls) { - // nulls use the constant - sb.append(NULL); - } - } else { - Class type = ConstructorUtils.getWrapper(object.getClass()); - if ( ConstructorUtils.isClassSimple(type) ) { - // Simple (String, Number, etc.) - if (Date.class.isAssignableFrom(type) || Timestamp.class.isAssignableFrom(type)) { - // date - Date d = (Date) object; - sb.append(d.getTime()); - } else if (Number.class.isAssignableFrom(type)) { - // number - sb.append(object.toString()); - } else if (Boolean.class.isAssignableFrom(type)) { - // boolean - if ( ((Boolean)object).booleanValue() ) { - sb.append(BOOLEAN_TRUE); - } else { - sb.append(BOOLEAN_FALSE); - } - } else { - sb.append(QUOT); - sb.append( escapeForJSON(object.toString()) ); - sb.append(QUOT); - } - } else if ( ConstructorUtils.isClassArray(type) ) { - // ARRAY - int length = ArrayUtils.size((Object[])object); - sb.append(ARRAY_BEG); - if (length > 0) { - for (int i = 0; i < length; ++i) { - if (i > 0) { - sb.append(JSON_SEP); - } - makeEOL(sb, humanOutput); - makeLevelSpaces(sb, level+1, humanOutput); - sb.append( toJSON(Array.get(object, i), level+1, maxLevel, humanOutput, includeNulls, includeClassField, properties, encoders) ); - } - makeEOL(sb, humanOutput); - makeLevelSpaces(sb, level, humanOutput); - } - sb.append(ARRAY_END); - } else if ( ConstructorUtils.isClassCollection(type) ) { - // COLLECTION - Collection collection = (Collection) object; - sb.append(ARRAY_BEG); - if (! collection.isEmpty()) { - boolean first = true; - for (Object element : collection) { - if (first) { - first = false; - } else { - sb.append(JSON_SEP); - } - makeEOL(sb, humanOutput); - makeLevelSpaces(sb, level+1, humanOutput); - sb.append( toJSON(element, level+1, maxLevel, humanOutput, includeNulls, includeClassField, properties, encoders) ); - } - makeEOL(sb, humanOutput); - makeLevelSpaces(sb, level, humanOutput); - } - sb.append(ARRAY_END); - } else { - // must be a bean or map, make sure it is a map - // special handling for certain object types - String special = TranscoderUtils.handleObjectEncoding(object, encoders); - if (special != null) { - if ("".equals(special)) { - // skip this one entirely - sb.append(NULL); - } else { - // just use the value in special to represent this - sb.append(QUOT); - sb.append( escapeForJSON(special) ); - sb.append(QUOT); - } - } else { - // normal handling - if (maxLevel <= level) { - // if the max level was reached then stop - sb.append(QUOT); - sb.append( "MAX level reached (" ); - sb.append( level ); - sb.append( "):" ); - sb.append( escapeForJSON(object.toString()) ); - sb.append(QUOT); - } else { - Map map = null; - if (Map.class.isAssignableFrom(type)) { - map = (Map) object; - } else { - // reflect over objects - map = ReflectUtils.getInstance().getObjectValues(object, FieldsFilter.SERIALIZABLE, includeClassField); - } - // add in the optional properties if it makes sense to do so - if (level == 0 && properties != null && ! properties.isEmpty()) { - map.putAll(properties); - } - sb.append(OBJ_BEG); - boolean first = true; - for (Entry entry : map.entrySet()) { - if (entry.getKey() != null) { - Object value = entry.getValue(); - if (value != null || includeNulls) { - if (first) { - first = false; - } else { - sb.append(JSON_SEP); - } - makeEOL(sb, humanOutput); - makeLevelSpaces(sb, level+1, humanOutput); - sb.append(QUOT); - sb.append(entry.getKey()); - sb.append(QUOT); - sb.append(OBJ_SEP); - if (humanOutput) { sb.append(SPACE); } - sb.append( toJSON(value, level+1, maxLevel, humanOutput, includeNulls, includeClassField, properties, encoders) ); - } - } - } - makeEOL(sb, humanOutput); - makeLevelSpaces(sb, level, humanOutput); - sb.append(OBJ_END); - } - } - } + this.mapper = new ObjectMapper(); + if (humanOutput) { + this.mapper.enable(SerializationFeature.INDENT_OUTPUT); } - return sb.toString(); - } - - protected static void makeEOL(StringBuilder sb, boolean includeEOL) { - if (includeEOL) { - sb.append(EOL); + if (!includeNulls) { + this.mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); } } - protected static final String SPACES = " "; - protected static void makeLevelSpaces(StringBuilder sb, int level, boolean includeEOL) { - if (includeEOL) { - for (int i = 0; i < level; i++) { - sb.append(SPACES); - } - } + @Override + public String getHandledFormat() { + return "json"; } - /** - * Escape a string for JSON encoding - * @param string any string - * @return the escaped string - */ - public static String escapeForJSON(String string) { - StringBuilder sb = new StringBuilder(); - if (string != null) { - for (int i = 0, len = string.length(); i < len; i++) { - char c = string.charAt(i); - switch (c) { - case QUOT: - sb.append("\\\""); - break; - case BACK: - sb.append("\\\\"); - break; - case SLASH: - sb.append("\\/"); - break; - case '\b': - sb.append("\\b"); - break; - case '\f': - sb.append("\\f"); - break; - case '\n': - sb.append("\\n"); - break; - case '\r': - sb.append("\\r"); - break; - case '\t': - sb.append("\\t"); - break; - default: - if (Character.isISOControl(c)) { - sb.append("\\u"); - int n = c; - for (int j = 0; j < 4; ++j) { - int digit = (n & 0xf000) >> 12; - sb.append(hex[digit]); - n <<= 4; - } - } else { - sb.append(c); - } - } - } + @Override + public String encode(Object object, String name, Map properties) { + Objects.requireNonNull(object, "object cannot be null"); + try { + Object payload = buildPayload(object, name, properties); + return mapper.writeValueAsString(payload); + } catch (JsonProcessingException e) { + throw new IllegalArgumentException("Failed to encode object to JSON", e); } - return sb.toString(); } + private Object buildPayload(Object object, String name, Map properties) { + boolean hasName = name != null && !name.isEmpty(); + boolean hasProperties = properties != null && !properties.isEmpty(); - // STATICS - - private static final Object MARK_OBJECT_END = new Object(); - private static final Object MARK_ARRAY_END = new Object(); - private static final Object MARK_COLON = new Object(); - private static final Object MARK_COMMA = new Object(); - private static final Object MARK_END_INPUT = new Object(); - public static final int FIRST = 0; - public static final int CURRENT = 1; - public static final int NEXT = 2; - - private static Map escapes = new HashMap(); - static { - escapes.put(new Character('"'), new Character('"')); - escapes.put(new Character('\\'), new Character('\\')); - escapes.put(new Character('/'), new Character('/')); - escapes.put(new Character('b'), new Character('\b')); - escapes.put(new Character('f'), new Character('\f')); - escapes.put(new Character('n'), new Character('\n')); - escapes.put(new Character('r'), new Character('\r')); - escapes.put(new Character('t'), new Character('\t')); - } - - protected static char[] hex = "0123456789ABCDEF".toCharArray(); - - /** - * Create Java objects from JSON (note that only simple java objects, maps, and arrays will be returned)
- * Dates will come back in as UTC timecodes or possibly strings which you will need to parse manually
- * Numbers will come in as int if they are small, long if they are big, and BigInteger if they are huge, - * floating point is handled similarly: float, double, BigDecimal
- * JSON arrays come back as a List always, similarly, any collection or array that was output will come back as a list
- * You can use the {@link ConversionUtils} to help with conversion if needed
- * - * Derived from code at: - * https://svn.sourceforge.net/svnroot/stringtree/trunk/src/delivery/java/org/stringtree/json/JSONWriter.java - */ - public class JsonReader { - - private CharacterIterator it; // TODO crikey - thread safety - private char c; // TODO crikey - thread safety - private Object token; // TODO crikey - thread safety - private StringBuffer buf = new StringBuffer(); // TODO crikey - thread safety - - private char next() { - c = it.next(); - return c; - } - - private void skipWhiteSpace() { - while (Character.isWhitespace(c)) { - next(); - } - } - - public Object read(CharacterIterator it) { - return read(it, NEXT); + if (!hasName && !hasProperties && !includeClassField) { + return object; } - public Object read(String string) { - CharacterIterator ci = new StringCharacterIterator(string); - return read(ci, FIRST); + Map envelope = new LinkedHashMap<>(); + if (hasProperties) { + envelope.putAll(properties); } - - /** - * 3rd public input method, should mostly not be used directly - * Called ONLY by the other 2 read methods ({@link #read(String)} and {@link #read(CharacterIterator)}) - * @param ci - * @param start - * @return the Object which represents the JSON string, null for invalid - */ - public Object read(CharacterIterator ci, int start) { - it = ci; - switch (start) { - case FIRST: - c = it.first(); - break; - case CURRENT: - c = it.current(); - break; - case NEXT: - c = it.next(); - break; - } - Object o = read(); - if (MARK_END_INPUT.equals(o) || MARK_COLON.equals(o)) { - o = null; // SPECIAL cases - empty or invalid input - } - return o; - } - - private Object read() { - skipWhiteSpace(); - char ch = c; - next(); - switch (ch) { - case '"': token = string(); break; - case '[': token = array(); break; - case ']': token = MARK_ARRAY_END; break; - case ',': token = MARK_COMMA; break; - case '{': token = object(); break; - case '}': token = MARK_OBJECT_END; break; - case ':': token = MARK_COLON; break; - case 't': - next(); next(); next(); // assumed r-u-e - token = Boolean.TRUE; - break; - case'f': - next(); next(); next(); next(); // assumed a-l-s-e - token = Boolean.FALSE; - break; - case 'n': - next(); next(); next(); // assumed u-l-l - token = null; - break; - case StringCharacterIterator.DONE: - token = MARK_END_INPUT; - break; - default: - if (Character.isDigit(ch) || ch == '-') { - // Push this back on so it's part of the number - c = it.previous(); - token = number(); - } - } - // System.out.println("token: " + token); // enable this line to see the token stream - return token; - } - - private Object object() { - Map ret = new ArrayOrderedMap(); - Object key = read(); - while (token != MARK_OBJECT_END && token != MARK_END_INPUT) { - read(); // should be a colon - if (token != MARK_OBJECT_END) { - ret.put(key, read()); - if (read() == MARK_COMMA) { - key = read(); - } - } - } - if (MARK_END_INPUT.equals(token)) { - ret = null; // did not end the object in a valid way - } - return ret; - } - - private Object array() { - List ret = new ArrayList(); - Object value = read(); - while (token != MARK_ARRAY_END && token != MARK_END_INPUT) { - ret.add(value); - if (read() == MARK_COMMA) { - value = read(); - } - } - if (MARK_END_INPUT.equals(token)) { - ret = null; // did not end the array in a valid way - } - return ret; - } - - private Object number() { - int length = 0; - boolean isFloatingPoint = false; - buf.setLength(0); - - if (c == '-') { - add(); - } - length += addDigits(); - if (c == '.') { - add(); - length += addDigits(); - isFloatingPoint = true; - } - if (c == 'e' || c == 'E') { - add(); - if (c == '+' || c == '-') { - add(); - } - addDigits(); - isFloatingPoint = true; - } - - String s = buf.toString(); - // more friendly handling of numbers - Object num = null; - if (isFloatingPoint) { - if (length < 10) { - num = Float.valueOf(s); - } else if (length < 17) { - num = Double.valueOf(s); - } else { - num = new BigDecimal(s); - } - } else { - if (length < 10) { - num = Integer.valueOf(s); - } else if (length < 19) { - num = Long.valueOf(s); - } else { - num = new BigInteger(s); - } - } - return num; - } - - private int addDigits() { - int ret; - for (ret = 0; Character.isDigit(c); ++ret) { - add(); - } - return ret; + if (includeClassField && !(object instanceof Map)) { + envelope.put("class", object.getClass().getName()); } + String key = hasName ? name : DATA_KEY; + envelope.put(key, object); + return envelope; + } - private Object string() { - buf.setLength(0); - while (c != '"' && c != StringCharacterIterator.DONE) { - if (c == '\\') { - next(); - if (c == 'u') { - add(unicode()); - } else { - Object value = escapes.get(new Character(c)); - if (value != null) { - add(((Character) value).charValue()); - } - } - } else { - add(); - } + @Override + public Map decode(String string) { + Objects.requireNonNull(string, "string cannot be null"); + try { + JsonNode node = mapper.readTree(string); + if (node == null || node.isNull()) { + return new LinkedHashMap<>(); } - // unterminated string will terminate automatically - next(); - return buf.toString(); - } - - private void add(char cc) { - buf.append(cc); - next(); - } - - private void add() { - add(c); - } - - private char unicode() { - int value = 0; - for (int i = 0; i < 4; ++i) { - switch (next()) { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - value = (value << 4) + c - '0'; - break; - case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': - value = (value << 4) + (c - 'a') + 10; - break; - case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': - value = (value << 4) + (c - 'A') + 10; - break; - } + if (node.isObject()) { + return mapper.convertValue(node, new TypeReference>() {}); } - return (char) value; + Map result = new LinkedHashMap<>(); + result.put(DATA_KEY, mapper.convertValue(node, Object.class)); + return result; + } catch (IOException e) { + throw new IllegalArgumentException("Failed to decode JSON", e); } - } - } diff --git a/src/main/java/org/azeckoski/reflectutils/transcoders/Transcoder.java b/src/main/java/org/azeckoski/reflectutils/transcoders/Transcoder.java index ddb0736..3f57905 100644 --- a/src/main/java/org/azeckoski/reflectutils/transcoders/Transcoder.java +++ b/src/main/java/org/azeckoski/reflectutils/transcoders/Transcoder.java @@ -1,78 +1,21 @@ -/** - * $Id: Transcoder.java 81 2011-12-19 17:03:40Z azeckoski $ - * $URL: http://reflectutils.googlecode.com/svn/trunk/src/main/java/org/azeckoski/reflectutils/transcoders/Transcoder.java $ - * Transcoder.java - entity-broker - Sep 16, 2008 3:20:14 PM - azeckoski - ************************************************************************** - * Copyright (c) 2008 Aaron Zeckoski - * Licensed under the Apache License, Version 2.0 - * - * A copy of the Apache License has been included in this - * distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt - * - * Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk) - */ - package org.azeckoski.reflectutils.transcoders; import java.util.Map; -import org.azeckoski.reflectutils.ReflectUtils; - - /** - * The transcoder can convert from a java objects => a format => java objects (simple)
- * Note that conversion to simple objects is all that is generally supported, - * conversions to complex objects require use of the {@link ReflectUtils} to handle - * the conversion using {@link ReflectUtils#populate(Object, Map)} or {@link ReflectUtils#convert(Object, Class)} - *
- * The ability to append optional properties is also supported
- * The various transcoders will also have optional configuration parameters which should be controlled - * via the constructors.
- * Transcoders should be written to be created once and used many times without problems. - * - * @author Aaron Zeckoski (azeckoski @ gmail.com) + * Simple contract for encoding and decoding objects to formats such as JSON or XML. */ public interface Transcoder { - /** - * default map key to use if the output data is not actually a map but is a list or array or whatever - * when it is being decoded into a map - */ - public static final String DATA_KEY = "data"; + String DATA_KEY = "data"; - /** - * @return the handled format (xml, json, etc.) - */ - public String getHandledFormat(); + String getHandledFormat(); - /** - * @param object any java object (should not be null) - * @param name (optional) the name of the data, will be handled differently by the encoders (null for default: {@link #DATA_KEY}) - * @param properties (optional) additional properties which will be added to the encoding - * as if it were a property of the bean or map being encoded, if the object being encoded is not a bean - * or a map then the properties are ignored - * @return the object encoded into the handled format - */ - public String encode(Object object, String name, Map properties); - - /** - * @param object any java object (should not be null) - * @param name (optional) the name of the data, will be handled differently by the encoders (null for default: {@link #DATA_KEY}) - * @param properties (optional) additional properties which will be added to the encoding - * as if it were a property of the bean or map being encoded, if the object being encoded is not a bean - * or a map then the properties are ignored - * @param maxDepth the maximum traversal depth to use for this specific object - * @return the object encoded into the handled format - */ - public String encode(Object object, String name, Map properties, int maxDepth); + String encode(Object object, String name, Map properties); - /** - * Decode the data string into a map of java objects (typically simple objects like String, Integer, etc.) - * @param string a string in the handled format - * @return the map of java objects based on the data string, this will not attempt to convert XML into beans - * but will simply convert data into maps or lists or simple java objects (strings, etc.), if there - * is only a single simple value then it will be placed into the map with the key {@value #DATA_KEY} - */ - public Map decode(String string); + default String encode(Object object, String name, Map properties, int maxDepth) { + return encode(object, name, properties); + } + Map decode(String string); } diff --git a/src/main/java/org/azeckoski/reflectutils/transcoders/TranscoderUtils.java b/src/main/java/org/azeckoski/reflectutils/transcoders/TranscoderUtils.java deleted file mode 100644 index 33a23c9..0000000 --- a/src/main/java/org/azeckoski/reflectutils/transcoders/TranscoderUtils.java +++ /dev/null @@ -1,121 +0,0 @@ -/** - * $Id: TranscoderUtils.java 65 2010-04-05 14:53:55Z azeckoski $ - * $URL: http://reflectutils.googlecode.com/svn/trunk/src/main/java/org/azeckoski/reflectutils/transcoders/TranscoderUtils.java $ - * TranscoderUtils.java - reflectutils - Nov 12, 2008 4:17:30 PM - azeckoski - ************************************************************************** - * Copyright (c) 2008 Aaron Zeckoski - * Licensed under the Apache License, Version 2.0 - * - * A copy of the Apache License has been included in this - * distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt - * - * Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk) - */ - -package org.azeckoski.reflectutils.transcoders; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.Reader; -import java.io.Writer; -import java.lang.reflect.Type; -import java.util.List; - - -/** - * This allows for special handling which is shared between the transcoders - * - * @author Aaron Zeckoski (azeckoski @ gmail.com) - */ -public class TranscoderUtils { - - /** - * This will handle the encoding of special and user specific objects, - * this allows there to be added control over the way certain types of objects are encoded - * - * @param object - * @return a null if the current object is not special, an empty string to indicate the - * object should be skipped over with no output, and any string value to indicate the - * return value to use instead of attempting to encode the object - */ - public static String handleObjectEncoding(Object object, List encoders) { - String encoded = null; - if (encoders != null) { - for (ObjectEncoder encoder : encoders) { - try { - encoded = encoder.encodeObject(object); - } catch (Exception e) { - // nothing to do here but skip to the next one - encoded = null; - } - if (encoded != null) { - break; // break out of the loop because we are done - } - } - } - if (encoded == null) { - encoded = checkObjectSpecial(object); - } - return encoded; - } - - /** - * This will ensure that no objects that are known to be impossible to serialize properly will - * cause problems with the transcoders by allowing them to go into loops - * - * @param object - * @return a null if the current object is not special, an empty string to indicate the - * object should be skipped over with no output, and any string value to indicate the - * return value to use instead of attempting to encode the object - */ - public static String checkObjectSpecial(Object object) { - String special = null; - if (object != null) { - Class type = object.getClass(); - if (Class.class.isAssignableFrom(type)) { - // class objects are serialized as the full name - special = ((Class)object).getName(); - } else if (Type.class.isAssignableFrom(type)) { - // type just does to string - special = ((Type)object).toString(); - } else if (Package.class.isAssignableFrom(type)) { - // package uses name only - special = ((Package)object).getName(); - } else if (ClassLoader.class.isAssignableFrom(type)) { - // classloaders are skipped over entirely - special = ""; - } else if (InputStream.class.isAssignableFrom(type)) { - // skip IS - special = ""; - } else if (OutputStream.class.isAssignableFrom(type)) { - // skip OS - special = ""; - } else if (InputStream.class.isAssignableFrom(type)) { - // skip IS - special = ""; - } else if (Writer.class.isAssignableFrom(type)) { - // skip writer - special = ""; - } else if (Reader.class.isAssignableFrom(type)) { - // turn reader into string - Reader reader = ((Reader)object); - StringBuilder sb = new StringBuilder(); - try { - while (reader.ready()) { - int c = reader.read(); - if (c <= -1) { - break; - } - sb.append((char) c); - } - special = sb.toString(); - } catch (IOException e) { - special = "Could not read from Reader ("+reader.toString()+"): " + e.getMessage(); - } - } - } - return special; - } - -} diff --git a/src/main/java/org/azeckoski/reflectutils/transcoders/XMLTranscoder.java b/src/main/java/org/azeckoski/reflectutils/transcoders/XMLTranscoder.java index 626b17f..a5d6c85 100644 --- a/src/main/java/org/azeckoski/reflectutils/transcoders/XMLTranscoder.java +++ b/src/main/java/org/azeckoski/reflectutils/transcoders/XMLTranscoder.java @@ -1,1003 +1,136 @@ -/** - * $Id: XMLTranscoder.java 106 2012-02-09 21:12:51Z azeckoski $ - * $URL: http://reflectutils.googlecode.com/svn/trunk/src/main/java/org/azeckoski/reflectutils/transcoders/XMLTranscoder.java $ - * XMLEncoder.java - entity-broker - Sep 15, 2008 6:36:42 PM - azeckoski - ************************************************************************** - * Copyright (c) 2008 Aaron Zeckoski - * Licensed under the Apache License, Version 2.0 - * - * A copy of the Apache License has been included in this - * distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt - * - * Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk) - */ - package org.azeckoski.reflectutils.transcoders; -import java.io.ByteArrayInputStream; -import java.io.CharArrayWriter; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.SerializationFeature; + import java.io.IOException; -import java.lang.reflect.Array; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.sql.Timestamp; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.List; +import java.util.LinkedHashMap; import java.util.Map; -import java.util.Stack; -import java.util.Vector; -import java.util.Map.Entry; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - -import org.azeckoski.reflectutils.ArrayUtils; -import org.azeckoski.reflectutils.ConstructorUtils; -import org.azeckoski.reflectutils.DateUtils; -import org.azeckoski.reflectutils.FieldUtils; -import org.azeckoski.reflectutils.ReflectUtils; -import org.azeckoski.reflectutils.ClassFields.FieldsFilter; -import org.azeckoski.reflectutils.map.ArrayOrderedMap; - -import org.xml.sax.Attributes; -import org.xml.sax.SAXException; -import org.xml.sax.helpers.DefaultHandler; - +import java.util.Objects; /** - * Provides methods for encoding and decoding XML
- * Note that the XML parser always trashes the root node currently - * - * @author Aaron Zeckoski (azeckoski @ gmail.com) + * Jackson-backed implementation for XML encoding/decoding. */ -@SuppressWarnings({ "unchecked", "rawtypes" }) public class XMLTranscoder implements Transcoder { - private static final String ELEMENT = "element"; - - public String getHandledFormat() { - return "xml"; - } - - public String encode(Object object, String name, Map properties) { - return encode(object, name, properties, this.maxLevel); - } - - public String encode(Object object, String name, Map properties, int maxDepth) { - String encoded = ""; - if (object != null) { - // only set the name if this is not null to preserve the "null" tag - if (name == null || "".equals(name)) { - name = DATA_KEY; - } - } - encoded = XMLTranscoder.makeXML(object, name, properties, this.humanOutput, this.includeNulls, - this.includeClass, this.includeClassField, maxDepth, this.fixTags, this.encoders); - return encoded; - } + private final XmlMapper mapper; - public Map decode(String string) { -// Object decode = new XMLparser(string).getObject(); -// if (decode instanceof Map) { -// decoded = (Map) decode; -// } else { -// // if the result is not a map then simply put the result into a map -// decoded = new ArrayOrderedMap(); -// decoded.put(Transcoder.DATA_KEY, decode); -// } - return new XMLparser(string).getMap(); + public XMLTranscoder() { + this(false, true); } - /** - * Default constructor: - * See other constructors for options - */ - public XMLTranscoder() {} - - private List encoders = null; - public void setEncoders(List encoders) { - this.encoders = encoders; - } - public List getEncoders() { - return encoders; - } - public void addEncoder(ObjectEncoder objectEncoder) { - if (this.encoders == null) { - this.encoders = new ArrayList(); + public XMLTranscoder(boolean humanOutput, boolean includeNulls) { + this.mapper = new XmlMapper(); + if (humanOutput) { + this.mapper.enable(SerializationFeature.INDENT_OUTPUT); } - this.encoders.add(objectEncoder); - } - - private boolean humanOutput = false; - private boolean includeNulls = true; - private boolean includeClass = false; - private boolean includeClassField = false; - private boolean fixTags = true; - - /** - * @param humanOutput if true then enable human readable output (includes indentation and line breaks) - * @param includeNulls if true then create output tags for null values - * @param includeClassField if true then include the value from the "getClass()" method as "class" when encoding beans and maps - */ - public XMLTranscoder(boolean humanOutput, boolean includeNulls, boolean includeClassField) { - this.humanOutput = humanOutput; - this.includeNulls = includeNulls; - this.includeClassField = includeClassField; - } - - /** - * @param humanOutput if true then enable human readable output (includes indentation and line breaks) - * @param includeNulls if true then create output tags for null values - * @param includeClassField if true then include the value from the "getClass()" method as "class" when encoding beans and maps - * @param includeClass if true then add in class tips to the XML output - */ - public XMLTranscoder(boolean humanOutput, boolean includeNulls, boolean includeClassField, boolean includeClass) { - this.humanOutput = humanOutput; - this.includeNulls = includeNulls; - this.includeClassField = includeClassField; - this.includeClass = includeClass; - } - - private int maxLevel = 7; - /** - * @param maxLevel the number of objects to follow when traveling through the object, - * 0 means only the fields in the initial object, default is 7 - */ - public void setMaxLevel(int maxLevel) { - this.maxLevel = maxLevel; - } - - /** - * @param fixTags if true then fix up any invalid xml tag names, else just throw exception - */ - public void setFixTags(boolean fixTags) { - this.fixTags = fixTags; - } - - public boolean isHumanOutput() { - return humanOutput; - } - - public void setHumanOutput(boolean humanOutput) { - this.humanOutput = humanOutput; - } - - public boolean isIncludeNulls() { - return includeNulls; - } - - public void setIncludeNulls(boolean includeNulls) { - this.includeNulls = includeNulls; - } - - public boolean isIncludeClass() { - return includeClass; - } - - public void setIncludeClass(boolean includeClass) { - this.includeClass = includeClass; - } - - public boolean isIncludeClassField() { - return includeClassField; - } - - public void setIncludeClassField(boolean includeClassField) { - this.includeClassField = includeClassField; - } - - public boolean isFixTags() { - return fixTags; - } - - public int getMaxLevel() { - return maxLevel; - } - - - - // STATICS - - public static final char SPACE = ' '; - public static final char AMP = '&'; - /** - * single quote (') - */ - public static final char APOS = '\''; - public static final char BANG = '!'; - public static final char EQ = '='; - public static final char GT = '>'; - public static final char LT = '<'; - public static final char QUEST = '?'; - public static final char QUOT = '"'; - public static final char SLASH = '/'; - public static final char EOL = '\n'; - - - /** - * Convert an object into a well-formed, element-normal XML string. - * @param object any object - * @return the XML string version of the object - */ - public static String makeXML(Object object) { - return makeXML(object, null, null, false, true, false, false, 7, true, null); - } - - /** - * Convert an object into a well-formed, element-normal XML string. - * @param object any object - * @param tagName (optional) enclosing root tag - * @param properties (optional) optional properties to add into the encoded data - * @param humanOutput true of human readable output - * @param includeNulls true to include null values when generating tags - * @param maxLevel the maximum number of levels of objects to encode before stopping - * @return the XML string version of the object - */ - public static String makeXML(Object object, String tagName, Map properties, boolean humanOutput, boolean includeNulls, boolean includeClass, boolean includeClassField, int maxLevel, List encoders) { - return toXML(object, tagName, 0, maxLevel, humanOutput, includeNulls, includeClass, includeClassField, true, properties, encoders); - } - - /** - * Convert an object into a well-formed, element-normal XML string. - * @param object any object - * @param tagName (optional) enclosing root tag - * @param properties (optional) optional properties to add into the encoded data - * @param humanOutput true of human readable output - * @param includeNulls true to include null values when generating tags - * @param maxLevel the maximum number of levels of objects to encode before stopping - * @param fixTags fix up tag names (instead of throwing an exception) - * @return the XML string version of the object - */ - public static String makeXML(Object object, String tagName, Map properties, boolean humanOutput, boolean includeNulls, boolean includeClass, boolean includeClassField, int maxLevel, boolean fixTags, List encoders) { - return toXML(object, tagName, 0, maxLevel, humanOutput, includeNulls, includeClass, includeClassField, fixTags, properties, encoders); - } - - protected static String toXML(Object object, String tagName, int level, int maxLevel, boolean humanOutput, boolean includeNulls, boolean includeClass, boolean includeClassField, boolean fixTags, Map properties, List encoders) { - StringBuilder sb = new StringBuilder(); - - if (object == null) { - if (includeNulls) { - // nulls are empty tags always - tagName = validate(tagName == null ? "null" : tagName, fixTags); - makeLevelSpaces(sb, level, humanOutput); - sb.append(LT); - sb.append(tagName); - sb.append(SLASH); - sb.append(GT); - makeEOL(sb, humanOutput); - } - } else { - Class type = ConstructorUtils.getWrapper(object.getClass()); - if ( ConstructorUtils.isClassSimple(type) ) { - // Simple (String, Number, etc.) - tagName = validate(tagName == null ? makeElementName(type) : tagName, fixTags); - String value = ""; - makeLevelSpaces(sb, level, humanOutput); - sb.append(LT); - sb.append(tagName); - if (Date.class.isAssignableFrom(type) || Timestamp.class.isAssignableFrom(type)) { - // date - Date d = (Date) object; - value = d.getTime()+""; - sb.append(" type='date' date='"); - sb.append( DateUtils.makeDateISO8601(d) ); - sb.append(APOS); - } else if (Number.class.isAssignableFrom(type)) { - // number - sb.append(" type='number'"); - if (includeClass) { - makeClassName(sb, type); - } - value = object.toString(); - } else if (Boolean.class.isAssignableFrom(type)) { - // boolean - value = object.toString(); - sb.append(" type='boolean'"); - } else { - value = escapeForXML( object.toString() ); - } - sb.append(GT); - sb.append(value); - sb.append(LT); - sb.append(SLASH); - sb.append(tagName); - sb.append(GT); - makeEOL(sb, humanOutput); - } else if ( ConstructorUtils.isClassArray(type) ) { - // ARRAY - tagName = validate(tagName == null ? "array" : tagName, fixTags); - int length = ArrayUtils.size((Object[])object); - Class elementType = ArrayUtils.type((Object[])object); - makeLevelSpaces(sb, level, humanOutput); - sb.append(LT); - sb.append(tagName); - sb.append(" type='array' length='"); - sb.append(length); - sb.append(APOS); - if (includeClass) { - sb.append(" component='"); - sb.append( ConstructorUtils.getTypeFromInnerCollection(elementType).getName() ); - sb.append(APOS); - } - sb.append(GT); - makeEOL(sb, humanOutput); - for (int i = 0; i < length; ++i) { - sb.append( toXML(Array.get(object, i), makeElementName(elementType), level+1, maxLevel, humanOutput, includeNulls, includeClass, includeClassField, fixTags, properties, encoders) ); - } - makeLevelSpaces(sb, level, humanOutput); - sb.append(LT); - sb.append(SLASH); - sb.append(tagName); - sb.append(GT); - makeEOL(sb, humanOutput); - } else if ( ConstructorUtils.isClassCollection(type) ) { - // COLLECTION - tagName = validate(tagName == null ? "collection" : tagName, fixTags); - Collection collection = (Collection) object; - makeLevelSpaces(sb, level, humanOutput); - sb.append(LT); - sb.append(tagName); - sb.append(" type='collection' size='"); - sb.append(collection.size()); - sb.append(APOS); - if (includeClass) { - makeClassName(sb, ConstructorUtils.getTypeFromInnerCollection(type)); - } - sb.append(GT); - makeEOL(sb, humanOutput); - for (Object element : collection) { - Class elementType = null; - if (element != null) { - elementType = element.getClass(); - } - sb.append( toXML(element, makeElementName(elementType), level+1, maxLevel, humanOutput, includeNulls, includeClass, includeClassField, fixTags, properties, encoders) ); - } - makeLevelSpaces(sb, level, humanOutput); - sb.append(LT); - sb.append(SLASH); - sb.append(tagName); - sb.append(GT); - makeEOL(sb, humanOutput); - } else { - // must be a bean or map, make sure it is a map - tagName = validate(tagName == null ? makeElementName(type) : tagName, fixTags); - // special handling for certain object types - String special = TranscoderUtils.handleObjectEncoding(object, encoders); - if (special != null) { - if ("".equals(special)) { - // skip this one entirely - } else { - // just use the value in special to represent this - makeLevelSpaces(sb, level, humanOutput); - sb.append(LT); - sb.append(tagName); - sb.append(GT); - sb.append( escapeForXML(special) ); - sb.append(LT); - sb.append(SLASH); - sb.append(tagName); - sb.append(GT); - makeEOL(sb, humanOutput); - } - } else { - // normal handling - if (maxLevel <= level) { - // if the max level was reached then stop - sb.append(LT); - sb.append(tagName); - sb.append(GT); - sb.append( "MAX level reached (" ); - sb.append( level ); - sb.append( "):" ); - sb.append( escapeForXML(object.toString()) ); - sb.append(LT); - sb.append(SLASH); - sb.append(tagName); - sb.append(GT); - makeEOL(sb, humanOutput); - } else { - String xmlType = "bean"; - Map map = null; - if (Map.class.isAssignableFrom(type)) { - xmlType = "map"; - map = (Map) object; - } else { - // reflect over objects - map = ReflectUtils.getInstance().getObjectValues(object, FieldsFilter.SERIALIZABLE, false); - } - // add in the optional properties if it makes sense to do so - if (level == 0 && properties != null && ! properties.isEmpty()) { - map.putAll(properties); - } - makeLevelSpaces(sb, level, humanOutput); - sb.append(LT); - sb.append(tagName); - sb.append(" type='"); - sb.append(xmlType); - sb.append(APOS); - sb.append(" size='"); - sb.append(map.size()); - sb.append(APOS); - if (includeClass) { - makeClassName(sb, ConstructorUtils.getTypeFromInnerCollection(type)); - } - sb.append(GT); - makeEOL(sb, humanOutput); - for (Entry entry : map.entrySet()) { - if (entry.getKey() != null) { - sb.append( toXML(entry.getValue(), entry.getKey().toString(), level+1, maxLevel, humanOutput, includeNulls, includeClass, includeClassField, fixTags, properties, encoders) ); - } - } - makeLevelSpaces(sb, level, humanOutput); - sb.append(LT); - sb.append(SLASH); - sb.append(tagName); - sb.append(GT); - makeEOL(sb, humanOutput); - } - } - } + if (!includeNulls) { + this.mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); } - return sb.toString(); } - protected static String makeElementName(Class type) { - String name = ELEMENT; - if (type != null) { - if (Map.class.isAssignableFrom(type)) { - // use the default "element" - } else { - String simpleName = type.getSimpleName().toLowerCase(); - // strip off the [] for arrays - int index = simpleName.indexOf('['); - if (index == 0) { - // weird to have [] at the beginning so just use default - } else if (index > 0) { - name = simpleName.substring(0, index); - } else { - // not array so just use the class name - // TODO maybe handle this prettier with by adding in "-" and stuff? - name = simpleName; - } - } - } - return name; + @Override + public String getHandledFormat() { + return "xml"; } - protected static void makeClassName(StringBuilder sb, Class type) { - if (type != null) { - sb.append(" class='"); - sb.append( type.getName() ); - sb.append(APOS); + @Override + public String encode(Object object, String name, Map properties) { + Objects.requireNonNull(object, "object cannot be null"); + try { + Object payload = buildPayload(object, name, properties); + return mapper.writeValueAsString(payload); + } catch (JsonProcessingException e) { + throw new IllegalArgumentException("Failed to encode object to XML", e); } } - protected static void makeEOL(StringBuilder sb, boolean includeEOL) { - if (includeEOL) { - sb.append(EOL); - } - } + private Object buildPayload(Object object, String name, Map properties) { + boolean hasName = name != null && !name.isEmpty(); + boolean hasProperties = properties != null && !properties.isEmpty(); - protected static final String SPACES = " "; - protected static void makeLevelSpaces(StringBuilder sb, int level, boolean includeEOL) { - if (includeEOL) { - for (int i = 0; i < level; i++) { - sb.append(SPACES); - } + if (!hasName && !hasProperties) { + return object; } - } - /** - * Escape a string for XML encoding: replace special characters with XML escapes: - *
-     * & (ampersand) is replaced by &amp;
-     * < (less than) is replaced by &lt;
-     * > (greater than) is replaced by &gt;
-     * " (double quote) is replaced by &quot;
-     * 
- * @param string The string to be escaped. - * @return The escaped string. - */ - public static String escapeForXML(String string) { - StringBuilder sb = new StringBuilder(); - for (int i = 0, len = string.length(); i < len; i++) { - char c = string.charAt(i); - switch (c) { - case AMP: - sb.append("&"); - break; - case LT: - sb.append("<"); - break; - case GT: - sb.append(">"); - break; - case QUOT: - sb.append("""); - break; - default: - sb.append(c); - } + Map envelope = new LinkedHashMap<>(); + if (hasProperties) { + envelope.putAll(properties); } - return sb.toString(); + String key = hasName ? name : DATA_KEY; + envelope.put(key, object); + return envelope; } - /** - * Validates that a string is a valid tag or attribute name - * i.e. it contains no spaces and is non-null/non-empty - * Whitespace is not allowed in tagNames and attributes. - * - * XML elements must follow these naming rules: - * Names can contain letters, numbers, and other characters - * Names cannot start with a number or punctuation character (and a few others) - * Names cannot start with the letters xml (or XML, or Xml, etc) - * Names cannot contain spaces - * - * See http://www.w3.org/TR/REC-xml/#sec-common-syn - * Names beginning with the string "xml", or with any string which would match (('X'|'x') ('M'|'m') ('L'|'l')), - * are reserved for standardization in this or future versions of this specification. - * - * @param string any string - * @param correct if true then correct any errors found (if possible) - * @return the valid string - * @throws IllegalArgumentException if the string is invalid (and cannot be corrected) - */ - public static String validate(String string, boolean correct) { - if (string == null) { - throw new IllegalArgumentException("string is NULL"); - } - int i, length = string.length(); - if (length == 0) { - throw new IllegalArgumentException("Empty string."); - } - StringBuilder sb = new StringBuilder(); - for (i = 0; i < length; i += 1) { - char c = string.charAt(i); - if (i==0) { - // check for invalid start chars - if (!Character.isLetter(c) && '_' != c && ':' != c) { - // XML names MUST start with a letter OR _ or :, anything else is invalid - // technically: ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF] - if (correct) { - sb.append('_'); - } else { - throw new IllegalArgumentException("'" + string + "' starts with a non-letter ("+c+") which is also not an underscore (_) or colon (:)."); - } - continue; // skip ahead - } else if ('x' == c || 'X' == c) { - // XML names special case - cannot start with "xml" (in any case) - if (string.toLowerCase().startsWith("xml")) { - if (correct) { - sb.append('_'); - i += 2; // skip chars - } else { - throw new IllegalArgumentException("'" + string + "' starts with 'xml' or 'XML'."); - } - continue; // skip ahead - } - } + @Override + public Map decode(String string) { + Objects.requireNonNull(string, "string cannot be null"); + try { + JsonNode node = mapper.readTree(string); + if (node == null || node.isNull()) { + return new LinkedHashMap<>(); } - if (Character.isWhitespace(c)) { - if (correct) { - sb.append('_'); - } else { - throw new IllegalArgumentException("'" + string + "' contains a whitespace character."); - } - } else if (!Character.isLetterOrDigit(c) && ':' != c && '-' != c && '.' != c && '_' != c) { - // technically: ":" | [A-Z] | "_" | [a-z] | "-" | "." | [0-9] plus #xB7 | [#x0300-#x036F] | [#x203F-#x2040] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF] - // old check - if ('=' == c || '\'' == c || '\"' == c || '>' == c || '<' == c || '&' == c) - if (correct) { - sb.append('_'); - } else { - throw new IllegalArgumentException("'" + string + "' contains an illegal xml character ("+c+") such as (=,',\",>,<,&), valid chars are (A-Za-z0-9:._-)."); - } - } else { - sb.append(c); + if (node.isObject()) { + Map result = mapper.convertValue(node, new TypeReference>() {}); + return sanitize(result); } + Map result = new LinkedHashMap<>(); + result.put(DATA_KEY, mapper.convertValue(node, Object.class)); + return sanitize(result); + } catch (IOException e) { + throw new IllegalArgumentException("Failed to decode XML", e); } - return sb.toString(); } - - - // DECODER - - protected SAXParserFactory parserFactory = null; - protected SAXParser parser = null; - protected SAXParser getParser() { - if (parserFactory == null) { - parserFactory = SAXParserFactory.newInstance(); - parserFactory.setValidating(true); - parserFactory.setNamespaceAware(true); - } - if (parser != null) { - try { - parser.reset(); - } catch (UnsupportedOperationException e) { - // could not reset it so we have to make a new one - parser = null; - } - } - if (parser == null) { - try { - parser = parserFactory.newSAXParser(); - } catch (ParserConfigurationException e) { - throw new RuntimeException("Failed to get XML parser from factory: " + parserFactory, e); - } catch (SAXException e) { - throw new RuntimeException("Failed to get XML parser from factory: " + parserFactory, e); - } + @SuppressWarnings("unchecked") + private Map sanitize(Map source) { + Map result = new LinkedHashMap<>(); + for (Map.Entry entry : source.entrySet()) { + result.put(entry.getKey(), coerceValue(entry.getValue())); } - return parser; + return result; } - /** - * Use SAX to process the XML document - */ - public class XMLparser extends DefaultHandler { - private String xml = null; - private Map map = null; - public XMLparser(String xml) { - if (xml == null || "".equals(xml)) { - throw new IllegalArgumentException("xml cannot be null or empty"); - } - this.xml = xml; - this.map = new ArrayOrderedMap(); - containerStack.push( new Container(this.map) ); // init the holder stack (causes root node to be trashed) - parseXML(xml); - } - - /** - * @return the map which contains the data parsed out of the xml string - */ - public Map getMap() { - return map; + @SuppressWarnings("unchecked") + private Object coerceValue(Object value) { + if (value instanceof Map map) { + Map coerced = new LinkedHashMap<>(); + map.forEach((k, v) -> coerced.put(String.valueOf(k), coerceValue(v))); + return coerced; } - - protected void parseXML(String xml) { - try { - getParser().parse( new ByteArrayInputStream(xml.getBytes()), this ); - } catch (SAXException se) { - throw new IllegalArgumentException("Failed to parse xml ("+xml+"): " + se.getMessage(), se); - } catch (IOException ie) { - throw new RuntimeException("Failed to convert XML string ("+xml+") into inputstream", ie); + if (value instanceof Iterable iterable) { + java.util.List list = new java.util.ArrayList<>(); + for (Object item : iterable) { + list.add(coerceValue(item)); } + return list; } - - // handle the XML parsing - - /** - * Adds the value to the container using the given key, - * if the key already exists in the container then the container needs to be switched - * over to a collection and its contents moved, then the stack needs to be updated, - * and finally the parent container needs to have it's value replaced - */ - protected void add(Container container, String key, Object value) { - // first we need to make sure this container is on the stack -// if (containerStack.peek() != container) { -// containerStack.push( new Container(container.getContainer(), key, value) ); -// } - // now do the add - Class type = container.getContainer().getClass(); - if ( ConstructorUtils.isClassMap(type)) { - Map m = (Map)container.getContainer(); - if (m.containsKey(key)) { - // this should have been a collection so replace the map and move elements over to collection - Collection collection = (Collection) makeContainerObject(Types.COLLECTION); - for (Entry entry : m.entrySet()) { - collection.add( entry.getValue()); - } - collection.add(value); - // now replace the container in the stack - int endPosition = containerStack.size()-1; - int containerPosition = endPosition; - if (container != containerStack.peek() && containerPosition != 0) { - containerPosition--; - } - Container current = containerStack.get(containerPosition); - current.replaceContainer(collection); // update container and replace the value in the parent object in the container - // finally we need to get the next thing in the stack to point back at the new parent - if (containerPosition < endPosition) { - // there is another container on the stack which needs to be replaced - containerStack.set(endPosition, new Container(collection, 1, value) ); - } - } else { - m.put(key, value); - } - } else if ( ConstructorUtils.isClassCollection(type)) { - Collection collection = ((Collection)container.getContainer()); - collection.add(value); - // make sure the parent index is correct - if (container != containerStack.peek()) { - containerStack.peek().updateIndex(collection.size() - 1); - } - } else { - // bean or something we hope + if (value instanceof String s) { + if (s.matches("[-+]?\\d+")) { try { - ReflectUtils.getInstance().setFieldValue(container.getContainer(), key, value); - } catch (RuntimeException e) { - throw new RuntimeException("Unknown container type ("+type+") and could not set field on container: " + container, e); - } - } - } - - private Stack tagStack = new Stack(); - private Stack containerStack = new Stack(); - - private CharArrayWriter contents = new CharArrayWriter(); - private Types currentType = null; - // this should be false when there are no contents to read - private boolean currentContents = false; - - // Event Handlers - @Override - public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException { - contents.reset(); - tagStack.push(localName); - if (tagStack.size() > containerStack.size() + 1) { - // add a new container to the stack, use the types info from the parent - Container lastContainer = containerStack.peek(); - Object newContainerObject = makeContainerObject(currentType); - String parentName = ( tagStack.size() > 1 ? tagStack.get(tagStack.size()-2) : tagStack.peek() ); - containerStack.push( new Container(lastContainer.getContainer(), parentName, newContainerObject) ); - add(lastContainer, parentName, newContainerObject); - } - currentType = getDataType(attributes); - currentContents = false; - } - - @Override - public void endElement(String uri, String localName, String name) throws SAXException { - if (tagStack.size() > containerStack.size()) { - // only add data when we are above a container - Object val = null; - if (currentContents) { - String content = unescapeXML(contents.toString().trim()); - val = content; - if (Types.BOOLEAN.equals(currentType)) { - val = Boolean.valueOf(content); - } else if (Types.NUMBER.equals(currentType)) { - try { - val = number(content); - } catch (NumberFormatException e) { - val = content; - } - } else if (Types.DATE.equals(currentType)) { - try { - val = new Date(Long.valueOf(content)); - } catch (NumberFormatException e) { - val = content; - } + if (s.length() < 10) { + return Integer.valueOf(s); } + return Long.valueOf(s); + } catch (NumberFormatException ignored) { + // fall back to double below } - // put the value into the current container - add(containerStack.peek(), localName, val); - } - if (tagStack.isEmpty()) { - throw new IllegalStateException("tag stack is out of sync, empty while still processing tags: " + localName); - } else { - tagStack.pop(); - } - // now we need to remove the current container if we are done with it - while (tagStack.size() < containerStack.size()) { - if (containerStack.size() <= 1) break; - containerStack.pop(); - } - contents.reset(); - } - - @Override - public void characters(char[] ch, int start, int length) throws SAXException { - // get the text out of the element - contents.write(ch, start, length); - currentContents = true; - } - - @Override - public String toString() { - return "parser: " + xml + " => " + map; - } - } - - public static String unescapeXML(String string) { - if (string != null && string.length() > 0) { - string = string.replace("<","<").replace(">", ">").replace(""", "\"").replace("&", "&").replace("'","'"); - } - return string; - } - - /** - * This will force a tag or attribute to be valid in XML by replacing the invalid chars with "_", - * invalid chars are ' ' (space), =, ', ", >, <, & - * @param string any string - * @return a valid string - */ - public static String convertInvalidChars(String string) { - if (string != null && string.length() > 0) { - string = string.replace(' ','_').replace('=','_').replace('"','_').replace('\'','_').replace('<','_').replace('>','_').replace('&','_'); - } - return string; - } - - private static enum Types {STRING,NUMBER,BOOLEAN,DATE,ARRAY,COLLECTION,MAP,BEAN}; - - protected static Types getDataType(Attributes attributes) { - Types elementType = Types.STRING; - String value = attributes.getValue("", "type"); - if (value != null) { - if ("boolean".equals(value)) { - elementType = Types.BOOLEAN; - } else if ("number".equals(value)) { - elementType = Types.NUMBER; - } else if ("date".equals(value)) { - elementType = Types.DATE; - } else if ("array".equals(value)) { - elementType = Types.ARRAY; - } else if ("collection".equals(value)) { - elementType = Types.COLLECTION; - } else if ("map".equals(value)) { - elementType = Types.MAP; - } else if ("bean".equals(value)) { - elementType = Types.BEAN; - } - } - return elementType; - } - - protected static Class getDataClass(Attributes attributes) { - Class type = String.class; - String value = attributes.getValue("", "type"); - if (value != null) { - if (value.startsWith("class ")) { - value = value.substring(6); - } - // TODO handle the classes? - } - return type; - } - - protected static Object makeContainerObject(Types type) { - Object newContainer = null; - if (Types.ARRAY.equals(type) - || Types.COLLECTION.equals(type)) { - newContainer = new Vector(); - } else { - // bean, map, unknown - newContainer = new ArrayOrderedMap(); - } - return newContainer; - } - - /** - * Converts a string into a number - * @param s the string - * @return the number - * @throws NumberFormatException if the string is not a number - */ - @SuppressWarnings("fallthrough") - protected static Number number(String s) { - int length = s.length(); - boolean isFloatingPoint = false; - - for (int i = 0; i < s.length(); i++) { - char c = s.charAt(i); - switch (c) { - case '.': - case 'e': - case 'E': - isFloatingPoint = true; - case '-': - case '+': - length--; - } - } - - // more friendly handling of numbers - Number num = null; - if (isFloatingPoint) { - if (length < 10) { - num = Float.valueOf(s); - } else if (length < 17) { - num = Double.valueOf(s); - } else { - num = new BigDecimal(s); } - } else { - if (length < 10) { - num = Integer.valueOf(s); - } else if (length < 19) { - num = Long.valueOf(s); - } else { - num = new BigInteger(s); - } - } - return num; - } - - protected static class Container { - private boolean root = false; - public void setRoot(boolean root) { - this.root = root; - } - public boolean isRoot() { - return root; - } - public Object parent; - public Object getParent() { - return parent; - } - public String key; - public String getKey() { - return key; - } - public int index; - public int getIndex() { - return index; - } - public Object container; - public Object getContainer() { - return container; - } - public void updateIndex(int index) { - if (index < 0) { - throw new IllegalArgumentException("invalid index: " + index); - } - this.index = index; - key = null; - } - /** - * Replace the container with a new one based on the parent and settings in this Container - */ - public void replaceContainer(Object container) { - if (container == null) { - throw new IllegalArgumentException("No null params allowed"); - } - if (key != null) { - FieldUtils.getInstance().setFieldValue(parent, key, container); - } else if (index >= 0) { - FieldUtils.getInstance().setIndexedValue(parent, index, container); - } - // if not key or index then do nothing except replacing the value - this.container = container; - } - /** - * Use if parent is non-existent (i.e. this is the root) - */ - public Container(Object container) { - if (container == null) { - throw new IllegalArgumentException("No null params allowed"); - } - this.container = container; - this.root = true; - } - /** - * Use if parent is keyed - */ - public Container(Object parent, String key, Object container) { - if (parent == null || key == null || container == null) { - throw new IllegalArgumentException("No null params allowed"); + if (s.matches("[-+]?\\d*\\.\\d+")) { + try { + return Double.valueOf(s); + } catch (NumberFormatException ignored) { + return s; + } } - this.container = container; - this.key = key; - this.parent = parent; - } - /** - * Use if parent is indexed - */ - public Container(Object parent, int index, Object container) { - if (parent == null || index < 0 || container == null) { - throw new IllegalArgumentException("No null params or index < 0 allowed"); + if ("true".equalsIgnoreCase(s) || "false".equalsIgnoreCase(s)) { + return Boolean.valueOf(s); } - this.container = container; - this.index = index; - this.parent = parent; - } - @Override - public String toString() { - return "C:root="+root+":parent="+(parent==null?parent:parent.getClass().getSimpleName())+":key="+key+":index="+index+":container="+(container==null?container:container.getClass().getSimpleName()); } + return value; } - } diff --git a/src/main/java/org/azeckoski/reflectutils/transcoders/package.html b/src/main/java/org/azeckoski/reflectutils/transcoders/package.html deleted file mode 100644 index 3eb894e..0000000 --- a/src/main/java/org/azeckoski/reflectutils/transcoders/package.html +++ /dev/null @@ -1,5 +0,0 @@ - - -These transcoders (encoders/decoders) are used to convert java objects => JSON/XML => java objects - - \ No newline at end of file diff --git a/src/main/java/overview.html b/src/main/java/overview.html deleted file mode 100644 index cc0d13d..0000000 --- a/src/main/java/overview.html +++ /dev/null @@ -1,68 +0,0 @@ - - -
-

A set of reflection utilities and miscellaneous utilities related to working with classes and their fields with no dependencies which is compatible with java 1.5 and generics.

Features:

These are built to be compatible with Apache Commons BeanUtils and the nesting structure works the same, refer to the apache BeanUtils project docs for details. Support for Apache DynaClass / DynaBean is included. Current users of beanutils should be able to drop in these utilities and gain the functionality with minimal code changes.

Handles field operations for properties (getters and setters), partial properties (only getter or only setter), and fields. This is configurable to use the fields only, properties only, or the hybrid approach (default). This improves upon the BeanUtils limitation of handling only properties or the Google utilities limitation of handling only fields.

Getting and setting fields supports simple, nested, indexed, and mapped values

  • Simple: Get/set a field in a bean (or map), Example: "title", "id"
  • Nested: Get/set a field in a bean which is contained in another bean, Example: "someBean.title", "someBean.id"
  • Indexed: Get/set a list/array item by index in a bean, Example: "myList1", "anArray2"
  • Mapped: Get/set a map entry by key in a bean, Example: "myMap(key)", "someMap(thing)"

Includes support for dealing with annotations and working with fields which have annotations on them. Methods for finding fields with an annotation and finding all annotations in a class or on a fields are included.

Includes support for deep cloning, deep copying, and populating objects using auto-conversion. Also includes support for fuzzy copies where object data can be copied from one object to another without the objects being the same type.

Also includes an extendable conversion system for converting between java types. This system also handles conversions between arrays, maps, collections, enums, and scalars and improves upon the apache system by handling more types and handling object holders. Support for construction of any class and a set of utilities for determining what types of objects you are working with are also included. A method for executing a specific constructor can be used if more control if needed.

Includes transcoders (encoder/decoder) for conversion of class data to and from JSON and XML. The transcoders are clean and simple and work with any type of object. They will default to converting the incoming data into maps of simple java objects but these can be converted to the correct objects using the reflection utilities if desired.

The utilities cache reflection data for high performance operation but uses weak/soft caching to avoid holding open ClassLoaders and causing the caches to exist in memory permanently. The ability to override the caching mechanism with your own is supported.

The utilities are modular and are meant to be extendable and overridable. All methods are protected or public so that the various utility classes can be easily overridden if needed.


Sample code:

Examples operate on the class at the bottom (TestEntity). There are more samples in the guide.

TestEntity.class (comes directly from the test cases)

public class TestEntity {
-   private Long id = new Long(3);
-   private String entityId = "33";
-   \@TestAnnote
-   private String extra = null;
-   private Boolean bool = null;
-   private String[] sArray = {"1","2"};
-
-   public String getPrefix() {
-      return "crud";
-   }
-   public String createEntity(Object entity) {
-      return "1";
-   }
-   \@TestAnnote
-   public String getEntityId() {
-      return entityId;
-   }
-   public void setEntityId(String entityId) {
-      this.entityId = entityId;
-   }
-   public Long getId() {
-      return id;
-   }
-   public void setId(Long id) {
-      this.id = id;
-   }
-   \@TestAnnoteField1
-   public String getExtra() {
-      return extra;
-   }
-   \@TestAnnoteField2("TEST")
-   public void setExtra(String extra) {
-      this.extra = extra;
-   }
-   public String[] getSArray() {
-      return sArray;
-   }
-   public void setSArray(String[] array) {
-      sArray = array;
-   }
-   public Boolean getBool() {
-      return bool;
-   }
-   public void setBool(Boolean bool) {
-      this.bool = bool;
-   }
-}
-
-
- You are encouraged to look at the test cases (available in the source code) which illustrate uses of the utilities - far better than the documentation. -
- - \ No newline at end of file diff --git a/src/test/java/org/azeckoski/reflectutils/ArrayUtilsTest.java b/src/test/java/org/azeckoski/reflectutils/ArrayUtilsTest.java index b5a30fb..251ea7c 100644 --- a/src/test/java/org/azeckoski/reflectutils/ArrayUtilsTest.java +++ b/src/test/java/org/azeckoski/reflectutils/ArrayUtilsTest.java @@ -17,7 +17,9 @@ import java.util.ArrayList; import java.util.List; -import junit.framework.TestCase; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; /** * Tests the various methods used to analyze a class and cache the information @@ -25,11 +27,12 @@ * * @author Aaron Zeckoski (azeckoski@gmail.com) */ -public class ArrayUtilsTest extends TestCase { +public class ArrayUtilsTest { /** * Test method for {@link org.azeckoski.reflectutils.ArrayUtils#resize(T[], int)}. */ + @Test public void testResize() { String[] array = new String[] {"A","B","C","D"}; @@ -68,6 +71,7 @@ public void testResize() { /** * Test method for {@link org.azeckoski.reflectutils.ArrayUtils#removeDuplicates(java.util.List)}. */ + @Test public void testRemoveDuplicates() { List list = new ArrayList(); list.add("A"); diff --git a/src/test/java/org/azeckoski/reflectutils/ClassFieldsTest.java b/src/test/java/org/azeckoski/reflectutils/ClassFieldsTest.java index 3144e23..3e3e638 100644 --- a/src/test/java/org/azeckoski/reflectutils/ClassFieldsTest.java +++ b/src/test/java/org/azeckoski/reflectutils/ClassFieldsTest.java @@ -14,7 +14,9 @@ package org.azeckoski.reflectutils; -import junit.framework.TestCase; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; import org.azeckoski.reflectutils.ClassFields.FieldFindMode; import org.azeckoski.reflectutils.ClassFields.FieldsFilter; import org.azeckoski.reflectutils.annotations.*; @@ -38,11 +40,13 @@ * @author Aaron Zeckoski (azeckoski@gmail.com) */ @SuppressWarnings("unchecked") -public class ClassFieldsTest extends TestCase { +public class ClassFieldsTest { /** * Test method for {@link org.azeckoski.reflectutils.ClassFields#ClassFields(java.lang.Class, java.lang.reflect.Method[], java.lang.reflect.Method[], java.lang.reflect.Field[])}. */ + + @Test public void testClassFieldsClassOfQMethodArrayMethodArrayFieldArray() { ClassFields cf = null; @@ -95,6 +99,8 @@ public void testClassFieldsClassOfQMethodArrayMethodArrayFieldArray() { /** * Test method for {@link org.azeckoski.reflectutils.ClassFields#ClassFields(java.lang.Class, java.beans.PropertyDescriptor[], java.lang.reflect.Field[])}. */ + + @Test public void testClassFieldsClassOfQPropertyDescriptorArrayFieldArray() { ClassFields cf = null; @@ -143,6 +149,8 @@ public void testClassFieldsClassOfQPropertyDescriptorArrayFieldArray() { /** * Test method for {@link org.azeckoski.reflectutils.ClassFields#ClassFields(java.lang.Class, boolean)}. */ + + @Test public void testClassFieldsClassOfQBoolean() { ClassFields cf = null; @@ -169,6 +177,10 @@ public void testClassFieldsClassOfQBoolean() { } } + + @Test + + public void testClassFieldsModes() { ClassFields cf = null; @@ -270,6 +282,8 @@ public void testClassFieldsModes() { /** * Test method for {@link org.azeckoski.reflectutils.ClassFields#ClassFields(java.lang.Class)}. */ + + @Test public void testClassFieldsClassOfQ() { ClassFields cf = null; @@ -350,6 +364,8 @@ public void testClassFieldsClassOfQ() { /** * Test method for {@link org.azeckoski.reflectutils.ClassFields#getFieldClass()}. */ + + @Test public void testGetFieldClass() { ClassFields cf = null; @@ -384,6 +400,8 @@ public void testGetFieldClass() { /** * Test method for {@link org.azeckoski.reflectutils.ClassFields#getFieldNames()}. */ + + @Test public void testGetFieldNames() { ClassFields cf = null; List names = null; @@ -446,6 +464,8 @@ public void testGetFieldNames() { /** * Test method for {@link org.azeckoski.reflectutils.ClassFields#getAllFieldNames()}. */ + + @Test public void testGetAllFieldNames() { ClassFields cf = null; List names = null; @@ -494,6 +514,8 @@ public void testGetAllFieldNames() { /** * Test method for {@link org.azeckoski.reflectutils.ClassFields#getFieldTypes()}. */ + + @Test public void testGetFieldTypes() { ClassFields cf = null; Map> types = null; @@ -566,6 +588,8 @@ public void testGetFieldTypes() { /** * Test method for {@link org.azeckoski.reflectutils.ClassFields#getFieldTypes(FieldsFilter.WRITEABLE)}. */ + + @Test public void testGetAllSettableFieldTypes() { ClassFields cf = null; Map> types = null; @@ -644,6 +668,8 @@ public void testGetAllSettableFieldTypes() { /** * Test method for {@link org.azeckoski.reflectutils.ClassFields#getAllGettableFieldTypes()}. */ + + @Test public void testGetAllGettableFieldTypes() { ClassFields cf = null; Map> types = null; @@ -720,6 +746,10 @@ public void testGetAllGettableFieldTypes() { assertEquals(String.class, types.get("entityId")); } + + @Test + + public void testGetFieldTypesFilter() { ClassFields cf = null; Map> types = null; @@ -768,6 +798,8 @@ public void testGetFieldTypesFilter() { /** * Test method for {@link org.azeckoski.reflectutils.ClassFields#size()}. */ + + @Test public void testSize() { ClassFields cf = null; @@ -792,6 +824,10 @@ public void testSize() { assertEquals(6, cf.size()); } + + @Test + + public void testSizeFilter() { ClassFields cf = null; @@ -825,6 +861,8 @@ public void testSizeFilter() { /** * Test method for {@link org.azeckoski.reflectutils.ClassFields#isEmpty()}. */ + + @Test public void testIsEmpty() { ClassFields cf = null; @@ -849,6 +887,10 @@ public void testIsEmpty() { assertFalse(cf.isEmpty()); } + + @Test + + public void testIsEmptyFilter() { ClassFields cf = null; @@ -880,6 +922,8 @@ public void testIsEmptyFilter() { /** * Test method for {@link org.azeckoski.reflectutils.ClassFields#isFieldNameValid(java.lang.String)}. */ + + @Test public void testIsFieldNameValid() { ClassFields cf = null; @@ -959,6 +1003,8 @@ public void testIsFieldNameValid() { /** * Test method for {@link org.azeckoski.reflectutils.ClassFields#isFieldNameValid(java.lang.String)}. */ + + @Test public void testIsAnyFieldNameValid() { ClassFields cf = null; @@ -1038,6 +1084,8 @@ public void testIsAnyFieldNameValid() { /** * Test method for {@link org.azeckoski.reflectutils.ClassFields#getFieldType(java.lang.String)}. */ + + @Test public void testGetFieldType() { ClassFields cf = null; @@ -1071,6 +1119,8 @@ public void testGetFieldType() { /** * Test method for {@link org.azeckoski.reflectutils.ClassFields#getClassProperty(java.lang.String)}. */ + + @Test public void testGetFieldProperty() { ClassFields cf = null; ClassProperty cp = null; @@ -1237,6 +1287,10 @@ public void testGetFieldProperty() { } + + @Test + + public void testPartialComplete() { ClassFields cf = null; ClassProperty cp = null; @@ -1335,6 +1389,11 @@ public void testPartialComplete() { } + + @Test + + + public void testTransientFinal() { ClassFields cf = null; ClassProperty cp = null; @@ -1456,6 +1515,10 @@ public void testTransientFinal() { assertFalse( cp.isTransient() ); } + + @Test + + public void testGetAllClassProperties() { ClassFields cf = null; Map m = null; @@ -1488,6 +1551,8 @@ public void testGetAllClassProperties() { /** * Test method for {@link org.azeckoski.reflectutils.ClassFields#getClassAnnotations()}. */ + + @Test public void testGetClassAnnotations() { ClassFields cf = null; Set s = null; @@ -1536,6 +1601,8 @@ public void testGetClassAnnotations() { /** * Test getting a single annotation from a class by type */ + + @Test public void testGetClassAnnotation() { ClassFields cf = null; @@ -1567,6 +1634,8 @@ public void testGetClassAnnotation() { /** * Test method for {@link org.azeckoski.reflectutils.ClassFields#getFieldAnnotations(java.lang.String)}. */ + + @Test public void testGetFieldAnnotations() { ClassFields cf = null; Set s = null; @@ -1614,6 +1683,8 @@ public void testGetFieldAnnotations() { /** * Test method for {@link org.azeckoski.reflectutils.ClassFields#getFieldAnnotation(java.lang.Class, java.lang.String)}. */ + + @Test public void testGetFieldAnnotation() { ClassFields cf = null; @@ -1660,6 +1731,8 @@ public void testGetFieldAnnotation() { /** * Test method for {@link org.azeckoski.reflectutils.ClassFields#getFieldNameByAnnotation(java.lang.Class)}. */ + + @Test public void testGetFieldNameByAnnotation() { ClassFields cf = null; @@ -1690,6 +1763,8 @@ public void testGetFieldNameByAnnotation() { /** * Test method for {@link org.azeckoski.reflectutils.ClassFields#makeFieldNameFromMethod(java.lang.String)}. */ + + @Test public void testMakeFieldNameFromMethod() { String name = null; @@ -1712,6 +1787,8 @@ public void testMakeFieldNameFromMethod() { /** * Test method for {@link org.azeckoski.reflectutils.ClassFields#capitalize(java.lang.String)}. */ + + @Test public void testCapitalize() { assertTrue( ClassFields.capitalize("lower").equals("Lower") ); assertTrue( ClassFields.capitalize("UPPER").equals("UPPER") ); @@ -1724,6 +1801,8 @@ public void testCapitalize() { /** * Test method for {@link org.azeckoski.reflectutils.ClassFields#unCapitalize(java.lang.String)}. */ + + @Test public void testUnCapitalize() { assertTrue( ClassFields.unCapitalize("lower").equals("lower") ); assertTrue( ClassFields.unCapitalize("UPPER").equals("uPPER") ); @@ -1736,6 +1815,8 @@ public void testUnCapitalize() { /** * Test method for {@link org.azeckoski.reflectutils.ClassFields#isGetClassMethod(java.lang.reflect.Method)}. */ + + @Test public void testIsGetClassMethod() { Method m = null; @@ -1754,6 +1835,10 @@ public void testIsGetClassMethod() { } } + + @Test + + public void testExcludeFields() { ClassFields cf = null; @@ -1768,6 +1853,10 @@ public void testExcludeFields() { } + + @Test + + public void testExcludeStaticFields() { ClassFields cf = null; @@ -1783,6 +1872,10 @@ public void testExcludeStaticFields() { assertEquals(2, cf.getFieldNames().size()); } + + @Test + + public void testIncludeStaticFields() { ClassFields cf = null; diff --git a/src/test/java/org/azeckoski/reflectutils/ConstructorUtilsTest.java b/src/test/java/org/azeckoski/reflectutils/ConstructorUtilsTest.java index 92149dc..96e9de7 100644 --- a/src/test/java/org/azeckoski/reflectutils/ConstructorUtilsTest.java +++ b/src/test/java/org/azeckoski/reflectutils/ConstructorUtilsTest.java @@ -27,9 +27,12 @@ import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; -import java.util.Vector; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; -import junit.framework.TestCase; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; import org.azeckoski.reflectutils.classes.TestBean; import org.azeckoski.reflectutils.classes.TestExtendBean; @@ -37,7 +40,6 @@ import org.azeckoski.reflectutils.classes.TestNoPubConstructor; import org.azeckoski.reflectutils.classes.TestPea; import org.azeckoski.reflectutils.classes.TestUltraNested; -import org.azeckoski.reflectutils.map.ArrayOrderedMap; /** @@ -45,11 +47,13 @@ * * @author Aaron Zeckoski (azeckoski @ gmail.com) */ -public class ConstructorUtilsTest extends TestCase { +public class ConstructorUtilsTest { /** * Test method for {@link org.azeckoski.reflectutils.ConstructorUtils#isClassArray(java.lang.Class)}. */ + + @Test public void testIsClassArray() { assertFalse(ConstructorUtils.isClassArray(String.class)); assertFalse(ConstructorUtils.isClassArray(int.class)); @@ -64,6 +68,8 @@ public void testIsClassArray() { /** * Test method for {@link org.azeckoski.reflectutils.ConstructorUtils#isClassPrimitive(java.lang.Class)}. */ + + @Test public void testIsClassPrimitive() { assertFalse(ConstructorUtils.isClassPrimitive(String.class)); assertTrue(ConstructorUtils.isClassPrimitive(int.class)); @@ -78,6 +84,8 @@ public void testIsClassPrimitive() { /** * Test method for {@link org.azeckoski.reflectutils.ConstructorUtils#isClassList(java.lang.Class)}. */ + + @Test public void testIsClassList() { assertFalse(ConstructorUtils.isClassList(String.class)); assertFalse(ConstructorUtils.isClassList(int.class)); @@ -92,6 +100,8 @@ public void testIsClassList() { /** * Test method for {@link org.azeckoski.reflectutils.ConstructorUtils#isClassCollection(java.lang.Class)}. */ + + @Test public void testIsClassCollection() { assertFalse(ConstructorUtils.isClassCollection(String.class)); assertFalse(ConstructorUtils.isClassCollection(int.class)); @@ -106,6 +116,8 @@ public void testIsClassCollection() { /** * Test method for {@link org.azeckoski.reflectutils.ConstructorUtils#isClassMap(java.lang.Class)}. */ + + @Test public void testIsClassMap() { assertFalse(ConstructorUtils.isClassMap(String.class)); assertFalse(ConstructorUtils.isClassMap(int.class)); @@ -120,6 +132,8 @@ public void testIsClassMap() { /** * Test method for {@link org.azeckoski.reflectutils.ConstructorUtils#isClassObjectHolder(java.lang.Class)}. */ + + @Test public void testIsClassObjectHolder() { assertFalse(ConstructorUtils.isClassObjectHolder(String.class)); assertFalse(ConstructorUtils.isClassObjectHolder(int.class)); @@ -134,6 +148,8 @@ public void testIsClassObjectHolder() { /** * Test method for {@link org.azeckoski.reflectutils.ConstructorUtils#getTypeFromArray(java.lang.Class)}. */ + + @Test public void testGetTypeFromArray() { assertEquals(String.class, ConstructorUtils.getTypeFromArray(String[].class)); assertEquals(int.class, ConstructorUtils.getTypeFromArray(int[].class)); @@ -144,11 +160,13 @@ public void testGetTypeFromArray() { * Test method for {@link org.azeckoski.reflectutils.ConstructorUtils#getClassFromInterface(java.lang.Class)}. */ @SuppressWarnings("unchecked") + + @Test public void testGetClassFromInterface() { - assertEquals(Vector.class, ConstructorUtils.getClassFromInterface(List.class)); - assertEquals(HashSet.class, ConstructorUtils.getClassFromInterface(Set.class)); - assertEquals(ArrayOrderedMap.class, ConstructorUtils.getClassFromInterface(Map.class)); - assertEquals(Vector.class, ConstructorUtils.getClassFromInterface(Collection.class)); + assertEquals(ArrayList.class, ConstructorUtils.getClassFromInterface(List.class)); + assertEquals(LinkedHashSet.class, ConstructorUtils.getClassFromInterface(Set.class)); + assertEquals(LinkedHashMap.class, ConstructorUtils.getClassFromInterface(Map.class)); + assertEquals(ArrayList.class, ConstructorUtils.getClassFromInterface(Collection.class)); assertEquals(Long.class, ConstructorUtils.getClassFromInterface(Long.class)); assertEquals(Integer.class, ConstructorUtils.getClassFromInterface(Integer.class)); assertEquals(String.class, ConstructorUtils.getClassFromInterface(String.class)); @@ -156,11 +174,11 @@ public void testGetClassFromInterface() { assertEquals(int.class, ConstructorUtils.getClassFromInterface(int.class)); // test special cases - assertEquals(Vector.class, ConstructorUtils.getClassFromInterface(Arrays.asList(new ArrayList()).getClass())); - assertEquals(Vector.class, ConstructorUtils.getClassFromInterface(Collections.synchronizedCollection(new ArrayList()).getClass())); - assertEquals(Vector.class, ConstructorUtils.getClassFromInterface(Collections.synchronizedList(new ArrayList()).getClass())); - assertEquals(HashSet.class, ConstructorUtils.getClassFromInterface(Collections.synchronizedSet(new HashSet()).getClass())); - assertEquals(ArrayOrderedMap.class, ConstructorUtils.getClassFromInterface(Collections.synchronizedMap(new HashMap()).getClass())); + assertEquals(ArrayList.class, ConstructorUtils.getClassFromInterface(Arrays.asList(new ArrayList()).getClass())); + assertEquals(ArrayList.class, ConstructorUtils.getClassFromInterface(Collections.synchronizedCollection(new ArrayList()).getClass())); + assertEquals(ArrayList.class, ConstructorUtils.getClassFromInterface(Collections.synchronizedList(new ArrayList()).getClass())); + assertEquals(LinkedHashSet.class, ConstructorUtils.getClassFromInterface(Collections.synchronizedSet(new HashSet()).getClass())); + assertEquals(LinkedHashMap.class, ConstructorUtils.getClassFromInterface(Collections.synchronizedMap(new HashMap()).getClass())); assertEquals(TreeSet.class, ConstructorUtils.getClassFromInterface(Collections.synchronizedSortedSet(new TreeSet()).getClass())); assertEquals(TreeMap.class, ConstructorUtils.getClassFromInterface(Collections.synchronizedSortedMap(new TreeMap()).getClass())); } @@ -168,6 +186,8 @@ public void testGetClassFromInterface() { /** * Test method for {@link org.azeckoski.reflectutils.ConstructorUtils#getImmutableTypes()}. */ + + @Test public void testGetImmutableTypes() { Set> s = ConstructorUtils.getImmutableTypes(); assertNotNull(s); @@ -177,6 +197,8 @@ public void testGetImmutableTypes() { /** * Test method for {@link org.azeckoski.reflectutils.ConstructorUtils#getPrimitiveToWrapper()}. */ + + @Test public void testGetPrimitiveToWrapper() { Map, Class> m = ConstructorUtils.getPrimitiveToWrapper(); assertNotNull(m); @@ -186,6 +208,8 @@ public void testGetPrimitiveToWrapper() { /** * Test method for {@link org.azeckoski.reflectutils.ConstructorUtils#getPrimitiveDefaults()}. */ + + @Test public void testGetPrimitiveDefaults() { Map, Object> m = ConstructorUtils.getPrimitiveDefaults(); assertNotNull(m); @@ -195,6 +219,8 @@ public void testGetPrimitiveDefaults() { /** * Test method for {@link org.azeckoski.reflectutils.ConstructorUtils#isClassSimple(java.lang.Class)}. */ + + @Test public void testIsClassSimple() { assertTrue( ConstructorUtils.isClassSimple(int.class) ); assertTrue( ConstructorUtils.isClassSimple(String.class) ); @@ -210,6 +236,8 @@ public void testIsClassSimple() { /** * Test method for {@link org.azeckoski.reflectutils.ConstructorUtils#getWrapperToPrimitive()}. */ + + @Test public void testGetWrapperToPrimitive() { Map, Class> m = ConstructorUtils.getWrapperToPrimitive(); assertNotNull(m); @@ -219,6 +247,8 @@ public void testGetWrapperToPrimitive() { /** * Test method for {@link org.azeckoski.reflectutils.ConstructorUtils#getWrapper(java.lang.Class)}. */ + + @Test public void testGetWrapper() { assertEquals(Integer.class, ConstructorUtils.getWrapper(int.class)); assertEquals(Integer.class, ConstructorUtils.getWrapper(Integer.class)); @@ -233,6 +263,8 @@ public void testGetWrapper() { /** * Test method for {@link org.azeckoski.reflectutils.ConstructorUtils#classEquals(java.lang.Class, java.lang.Class)}. */ + + @Test public void testClassEquals() { assertTrue( ConstructorUtils.classEquals(int.class, int.class) ); assertTrue( ConstructorUtils.classEquals(Integer.class, Integer.class) ); @@ -260,6 +292,8 @@ public void testClassEquals() { /** * Test method for {@link org.azeckoski.reflectutils.ConstructorUtils#classAssignable(java.lang.Class, java.lang.Class)}. */ + + @Test public void testClassAssignable() { assertTrue( ConstructorUtils.classAssignable(int.class, int.class) ); assertTrue( ConstructorUtils.classAssignable(Integer.class, Integer.class) ); @@ -296,6 +330,8 @@ public void testClassAssignable() { * Test method for {@link org.azeckoski.reflectutils.ConstructorUtils#constructClass(java.lang.Class)}. */ @SuppressWarnings("unchecked") + + @Test public void testConstructClassClassOfT() { ConstructorUtils constructUtils = new ConstructorUtils(); @@ -363,6 +399,8 @@ public void testConstructClassClassOfT() { /** * Test method for {@link org.azeckoski.reflectutils.ConstructorUtils#constructClass(java.lang.Class, java.lang.Object[])}. */ + + @Test public void testConstructClassClassOfTObjectArray() { ConstructorUtils constructUtils = new ConstructorUtils(); @@ -389,6 +427,10 @@ public void testConstructClassClassOfTObjectArray() { } } + + @Test + + public void testConstructNoPublic() { ConstructorUtils constructUtils = new ConstructorUtils(); @@ -397,6 +439,10 @@ public void testConstructNoPublic() { assertEquals("prot", t1.getConstructed()); } + + @Test + + public void testSpecialCheck() { assertTrue( ConstructorUtils.isClassSpecial(Class.class) ); assertTrue( ConstructorUtils.isClassSpecial(ClassLoader.class) ); diff --git a/src/test/java/org/azeckoski/reflectutils/ConversionUtilsTest.java b/src/test/java/org/azeckoski/reflectutils/ConversionUtilsTest.java index 4e58063..a05cc38 100644 --- a/src/test/java/org/azeckoski/reflectutils/ConversionUtilsTest.java +++ b/src/test/java/org/azeckoski/reflectutils/ConversionUtilsTest.java @@ -18,6 +18,7 @@ import java.util.Calendar; import java.util.Date; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -25,9 +26,9 @@ import org.azeckoski.reflectutils.classes.TestBean; import org.azeckoski.reflectutils.classes.TestPea; -import org.azeckoski.reflectutils.map.ArrayOrderedMap; +import org.junit.jupiter.api.Test; -import junit.framework.TestCase; +import static org.junit.jupiter.api.Assertions.*; /** @@ -35,8 +36,9 @@ * * @author Aaron Zeckoski (azeckoski @ gmail.com) */ -public class ConversionUtilsTest extends TestCase { +public class ConversionUtilsTest { + @Test @SuppressWarnings("unchecked") public void testConvertObject() { ConversionUtils convertUtils = new ConversionUtils(); @@ -45,18 +47,18 @@ public void testConvertObject() { // equivalent conversion also should be instantaneous since no conversion happens assertEquals(123, (int) convertUtils.convert(123, int.class) ); - assertEquals(123, (int) convertUtils.convert(new Integer(123), int.class) ); + assertEquals(123, (int) convertUtils.convert(Integer.valueOf(123), int.class) ); assertEquals("123", convertUtils.convert("123", String.class) ); assertEquals(abc, convertUtils.convert(abc, String[].class) ); // object conversion should be instant - assertEquals(new Integer(123), (Integer) convertUtils.convert(123, Object.class) ); + assertEquals(Integer.valueOf(123), (Integer) convertUtils.convert(123, Object.class) ); assertEquals("123", convertUtils.convert("123", Object.class) ); // now do actual conversions assertEquals(123, (int) convertUtils.convert("123", int.class) ); assertEquals("123", convertUtils.convert("123", String.class) ); - assertEquals(new Integer(123), convertUtils.convert("123", Integer.class) ); + assertEquals(Integer.valueOf(123), convertUtils.convert("123", Integer.class) ); // array to scalar assertEquals(123, (int) convertUtils.convert(new int[] {123,456}, int.class) ); @@ -101,6 +103,7 @@ public void testConvertObject() { assertEquals(3, map.size()); } + @Test public void testStringToArray() { ConversionUtils convertUtils = new ConversionUtils(); @@ -124,6 +127,7 @@ public void testStringToArray() { } + @Test public void testConvertDates() { ConversionUtils convertUtils = new ConversionUtils(); @@ -142,6 +146,7 @@ public void testConvertDates() { assertEquals(calendar, convertUtils.convert("19751029", Calendar.class)); } + @Test public void testConvertToString() { ConversionUtils convertUtils = new ConversionUtils(); @@ -151,17 +156,19 @@ public void testConvertToString() { } + @Test public void testConvertString() { ConversionUtils convertUtils = new ConversionUtils(); assertEquals(3, convertUtils.convertString("3", int.class)); - assertEquals(new Integer(3), convertUtils.convertString("3", Integer.class)); + assertEquals(Integer.valueOf(3), convertUtils.convertString("3", Integer.class)); int[] intArray = (int[]) convertUtils.convertString("3", int[].class); assertEquals(3, intArray[0]); assertEquals("XXX", convertUtils.convertString("XXX", Integer.class)); } private enum TestEnum {ONE, TWO, THREE}; + @Test public void testConvertEnums() { ConversionUtils convertUtils = new ConversionUtils(); @@ -179,6 +186,7 @@ public void testConvertEnums() { } @SuppressWarnings("unchecked") + @Test public void testObjectToMap() { // simple conversion ConversionUtils convertUtils = new ConversionUtils(); @@ -197,6 +205,7 @@ public void testObjectToMap() { // simple conversion assertEquals("woot", m1.get("myString")); } + @Test public void testMapToObject() { // simple conversion ConversionUtils convertUtils = new ConversionUtils(); @@ -222,6 +231,7 @@ public void testMapToObject() { // simple conversion } @SuppressWarnings("unchecked") + @Test public void testConvertMaps() { ConversionUtils convertUtils = new ConversionUtils(); @@ -230,9 +240,10 @@ public void testConvertMaps() { sm.put("B", "BZ"); sm.put("C", "CZ"); - Map aom = convertUtils.convert(sm, ArrayOrderedMap.class); + Map aom = convertUtils.convert(sm, LinkedHashMap.class); assertNotNull(aom); - + assertEquals(3, aom.size()); + assertEquals("AZ", aom.get("A")); } } diff --git a/src/test/java/org/azeckoski/reflectutils/DeepUtilsTest.java b/src/test/java/org/azeckoski/reflectutils/DeepUtilsTest.java index 623fc3f..09ed155 100644 --- a/src/test/java/org/azeckoski/reflectutils/DeepUtilsTest.java +++ b/src/test/java/org/azeckoski/reflectutils/DeepUtilsTest.java @@ -19,11 +19,14 @@ import java.util.Date; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; -import junit.framework.TestCase; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; import org.azeckoski.reflectutils.classes.TestBean; import org.azeckoski.reflectutils.classes.TestCollections; @@ -33,18 +36,19 @@ import org.azeckoski.reflectutils.classes.TestNesting; import org.azeckoski.reflectutils.classes.TestPea; import org.azeckoski.reflectutils.classes.TestUltraNested; -import org.azeckoski.reflectutils.map.ArrayOrderedMap; /** * Testing the deep utils * * @author Aaron Zeckoski (azeckoski@gmail.com) */ -public class DeepUtilsTest extends TestCase { +public class DeepUtilsTest { /** * Test method for {@link org.sakaiproject.ReflectUtils.util.reflect.ReflectUtil#deepClone(java.lang.Object, int, java.lang.String[])}. */ + + @Test public void testClone() { DeepUtils deepUtils = new DeepUtils(); @@ -120,6 +124,8 @@ public void testClone() { /** * Test method for {@link org.sakaiproject.ReflectUtils.util.reflect.ReflectUtil#deepCopy(java.lang.Object, java.lang.Object, int, java.lang.String[], boolean)}. */ + + @Test public void testCopy() { DeepUtils deepUtils = new DeepUtils(); @@ -147,6 +153,10 @@ public void testCopy() { assertEquals(orig.getMyString(), dest.getMyString()); } + + @Test + + public void testSimpleCopy() { DeepUtils deepUtils = new DeepUtils(); @@ -187,6 +197,10 @@ public void testSimpleCopy() { assertEquals("C", array[2]); } + + @Test + + public void testPopulate() { DeepUtils deepUtils = new DeepUtils(); List results = null; @@ -232,7 +246,7 @@ public void testPopulate() { assertEquals("OLD,BLUE", target.getMyString()); // objects - properties.put("myInt", new Long(222)); + properties.put("myInt", Long.valueOf(222)); properties.put("myString", 55555); results = deepUtils.populate(target, properties); assertNotNull(results); @@ -242,6 +256,10 @@ public void testPopulate() { assertEquals("55555", target.getMyString()); } + + @Test + + public void testPopulateFromParams() { DeepUtils deepUtils = new DeepUtils(); List results = null; @@ -256,7 +274,7 @@ public void testPopulateFromParams() { assertNotNull(results); assertEquals(3, results.size()); assertNotNull(target); - assertEquals(new Long(1000), target.getId()); + assertEquals(Long.valueOf(1000), target.getId()); assertEquals("OLD", target.getExtra()); assertEquals("33", target.getEntityId()); assertEquals(null, target.getBool()); @@ -264,6 +282,10 @@ public void testPopulateFromParams() { } + + @Test + + public void testPopulateFromParamsDates() { DeepUtils deepUtils = new DeepUtils(); List results = null; @@ -292,6 +314,8 @@ public void testPopulateFromParamsDates() { } @SuppressWarnings("unchecked") + + @Test public void testObjectToMap() { DeepUtils deepUtils = new DeepUtils(); Map map = null; @@ -328,7 +352,7 @@ public void testObjectToMap() { // get non-null object data m = (Map) map.get("testEntity"); assertNotNull(m); - assertEquals(new Long(3), m.get("id")); + assertEquals(Long.valueOf(3), m.get("id")); assertEquals("33", m.get("entityId")); assertTrue(m.containsKey("extra")); assertEquals(null, m.get("extra")); // null @@ -368,7 +392,7 @@ public void testObjectToMap() { // get non-null object data m = (Map) map.get("testEntity"); assertNotNull(m); - assertEquals(new Long(3), m.get("id")); + assertEquals(Long.valueOf(3), m.get("id")); assertEquals("33", m.get("entityId")); assertFalse(m.containsKey("extra")); assertEquals(null, m.get("extra")); // null @@ -421,10 +445,14 @@ public void testObjectToMap() { assertEquals("AZ", map.get("data")); } + + @Test + + public void testPopulateFromNestedMap() { DeepUtils deepUtils = new DeepUtils(); - Map m = new ArrayOrderedMap(); + Map m = new LinkedHashMap(); m.put("A", "AZ"); m.put("id", "999"); m.put("entityId", "AZ"); @@ -441,7 +469,7 @@ public void testPopulateFromNestedMap() { m.put("myString", "string"); deepUtils.populate(tc, m); assertEquals("F1", tc.myField); - assertEquals(new Integer(123), tc.fieldInt); + assertEquals(Integer.valueOf(123), tc.fieldInt); assertEquals(234, tc.getMyInt()); assertEquals("string", tc.getMyString()); diff --git a/src/test/java/org/azeckoski/reflectutils/FieldUtilsTest.java b/src/test/java/org/azeckoski/reflectutils/FieldUtilsTest.java index 783c045..c76cb5f 100644 --- a/src/test/java/org/azeckoski/reflectutils/FieldUtilsTest.java +++ b/src/test/java/org/azeckoski/reflectutils/FieldUtilsTest.java @@ -14,7 +14,9 @@ package org.azeckoski.reflectutils; -import junit.framework.TestCase; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; import org.azeckoski.reflectutils.classes.*; import org.azeckoski.reflectutils.exceptions.FieldSetValueException; import org.azeckoski.reflectutils.exceptions.FieldnameNotFoundException; @@ -29,11 +31,13 @@ * * @author Aaron Zeckoski (azeckoski @ gmail.com) */ -public class FieldUtilsTest extends TestCase { +public class FieldUtilsTest { /** * Test method for {@link org.azeckoski.reflectutils.FieldUtils#analyzeClass(java.lang.Class)}. */ + + @Test public void testAnalyzeClass() { FieldUtils fu = new FieldUtils(); ClassFields cf; @@ -54,6 +58,8 @@ public void testAnalyzeClass() { /** * Test method for {@link org.azeckoski.reflectutils.FieldUtils#analyzeObject(java.lang.Object)}. */ + + @Test public void testAnalyzeObject() { FieldUtils fu = new FieldUtils(); ClassFields cf; @@ -74,6 +80,8 @@ public void testAnalyzeObject() { /** * Test method for {@link org.azeckoski.reflectutils.FieldUtils#getFieldNames(java.lang.Class)}. */ + + @Test public void testGetFieldNames() { FieldUtils fu = new FieldUtils(); List names; @@ -93,6 +101,8 @@ public void testGetFieldNames() { * Test method for findFieldValue */ @SuppressWarnings({"unchecked", "UnusedAssignment"}) + + @Test public void testFindFieldValue() { FieldUtils fu = new FieldUtils(); ClassFields cf; @@ -169,6 +179,8 @@ public void testFindFieldValue() { * Test method for assignFieldValue */ @SuppressWarnings("unchecked") + + @Test public void testAssignFieldValue() { FieldUtils fu = new FieldUtils(); ClassFields cf; @@ -237,6 +249,8 @@ public void testAssignFieldValue() { /** * Test method for getSimpleValue */ + + @Test public void testGetSimpleValue() { FieldUtils fu = new FieldUtils(); Object value; @@ -272,6 +286,8 @@ public void testGetSimpleValue() { * Test method for {@link org.azeckoski.reflectutils.FieldUtils#getIndexedValue(java.lang.Object, java.lang.String)}. */ @SuppressWarnings("UnusedAssignment") + + @Test public void testGetIndexedValue() { FieldUtils fu = new FieldUtils(); Object value; @@ -341,6 +357,8 @@ public void testGetIndexedValue() { * Test method for {@link org.azeckoski.reflectutils.FieldUtils#getMappedValue(java.lang.Object, java.lang.String)}. */ @SuppressWarnings("UnusedAssignment") + + @Test public void testGetMappedValue() { FieldUtils fu = new FieldUtils(); Object value; @@ -395,6 +413,8 @@ public void testGetMappedValue() { /** * Test method for {@link org.azeckoski.reflectutils.FieldUtils#getValueOfMap(java.util.Map, java.lang.String)}. */ + + @Test public void testGetValueOfMap() { FieldUtils fu = new FieldUtils(); Object value; @@ -419,6 +439,8 @@ public void testGetValueOfMap() { /** * Test method for {@link org.azeckoski.reflectutils.FieldUtils#setSimpleValue(java.lang.Object, java.lang.String, java.lang.Object)}. */ + + @Test public void testSetSimpleValue() { FieldUtils fu = new FieldUtils(); @@ -465,6 +487,8 @@ public void testSetSimpleValue() { /** * Test method for {@link org.azeckoski.reflectutils.FieldUtils#setIndexedValue(java.lang.Object, java.lang.String, java.lang.Object)}. */ + + @Test public void testSetIndexedValue() { FieldUtils fu = new FieldUtils(); @@ -515,6 +539,10 @@ public void testSetIndexedValue() { assertEquals("BBB", myList.get(1)); } + + @Test + + public void testCollections() { FieldUtils fu = new FieldUtils(); @@ -567,6 +595,8 @@ public void testCollections() { /** * Test method for {@link org.azeckoski.reflectutils.FieldUtils#setMappedValue(java.lang.Object, java.lang.String, java.lang.Object)}. */ + + @Test public void testSetMappedValue() { FieldUtils fu = new FieldUtils(); @@ -622,6 +652,8 @@ public void testSetMappedValue() { /** * Test method for {@link org.azeckoski.reflectutils.FieldUtils#setValueOfMap(java.util.Map, java.lang.String, java.lang.Object)}. */ + + @Test public void testSetValueOfMap() { FieldUtils fu = new FieldUtils(); @@ -646,6 +678,8 @@ public void testSetValueOfMap() { * Test method for {@link org.azeckoski.reflectutils.FieldUtils#getFieldValue(java.lang.Object, java.lang.String)}. */ @SuppressWarnings({"unchecked", "UnusedAssignment"}) + + @Test public void testGetFieldValue() { FieldUtils fu = new FieldUtils(); Object value; @@ -770,6 +804,10 @@ public void testGetFieldValue() { assertEquals(24, value); } + + @Test + + public void testGetFieldValueAsType() { FieldUtils fu = FieldUtils.getInstance(); Object value; @@ -805,6 +843,8 @@ public void testGetFieldValueAsType() { /** * Test method for {@link org.azeckoski.reflectutils.FieldUtils#setFieldValue(java.lang.Object, java.lang.String, java.lang.Object)}. */ + + @Test public void testSetFieldValue() { FieldUtils fu = new FieldUtils(); @@ -922,6 +962,10 @@ public void testSetFieldValue() { assertEquals("delta", myMap.get("D")); } + + @Test + + public void testSetNoConvert() { FieldUtils fu = new FieldUtils(); @@ -987,6 +1031,8 @@ public void testSetNoConvert() { /** * Test method for {@link org.azeckoski.reflectutils.FieldUtils#getFieldValues(java.lang.Object)}. */ + + @Test public void testGetFieldValues() { FieldUtils fu = new FieldUtils(); Map m; @@ -1118,6 +1164,10 @@ public void testGetFieldValues() { assertNotNull(m.get("testEntity")); } + + @Test + + public void testAutoCreateBeans() { FieldUtils fu = new FieldUtils(); @@ -1152,6 +1202,10 @@ public void testAutoCreateBeans() { assertEquals("AZ", fu.getFieldValue(tc, "map.user.name")); } + + @Test + + public void testNonVisibleFields() { FieldUtils fu = FieldUtils.getInstance(); Object value; diff --git a/src/test/java/org/azeckoski/reflectutils/ReflectUtilTest.java b/src/test/java/org/azeckoski/reflectutils/ReflectUtilTest.java index fe53f5c..864cc4f 100644 --- a/src/test/java/org/azeckoski/reflectutils/ReflectUtilTest.java +++ b/src/test/java/org/azeckoski/reflectutils/ReflectUtilTest.java @@ -14,7 +14,9 @@ package org.azeckoski.reflectutils; -import junit.framework.TestCase; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; import org.azeckoski.reflectutils.annotations.TestAnnote; import org.azeckoski.reflectutils.classes.*; import org.azeckoski.reflectutils.exceptions.FieldnameNotFoundException; @@ -29,12 +31,14 @@ * * @author Aaron Zeckoski (azeckoski@gmail.com) */ -public class ReflectUtilTest extends TestCase { +public class ReflectUtilTest { /** * Test method for {@link org.sakaiproject.ReflectUtils.util.reflect.ReflectUtil#getFieldValue(java.lang.Object, java.lang.String)}. */ @SuppressWarnings("unchecked") + + @Test public void testGetFieldValueObjectString() { ReflectUtils reflectUtil = new ReflectUtils(); Object value = null; @@ -47,7 +51,7 @@ public void testGetFieldValueObjectString() { value = reflectUtil.getFieldValue( thing, "id"); assertNotNull(value); - assertEquals(new Long(3), value); + assertEquals(Long.valueOf(3), value); TestNesting nested = new TestNesting(10, "100", new String[] {"A", "B"}); value = reflectUtil.getFieldValue( nested, "id"); @@ -56,7 +60,7 @@ public void testGetFieldValueObjectString() { value = reflectUtil.getFieldValue( nested, "testEntity.id"); assertNotNull(value); - assertEquals(new Long(3), value); + assertEquals(Long.valueOf(3), value); value = reflectUtil.getFieldValue( nested, "testBean"); assertNull(value); @@ -108,7 +112,7 @@ public void testGetFieldValueObjectString() { assertEquals(5, value); value = reflectUtil.getFieldValue(ultra, "testNesting.testEntity.id"); - assertEquals(new Long(3), value); + assertEquals(Long.valueOf(3), value); value = reflectUtil.getFieldValue(ultra, "testNesting.sList[0]"); assertEquals("A", value); @@ -137,6 +141,8 @@ public void testGetFieldValueObjectString() { /** * Test method for {@link org.azeckoski.reflectutils.ReflectUtils#getFieldValueAsString(java.lang.Object, java.lang.String, java.lang.Class)}. */ + + @Test public void testGetFieldValueAsString() { ReflectUtils reflectUtil = new ReflectUtils(); String value = null; @@ -167,6 +173,8 @@ public void testGetFieldValueAsString() { /** * Test method for {@link org.sakaiproject.ReflectUtils.util.reflect.ReflectUtil#setFieldValue(java.lang.Object, java.lang.String, java.lang.Object)}. */ + + @Test public void testSetFieldValue() { ReflectUtils reflectUtil = new ReflectUtils(); Object thing = null; @@ -256,8 +264,8 @@ public void testSetFieldValue() { reflectUtil.setFieldValue(ultra, "testNesting.id", 20); assertEquals(20, ultra.getTestNesting().getId()); - reflectUtil.setFieldValue(ultra, "testNesting.testEntity.id", new Long(6)); - assertEquals(new Long(6), ultra.getTestNesting().getTestEntity().getId()); + reflectUtil.setFieldValue(ultra, "testNesting.testEntity.id", Long.valueOf(6)); + assertEquals(Long.valueOf(6), ultra.getTestNesting().getTestEntity().getId()); reflectUtil.setFieldValue(ultra, "testNesting.sList[0]", "AAA"); assertEquals("AAA", ultra.getTestNesting().getSList().get(0)); @@ -280,6 +288,8 @@ public void testSetFieldValue() { /** * Test method for {@link org.sakaiproject.ReflectUtils.util.reflect.ReflectUtil#setFieldStringValue(java.lang.Object, java.lang.String, java.lang.String)}. */ + + @Test public void testSetFieldStringValue() { ReflectUtils reflectUtil = new ReflectUtils(); Object thing = null; @@ -294,7 +304,7 @@ public void testSetFieldStringValue() { thing = new TestEntity(); reflectUtil.setFieldValue(thing, "id", "6"); - assertEquals(new Long(6), ((TestEntity)thing).getId()); + assertEquals(Long.valueOf(6), ((TestEntity)thing).getId()); thing = new TestEntity(); reflectUtil.setFieldValue(thing, "sArray", "A, B, C"); @@ -304,21 +314,25 @@ public void testSetFieldStringValue() { assertEquals("C", ((TestEntity)thing).getSArray()[2]); } + + @Test + + public void testSetFieldValueWithConversion() { ReflectUtils reflectUtil = new ReflectUtils(); Object thing = null; thing = new TestEntity(); reflectUtil.setFieldValue(thing, "id", "10", true); - assertEquals(new Long(10), ((TestEntity)thing).getId()); + assertEquals(Long.valueOf(10), ((TestEntity)thing).getId()); thing = new TestEntity(); reflectUtil.setFieldValue(thing, "id", 10, true); - assertEquals(new Long(10), ((TestEntity)thing).getId()); + assertEquals(Long.valueOf(10), ((TestEntity)thing).getId()); thing = new TestEntity(); reflectUtil.setFieldValue(thing, "id", new String[] {"10"}, true); - assertEquals(new Long(10), ((TestEntity)thing).getId()); + assertEquals(Long.valueOf(10), ((TestEntity)thing).getId()); thing = new TestEntity(); reflectUtil.setFieldValue(thing, "bool", true, true); @@ -362,6 +376,8 @@ public void testSetFieldValueWithConversion() { * Test method for {@link org.azeckoski.reflectutils.ReflectUtils#constructClass(java.lang.Class)}. */ @SuppressWarnings("unchecked") + + @Test public void testConstructClass() { ReflectUtils reflectUtil = new ReflectUtils(); @@ -426,17 +442,23 @@ public void testConstructClass() { } } + + @Test + + public void testConvert() { ReflectUtils reflectUtil = new ReflectUtils(); assertEquals(123, (int) reflectUtil.convert("123", int.class) ); assertEquals("123", reflectUtil.convert("123", String.class) ); - assertEquals(new Integer(123), reflectUtil.convert("123", Integer.class) ); + assertEquals(Integer.valueOf(123), reflectUtil.convert("123", Integer.class) ); } /** * Test method for {@link org.azeckoski.reflectutils.ReflectUtils#pdNameCompare(java.lang.String, java.lang.String)}. */ + + @Test public void testPdNameCompare() { assertFalse( ReflectUtils.pdNameCompare(null, "") ); assertFalse( ReflectUtils.pdNameCompare("", "") ); @@ -452,6 +474,8 @@ public void testPdNameCompare() { /** * Test method for {@link org.sakaiproject.ReflectUtils.util.reflect.ReflectUtil#getFieldTypes()}. */ + + @Test public void testGetFieldTypes() { ReflectUtils reflectUtil = new ReflectUtils(); Map> types; @@ -466,6 +490,8 @@ public void testGetFieldTypes() { /** * Test method for {@link org.sakaiproject.ReflectUtils.util.reflect.ReflectUtil#getFieldType(java.lang.Class, java.lang.String)}. */ + + @Test public void testGetFieldType() { ReflectUtils reflectUtil = new ReflectUtils(); Class type; @@ -494,6 +520,8 @@ public void testGetFieldType() { /** * Test method for {@link org.sakaiproject.ReflectUtils.util.reflect.ReflectUtil#getObjectValues(java.lang.Object)}. */ + + @Test public void testGetObjectValues() { Map m = null; ReflectUtils reflectUtil = new ReflectUtils(); @@ -527,7 +555,7 @@ public void testGetObjectValues() { assertTrue(m.containsKey("sArray")); assertTrue(m.containsKey("bool")); assertTrue(m.containsKey("prefix")); - assertEquals(new Long(3), m.get("id")); + assertEquals(Long.valueOf(3), m.get("id")); assertEquals("33", m.get("entityId")); assertEquals(null, m.get("extra")); assertEquals("crud", m.get("prefix")); @@ -537,6 +565,8 @@ public void testGetObjectValues() { /** * Test method for {@link org.sakaiproject.ReflectUtils.util.reflect.ReflectUtil#getFieldNameWithAnnotation(java.lang.Class, java.lang.Class)}. */ + + @Test public void testGetFieldNameWithAnnotation() { ReflectUtils reflectUtil = new ReflectUtils(); String fieldName = null; @@ -551,6 +581,8 @@ public void testGetFieldNameWithAnnotation() { /** * Test method for {@link org.sakaiproject.ReflectUtils.util.reflect.ReflectUtil#getFieldValueAsString(java.lang.Object, java.lang.String, java.lang.Class)}. */ + + @Test public void testGetFieldValueObjectStringClassOfQextendsAnnotation() { String value = null; ReflectUtils reflectUtil = new ReflectUtils(); @@ -593,6 +625,8 @@ public void testGetFieldValueObjectStringClassOfQextendsAnnotation() { /** * Test method for {@link org.sakaiproject.ReflectUtils.util.reflect.ReflectUtil#deepClone(java.lang.Object, int, java.lang.String[])}. */ + + @Test public void testClone() { ReflectUtils reflectUtil = new ReflectUtils(); @@ -626,6 +660,8 @@ public void testClone() { /** * Test method for {@link org.sakaiproject.ReflectUtils.util.reflect.ReflectUtil#deepCopy(java.lang.Object, java.lang.Object, int, java.lang.String[], boolean)}. */ + + @Test public void testCopy() { ReflectUtils reflectUtil = new ReflectUtils(); @@ -653,6 +689,10 @@ public void testCopy() { assertEquals(orig.getMyString(), dest.getMyString()); } + + @Test + + public void testSimpleCopy() { ReflectUtils reflectUtil = new ReflectUtils(); @@ -693,6 +733,10 @@ public void testSimpleCopy() { assertEquals("C", array[2]); } + + @Test + + public void testPopulate() { ReflectUtils reflectUtil = new ReflectUtils(); List results = null; @@ -738,7 +782,7 @@ public void testPopulate() { assertEquals("OLD,BLUE", target.getMyString()); // objects - properties.put("myInt", new Long(222)); + properties.put("myInt", Long.valueOf(222)); properties.put("myString", 55555); results = reflectUtil.populate(target, properties); assertNotNull(results); @@ -748,6 +792,10 @@ public void testPopulate() { assertEquals("55555", target.getMyString()); } + + @Test + + public void testPopulateFromParams() { ReflectUtils reflectUtil = new ReflectUtils(); List results = null; @@ -762,7 +810,7 @@ public void testPopulateFromParams() { assertNotNull(results); assertEquals(3, results.size()); assertNotNull(target); - assertEquals(new Long(1000), target.getId()); + assertEquals(Long.valueOf(1000), target.getId()); assertEquals("OLD", target.getExtra()); assertEquals("33", target.getEntityId()); assertEquals(null, target.getBool()); @@ -770,6 +818,10 @@ public void testPopulateFromParams() { } + + @Test + + public void testPopulateFromParamsDates() { ReflectUtils reflectUtil = new ReflectUtils(); List results = null; @@ -800,6 +852,8 @@ public void testPopulateFromParamsDates() { /** * Test method for {@link org.sakaiproject.ReflectUtils.util.reflect.ReflectUtil#makeFieldNameFromMethod(java.lang.String)}. */ + + @Test public void testMakeFieldNameFromMethod() { String name = null; @@ -822,6 +876,8 @@ public void testMakeFieldNameFromMethod() { /** * Test method for {@link org.sakaiproject.ReflectUtils.util.reflect.ReflectUtil#getSuperclasses(java.lang.Class)}. */ + + @Test public void testGetSuperclasses() { List> superClasses = null; @@ -853,6 +909,8 @@ public void testGetSuperclasses() { * Test method for {@link org.sakaiproject.ReflectUtils.util.reflect.ReflectUtil#getClassFromCollection(java.util.Collection)}. */ @SuppressWarnings("unchecked") + + @Test public void testGetClassFromCollection() { Class result = null; @@ -876,13 +934,13 @@ public void testGetClassFromCollection() { assertEquals(String.class, result); HashSet s = new HashSet(); - s.add(new Double(22.0)); + s.add(Double.valueOf(22.0)); result = ReflectUtils.getClassFromCollection(s); assertNotNull(result); assertEquals(Double.class, result); - List v = new Vector(); - v.add( new Integer(30) ); + List v = new ArrayList(); + v.add( Integer.valueOf(30) ); result = ReflectUtils.getClassFromCollection(v); assertNotNull(result); assertEquals(Integer.class, result); @@ -891,6 +949,8 @@ public void testGetClassFromCollection() { /** * Test method for {@link org.sakaiproject.ReflectUtils.util.reflect.ReflectUtil#contains(T[], java.lang.Object)}. */ + + @Test public void testContains() { assertFalse( ReflectUtils.contains(new String[] {}, "stuff") ); assertFalse( ReflectUtils.contains(new String[] {"apple"}, "stuff") ); @@ -901,6 +961,8 @@ public void testContains() { /** * Test method for {@link org.sakaiproject.ReflectUtils.util.reflect.ReflectUtil#capitalize(java.lang.String)}. */ + + @Test public void testCapitalize() { assertTrue( ReflectUtils.capitalize("lower").equals("Lower") ); assertTrue( ReflectUtils.capitalize("UPPER").equals("UPPER") ); @@ -913,6 +975,8 @@ public void testCapitalize() { /** * Test method for {@link org.sakaiproject.ReflectUtils.util.reflect.ReflectUtil#unCapitalize(java.lang.String)}. */ + + @Test public void testUnCapitalize() { assertTrue( ReflectUtils.unCapitalize("lower").equals("lower") ); assertTrue( ReflectUtils.unCapitalize("UPPER").equals("uPPER") ); @@ -923,6 +987,8 @@ public void testUnCapitalize() { } @SuppressWarnings("unchecked") + + @Test public void testObjectToMap() { ReflectUtils reflectUtil = new ReflectUtils(); Map map = null; @@ -959,7 +1025,7 @@ public void testObjectToMap() { // get non-null object data m = (Map) map.get("testEntity"); assertNotNull(m); - assertEquals(new Long(3), m.get("id")); + assertEquals(Long.valueOf(3), m.get("id")); assertEquals("33", m.get("entityId")); assertTrue(m.containsKey("extra")); assertEquals(null, m.get("extra")); // null @@ -999,7 +1065,7 @@ public void testObjectToMap() { // get non-null object data m = (Map) map.get("testEntity"); assertNotNull(m); - assertEquals(new Long(3), m.get("id")); + assertEquals(Long.valueOf(3), m.get("id")); assertEquals("33", m.get("entityId")); assertFalse(m.containsKey("extra")); assertEquals(null, m.get("extra")); // null diff --git a/src/test/java/org/azeckoski/reflectutils/TranscodersTest.java b/src/test/java/org/azeckoski/reflectutils/TranscodersTest.java index 5462eaa..aac4e5c 100644 --- a/src/test/java/org/azeckoski/reflectutils/TranscodersTest.java +++ b/src/test/java/org/azeckoski/reflectutils/TranscodersTest.java @@ -1,1423 +1,68 @@ -/** - * $Id: TranscodersTest.java 110 2013-05-03 13:30:13Z azeckoski $ - * $URL: http://reflectutils.googlecode.com/svn/trunk/src/test/java/org/azeckoski/reflectutils/TranscodersTest.java $ - * TranscodersTest.java - genericdao - Sep 16, 2008 11:20:27 PM - azeckoski - ************************************************************************** - * Copyright (c) 2008 Aaron Zeckoski - * Licensed under the Apache License, Version 2.0 - * - * A copy of the Apache License has been included in this - * distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt - * - * Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk) - */ - package org.azeckoski.reflectutils; -import java.sql.Timestamp; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.Random; - -import junit.framework.TestCase; - -import org.azeckoski.reflectutils.classes.TestBaseOne; -import org.azeckoski.reflectutils.classes.TestBean; -import org.azeckoski.reflectutils.classes.TestCompound; -import org.azeckoski.reflectutils.classes.TestHibernateLikeBean; -import org.azeckoski.reflectutils.classes.TestNesting; -import org.azeckoski.reflectutils.classes.TestPea; -import org.azeckoski.reflectutils.classes.TestUltraNested; -import org.azeckoski.reflectutils.map.ArrayOrderedMap; -import org.azeckoski.reflectutils.transcoders.HTMLTranscoder; import org.azeckoski.reflectutils.transcoders.JSONTranscoder; -import org.azeckoski.reflectutils.transcoders.JSONTranscoder.JsonReader; import org.azeckoski.reflectutils.transcoders.Transcoder; import org.azeckoski.reflectutils.transcoders.XMLTranscoder; +import org.junit.jupiter.api.Test; +import java.util.LinkedHashMap; +import java.util.Map; -/** - * Testing the transcoders - * - * @author Aaron Zeckoski (azeckoski @ gmail.com) - */ -public class TranscodersTest extends TestCase { - - // testing the internal encoder - public void testJSONEncode() { - Transcoder transcoder = new JSONTranscoder(true, true, false); - String encoded = null; - - // test simple cases - encoded = transcoder.encode(null, null, null); - assertNotNull(encoded); - assertEquals("null", encoded); // json - - encoded = transcoder.encode("AaronZ", null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("AaronZ")); - - encoded = transcoder.encode(1234, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("1234")); - - encoded = transcoder.encode(true, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("true")); - - // test arrays - TestBean[] array = new TestBean[0]; - encoded = transcoder.encode(array, null, null); - assertNotNull(encoded); - assertEquals("[]", encoded); //json - - array = new TestBean[] {new TestBean(888), new TestBean(777)}; - encoded = transcoder.encode(array, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("888")); - assertTrue(encoded.contains("777")); - - // test collections - List list = new ArrayList(); - encoded = transcoder.encode(list, null, null); - assertNotNull(encoded); - assertEquals("[]", encoded); //json - - list.add( new TestPea("AZ","AaronZ")); - list.add( new TestPea("BZ","BeckyZ")); - encoded = transcoder.encode(list, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("AZ")); - assertTrue(encoded.contains("AaronZ")); - assertTrue(encoded.contains("BZ")); - assertTrue(encoded.contains("BeckyZ")); - - // test maps - Map m = new ArrayOrderedMap(); - m.put("id", 123); - m.put("thing", "AZ"); - encoded = transcoder.encode(m, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("123")); - assertTrue(encoded.contains("AZ")); - - Map m2 = new ArrayOrderedMap(); - m2.put("name", "aaron"); - m2.put("num", 456); - m2.put("array", new String[] {"A","B","C"}); - m.put("map", m2); - m.put("date", new Date(1255129200000l)); - m.put("timestamp", new Timestamp(1255129200000l)); - //m.put("calendar", new GregorianCalendar(2009,9,10)); - - encoded = transcoder.encode(m, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("123")); - assertTrue(encoded.contains("AZ")); - assertTrue(encoded.contains("aaron")); - assertTrue(encoded.contains("456")); - - m.put("az", new TestBean()); - m.put("bz", new TestPea()); - m.put("oList", list); - m.put("oArray", array); - encoded = transcoder.encode(m, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("123")); - assertTrue(encoded.contains("AZ")); - assertTrue(encoded.contains("aaron")); - assertTrue(encoded.contains("456")); - assertTrue(encoded.contains("az")); - assertTrue(encoded.contains("bz")); - assertTrue(encoded.contains("AaronZ")); - assertTrue(encoded.contains("BeckyZ")); - assertTrue(encoded.contains("888")); - assertTrue(encoded.contains("777")); - - // test beans - TestCompound tc = new TestCompound(); - encoded = transcoder.encode(tc, "az-root", null); - assertNotNull(encoded); -// assertTrue(encoded.contains("az-root")); - assertTrue(encoded.contains("fieldInt")); - assertTrue(encoded.contains("5")); - assertTrue(encoded.contains("myInt")); - assertTrue(encoded.contains("8")); - assertTrue(encoded.contains("myField")); - assertTrue(encoded.contains("myString")); - - // test excluding nulls - Transcoder transcoder2 = new JSONTranscoder(false, false, false); - encoded = transcoder2.encode(tc, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("fieldInt")); - assertTrue(encoded.contains("5")); - assertTrue(encoded.contains("myInt")); - assertTrue(encoded.contains("8")); - assertTrue(! encoded.contains("myField")); - assertTrue(! encoded.contains("myString")); - - TestUltraNested tun = new TestUltraNested("aztitle", new TestNesting(999, "bztitle", new String[] {"ZZ","YY","XX"}) ); - encoded = transcoder.encode(tun, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("aztitle")); - assertTrue(encoded.contains("testNesting")); - assertTrue(encoded.contains("sMap")); - assertTrue(encoded.contains("B2")); - assertTrue(encoded.contains("TWO")); - assertTrue(encoded.contains("testEntity")); - assertTrue(encoded.contains("prefix")); - assertTrue(encoded.contains("crud")); - assertTrue(encoded.contains("sArray")); - assertTrue(encoded.contains("entityId")); - assertTrue(encoded.contains("sList")); - assertTrue(encoded.contains("myArray")); - assertTrue(encoded.contains("extra")); - assertTrue(encoded.contains("testPea")); - assertTrue(encoded.contains("testBean")); - assertTrue(encoded.contains("999")); - assertTrue(encoded.contains("bztitle")); - assertTrue(encoded.contains("ZZ")); - - } - - public void testJSONEncodeInvalid() { - JSONTranscoder transcoder = new JSONTranscoder(); - JsonReader reader = transcoder.new JsonReader(); - Map map; - Object read; - - // invalid (becomes null) - read = reader.read(""); - assertNull(read); - read = reader.read(" "); - assertNull(read); - read = reader.read(":"); - assertNull(read); - read = reader.read("{"); - assertNull(read); - read = reader.read("["); - assertNull(read); - read = reader.read("{\"nonterminating string}"); - assertNull(read); - read = reader.read("{{{{"); - assertNull(read); - - // empty - read = reader.read("{ }"); - assertNotNull(read); - assertTrue(read instanceof Map); - - read = reader.read("{ \"key\" : \"string\" }"); - assertNotNull(read); - assertTrue(read instanceof Map); - map = (Map) read; - assertEquals(1, map.size()); - - map = (Map) reader.read("{ \"number\": 12345 }"); - assertEquals(12345, map.get("number")); - - map = (Map) reader.read("{ \"number\": -1.212345 }"); - // I think this should be a double really according to the JSON spec - assertEquals(-1.212345f, map.get("number")); - - map = (Map) reader.read("{ \"object\": { \"key\": 5} }"); - assertEquals(5, ((Map) map.get("object")).get("key")); - - map = (Map) reader.read("{ \"key1\": 1, \"key2\": 2 }"); - assertEquals(1, map.get("key1")); - assertEquals(2, map.get("key2")); - - List list = (List) reader.read("[ 0,1,2,3,4,5 ]"); - assertEquals(1, list.get(1)); - assertEquals(5, list.get(5)); - - String rnd = generateString(new Random(), - "abcdefghijklmnopqrstuvwxyz012344567789{}[]'\";;&<>\\!?", - 10000000); - reader.read(rnd); - } - - public static String generateString(Random rng, String characters, - int length) { - char[] text = new char[length]; - for (int i = 0; i < length; i++) { - text[i] = characters.charAt(rng.nextInt(characters.length())); - } - return new String(text); - } - - public void testJSONEncodeProperties() { - Transcoder transcoder = new JSONTranscoder(true, true, false); - String encoded = null; - - Map properties = new ArrayOrderedMap(); - properties.put("prop1", 999999); - properties.put("prop2", "Zeckoski"); - properties.put("prop3", new TestPea("AZ","azeckoski")); - properties.put("prop4", null); - - // test simple cases (ignored) - encoded = transcoder.encode(null, null, properties); - assertNotNull(encoded); - assertEquals("null", encoded); // json - assertFalse(encoded.contains("999999")); - assertFalse(encoded.contains("Zeckoski")); - assertFalse(encoded.contains("azeckoski")); - - encoded = transcoder.encode("AaronZ", null, properties); - assertNotNull(encoded); - assertTrue(encoded.contains("AaronZ")); - assertFalse(encoded.contains("999999")); - assertFalse(encoded.contains("Zeckoski")); - assertFalse(encoded.contains("azeckoski")); - - encoded = transcoder.encode(1234, null, properties); - assertNotNull(encoded); - assertTrue(encoded.contains("1234")); - assertFalse(encoded.contains("999999")); - assertFalse(encoded.contains("Zeckoski")); - assertFalse(encoded.contains("azeckoski")); - - encoded = transcoder.encode(true, null, properties); - assertNotNull(encoded); - assertTrue(encoded.contains("true")); - assertFalse(encoded.contains("999999")); - assertFalse(encoded.contains("Zeckoski")); - assertFalse(encoded.contains("azeckoski")); - - // test arrays - TestBean[] array = new TestBean[0]; - encoded = transcoder.encode(array, null, properties); - assertNotNull(encoded); - assertEquals("[]", encoded); //json - assertFalse(encoded.contains("999999")); - assertFalse(encoded.contains("Zeckoski")); - assertFalse(encoded.contains("azeckoski")); - - array = new TestBean[] {new TestBean(888), new TestBean(777)}; - encoded = transcoder.encode(array, null, properties); - assertNotNull(encoded); - assertTrue(encoded.contains("888")); - assertTrue(encoded.contains("777")); - assertFalse(encoded.contains("999999")); - assertFalse(encoded.contains("Zeckoski")); - assertFalse(encoded.contains("azeckoski")); - - // test collections - List list = new ArrayList(); - encoded = transcoder.encode(list, null, properties); - assertNotNull(encoded); - assertEquals("[]", encoded); //json - assertFalse(encoded.contains("999999")); - assertFalse(encoded.contains("Zeckoski")); - assertFalse(encoded.contains("azeckoski")); - - list.add( new TestPea("AZ","AaronZ")); - list.add( new TestPea("BZ","BeckyZ")); - encoded = transcoder.encode(list, null, properties); - assertNotNull(encoded); - assertTrue(encoded.contains("AZ")); - assertTrue(encoded.contains("AaronZ")); - assertTrue(encoded.contains("BZ")); - assertTrue(encoded.contains("BeckyZ")); - assertFalse(encoded.contains("999999")); - assertFalse(encoded.contains("Zeckoski")); - assertFalse(encoded.contains("azeckoski")); - - // test maps - Map m = new ArrayOrderedMap(); - m.put("id", 123); - m.put("thing", "AZ"); - encoded = transcoder.encode(m, null, properties); - assertNotNull(encoded); - assertTrue(encoded.contains("123")); - assertTrue(encoded.contains("AZ")); - assertTrue(encoded.contains("999999")); - assertTrue(encoded.contains("Zeckoski")); - assertTrue(encoded.contains("azeckoski")); - - Map m2 = new ArrayOrderedMap(); - m2.put("name", "aaron"); - m2.put("date", new Date()); - m2.put("num", 456); - m2.put("array", new String[] {"A","B","C"}); - m.put("map", m2); - - encoded = transcoder.encode(m, null, properties); - assertNotNull(encoded); - assertTrue(encoded.contains("123")); - assertTrue(encoded.contains("AZ")); - assertTrue(encoded.contains("aaron")); - assertTrue(encoded.contains("456")); - assertTrue(encoded.contains("999999")); - assertTrue(encoded.contains("Zeckoski")); - assertTrue(encoded.contains("azeckoski")); - - m.put("az", new TestBean()); - m.put("bz", new TestPea()); - m.put("oList", list); - m.put("oArray", array); - encoded = transcoder.encode(m, null, properties); - assertNotNull(encoded); - assertTrue(encoded.contains("123")); - assertTrue(encoded.contains("AZ")); - assertTrue(encoded.contains("aaron")); - assertTrue(encoded.contains("456")); - assertTrue(encoded.contains("az")); - assertTrue(encoded.contains("bz")); - assertTrue(encoded.contains("AaronZ")); - assertTrue(encoded.contains("BeckyZ")); - assertTrue(encoded.contains("888")); - assertTrue(encoded.contains("777")); - assertTrue(encoded.contains("999999")); - assertTrue(encoded.contains("Zeckoski")); - assertTrue(encoded.contains("azeckoski")); - - // test beans - TestCompound tc = new TestCompound(); - encoded = transcoder.encode(tc, "az-root", properties); - assertNotNull(encoded); -// assertTrue(encoded.contains("az-root")); - assertTrue(encoded.contains("fieldInt")); - assertTrue(encoded.contains("5")); - assertTrue(encoded.contains("myInt")); - assertTrue(encoded.contains("8")); - assertTrue(encoded.contains("myField")); - assertTrue(encoded.contains("myString")); - assertTrue(encoded.contains("999999")); - assertTrue(encoded.contains("Zeckoski")); - assertTrue(encoded.contains("azeckoski")); - - // test excluding nulls - Transcoder transcoder2 = new JSONTranscoder(false, false, false); - encoded = transcoder2.encode(tc, null, properties); - assertNotNull(encoded); - assertTrue(encoded.contains("fieldInt")); - assertTrue(encoded.contains("5")); - assertTrue(encoded.contains("myInt")); - assertTrue(encoded.contains("8")); - assertTrue(! encoded.contains("myField")); - assertTrue(! encoded.contains("myString")); - assertTrue(encoded.contains("999999")); - assertTrue(encoded.contains("Zeckoski")); - assertTrue(encoded.contains("azeckoski")); - - TestUltraNested tun = new TestUltraNested("aztitle", new TestNesting(999, "bztitle", new String[] {"ZZ","YY","XX"}) ); - encoded = transcoder.encode(tun, null, properties); - assertNotNull(encoded); - assertTrue(encoded.contains("aztitle")); - assertTrue(encoded.contains("testNesting")); - assertTrue(encoded.contains("sMap")); - assertTrue(encoded.contains("B2")); - assertTrue(encoded.contains("TWO")); - assertTrue(encoded.contains("testEntity")); - assertTrue(encoded.contains("prefix")); - assertTrue(encoded.contains("crud")); - assertTrue(encoded.contains("sArray")); - assertTrue(encoded.contains("entityId")); - assertTrue(encoded.contains("sList")); - assertTrue(encoded.contains("myArray")); - assertTrue(encoded.contains("extra")); - assertTrue(encoded.contains("testPea")); - assertTrue(encoded.contains("testBean")); - assertTrue(encoded.contains("999")); - assertTrue(encoded.contains("bztitle")); - assertTrue(encoded.contains("ZZ")); - assertTrue(encoded.contains("999999")); - assertTrue(encoded.contains("Zeckoski")); - assertTrue(encoded.contains("azeckoski")); +import static org.junit.jupiter.api.Assertions.*; - } +class TranscodersTest { - // testing the internal decoder - @SuppressWarnings("unchecked") - public void testJSONDecode() { + @Test + void jsonEncodeDecodeRoundTrip() { Transcoder transcoder = new JSONTranscoder(); - Map decoded = null; - - // TEST a few json test strings - String json = "{\"id\":123,\"thing\":\"AZ\"}"; - decoded = transcoder.decode(json); - assertNotNull(decoded); - assertEquals(123, decoded.get("id")); - assertEquals("AZ", decoded.get("thing")); - - json = "{\"id\":123,\"thing\":\"AZ\",\"map\":{\"name\":\"aaron\",\"date\":1221493247004,\"num\":456,\"array\":[\"A\",\"B\",\"C\"]}}"; - decoded = transcoder.decode(json); - assertNotNull(decoded); - assertEquals(3, decoded.size()); - assertEquals(123, decoded.get("id")); - assertEquals("AZ", decoded.get("thing")); - Map m2d = (Map) decoded.get("map"); - assertEquals(4, m2d.size()); - assertEquals("aaron", m2d.get("name")); - assertEquals(456, m2d.get("num")); - - // TEST in and out conversion - String encoded = null; - - // test simple cases - encoded = transcoder.encode(null, null, null); - assertNotNull(encoded); - assertEquals("null", encoded); - decoded = transcoder.decode(encoded); - assertNotNull(decoded); - assertEquals(null, decoded.get(Transcoder.DATA_KEY)); - - encoded = transcoder.encode("AaronZ", null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("AaronZ")); - decoded = transcoder.decode(encoded); - assertNotNull(decoded); - assertEquals("AaronZ", decoded.get(Transcoder.DATA_KEY)); - - encoded = transcoder.encode(1234, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("1234")); - decoded = transcoder.decode(encoded); - assertNotNull(decoded); - assertEquals(1234, decoded.get(Transcoder.DATA_KEY)); - - encoded = transcoder.encode(true, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("true")); - decoded = transcoder.decode(encoded); - assertNotNull(decoded); - assertEquals(true, decoded.get(Transcoder.DATA_KEY)); - - // test arrays - TestBean[] array = new TestBean[0]; - encoded = transcoder.encode(array, null, null); - assertNotNull(encoded); - assertEquals("[]", encoded); //json - decoded = transcoder.decode(encoded); - assertNotNull(decoded); - assertEquals(0, ((List)decoded.get(Transcoder.DATA_KEY)).size()); + Map payload = new LinkedHashMap<>(); + payload.put("name", "reflectutils"); + payload.put("version", 21); - array = new TestBean[] {new TestBean(888), new TestBean(777)}; - encoded = transcoder.encode(array, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("888")); - assertTrue(encoded.contains("777")); - decoded = transcoder.decode(encoded); - assertNotNull(decoded); - List> decodeArray = ((List>)decoded.get(Transcoder.DATA_KEY)); - assertEquals(2, decodeArray.size()); - assertEquals(array[0].getMyInt(), decodeArray.get(0).get("myInt")); - assertEquals(array[1].getMyString(), decodeArray.get(1).get("myString")); - - List list = new ArrayList(); - list.add( new TestPea("AZ","AaronZ")); - list.add( new TestPea("BZ","BeckyZ")); - - // test maps - Map m = new ArrayOrderedMap(); - m.put("id", 123); - m.put("thing", "AZ"); - encoded = transcoder.encode(m, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("123")); - assertTrue(encoded.contains("AZ")); - decoded = transcoder.decode(encoded); - assertNotNull(decoded); - assertEquals(2, decoded.size()); - assertEquals(123, decoded.get("id")); - assertEquals("AZ", decoded.get("thing")); - - Map m2 = new ArrayOrderedMap(); - m2.put("name", "aaron"); - m2.put("date", new Date()); - m2.put("num", 456); - m2.put("array", new String[] {"A","B","C"}); - m.put("map", m2); - - encoded = transcoder.encode(m, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("123")); - assertTrue(encoded.contains("AZ")); - assertTrue(encoded.contains("aaron")); - assertTrue(encoded.contains("456")); - decoded = transcoder.decode(encoded); - assertNotNull(decoded); - assertEquals(3, decoded.size()); - assertEquals(123, decoded.get("id")); - assertEquals("AZ", decoded.get("thing")); - m2d = (Map) decoded.get("map"); - assertEquals(4, m2d.size()); - assertEquals("aaron", m2d.get("name")); - assertEquals(456, m2d.get("num")); - - // test beans - TestCompound tc = new TestCompound(); - encoded = transcoder.encode(tc, "az-root", null); - assertNotNull(encoded); -// assertTrue(encoded.contains("az-root")); - assertTrue(encoded.contains("fieldInt")); - assertTrue(encoded.contains("5")); - assertTrue(encoded.contains("myInt")); - assertTrue(encoded.contains("8")); - assertTrue(encoded.contains("myField")); - assertTrue(encoded.contains("myString")); - decoded = transcoder.decode(encoded); - assertNotNull(decoded); - assertEquals(4, decoded.size()); - assertEquals(5, decoded.get("fieldInt")); - assertEquals(8, decoded.get("myInt")); - assertEquals(null, decoded.get("myField")); - assertEquals(null, decoded.get("myString")); + String encoded = transcoder.encode(payload, null, null); + Map decoded = transcoder.decode(encoded); + assertEquals("reflectutils", decoded.get("name")); + assertEquals(21, decoded.get("version")); } - public void testXMLEncode() { - Transcoder transcoder = new XMLTranscoder(false, true, false); - String encoded = null; - - // test simple cases - encoded = transcoder.encode(null, null, null); - assertNotNull(encoded); - assertTrue( encoded.startsWith("") ); // XML - - encoded = transcoder.encode("AaronZ", null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("AaronZ")); - - encoded = transcoder.encode(1234, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("1234")); - - encoded = transcoder.encode(true, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("true")); - - // test arrays - TestBean[] array = new TestBean[0]; - encoded = transcoder.encode(array, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("type='array'")); // XML - - array = new TestBean[] {new TestBean(888), new TestBean(777)}; - encoded = transcoder.encode(array, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("888")); - assertTrue(encoded.contains("777")); - - // test collections - List list = new ArrayList(); - encoded = transcoder.encode(list, null, null); - assertNotNull(encoded); - //assertEquals("[]", encoded); //json - - list.add( new TestPea("AZ","AaronZ")); - list.add( new TestPea("BZ","BeckyZ")); - encoded = transcoder.encode(list, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("AZ")); - assertTrue(encoded.contains("AaronZ")); - assertTrue(encoded.contains("BZ")); - assertTrue(encoded.contains("BeckyZ")); - - // test maps - Map m = new ArrayOrderedMap(); - m.put("id", 123); - m.put("thing", "AZ"); - encoded = transcoder.encode(m, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("123")); - assertTrue(encoded.contains("AZ")); - - Map m2 = new ArrayOrderedMap(); - m2.put("name", "aaron"); - m2.put("date", new Date()); - m2.put("num", 456); - m2.put("array", new String[] {"A","B","C"}); - m.put("map", m2); - - encoded = transcoder.encode(m, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("123")); - assertTrue(encoded.contains("AZ")); - assertTrue(encoded.contains("aaron")); - assertTrue(encoded.contains("456")); - - m.put("az", new TestBean()); - m.put("bz", new TestPea()); - m.put("oList", list); - m.put("oArray", array); - encoded = transcoder.encode(m, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("123")); - assertTrue(encoded.contains("AZ")); - assertTrue(encoded.contains("aaron")); - assertTrue(encoded.contains("456")); - assertTrue(encoded.contains("az")); - assertTrue(encoded.contains("bz")); - assertTrue(encoded.contains("AaronZ")); - assertTrue(encoded.contains("BeckyZ")); - assertTrue(encoded.contains("888")); - assertTrue(encoded.contains("777")); - - // test beans - TestCompound tc = new TestCompound(); - encoded = transcoder.encode(tc, "az-root", null); - assertNotNull(encoded); - assertTrue(encoded.contains("az-root")); // XML - assertTrue(encoded.contains("fieldInt")); - assertTrue(encoded.contains("5")); - assertTrue(encoded.contains("myInt")); - assertTrue(encoded.contains("8")); - assertTrue(encoded.contains("myField")); - assertTrue(encoded.contains("myString")); - - // test excluding nulls - Transcoder transcoder2 = new XMLTranscoder(false, false, false); - encoded = transcoder2.encode(tc, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("fieldInt")); - assertTrue(encoded.contains("5")); - assertTrue(encoded.contains("myInt")); - assertTrue(encoded.contains("8")); - assertTrue(! encoded.contains("myField")); - assertTrue(! encoded.contains("myString")); - - TestUltraNested tun = new TestUltraNested("aztitle", new TestNesting(999, "bztitle", new String[] {"ZZ","YY","XX"}) ); - encoded = transcoder.encode(tun, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("aztitle")); - assertTrue(encoded.contains("testNesting")); - assertTrue(encoded.contains("sMap")); - assertTrue(encoded.contains("B2")); - assertTrue(encoded.contains("TWO")); - assertTrue(encoded.contains("testEntity")); - assertTrue(encoded.contains("prefix")); - assertTrue(encoded.contains("crud")); - assertTrue(encoded.contains("sArray")); - assertTrue(encoded.contains("entityId")); - assertTrue(encoded.contains("sList")); - assertTrue(encoded.contains("myArray")); - assertTrue(encoded.contains("extra")); - assertTrue(encoded.contains("testPea")); - assertTrue(encoded.contains("testBean")); - assertTrue(encoded.contains("999")); - assertTrue(encoded.contains("bztitle")); - assertTrue(encoded.contains("ZZ")); - - // test names with illegal chars in them - /* - XML elements must follow these naming rules: - Names can contain letters, numbers, and other characters - Names cannot start with a number or punctuation character (and some others) - Names cannot start with the letters xml (or XML, or Xml, etc) - Names cannot contain spaces + @Test + void jsonEncodeWithProperties() { + Transcoder transcoder = new JSONTranscoder(true, true, true); + Map properties = new LinkedHashMap<>(); + properties.put("meta", "test"); - See http://www.w3.org/TR/REC-xml/#sec-common-syn - Names beginning with the string "xml", or with any string which would match (('X'|'x') ('M'|'m') ('L'|'l')), - are reserved for standardization in this or future versions of this specification. - */ - Map m3 = new ArrayOrderedMap(); - m3.put("totally-valid_name.1", "VALUE"); - m3.put("valid1with.num-andSTUFF", "VALUE"); - m3.put("1numberStart", "VALUE"); - m3.put(".periodStart", "VALUE"); - m3.put("xAtStart", "VALUE"); - m3.put("xmlAtStart", "VALUE"); - m3.put("XMLUpAtStart", "VALUE"); - m3.put("has spaces in it", "VALUE"); - m3.put("no=or'or\"oror&allowed", "VALUE"); - m3.put("#HashStart", "VALUE"); - m3.put("-DashStart", "VALUE"); - m3.put("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()_+-=<>,.:;\"'[]{}|\\~`01234567890", "VALUE"); - encoded = transcoder.encode(m3, "root", null); - assertNotNull(encoded); - assertTrue(encoded.contains("totally-valid_name.1")); - assertTrue(encoded.contains("valid1with.num-andSTUFF")); - assertTrue(encoded.contains("_numberStart")); - assertTrue(encoded.contains("_periodStart")); - assertTrue(encoded.contains("xAtStart")); - assertTrue(encoded.contains("_AtStart")); - assertTrue(encoded.contains("_UpAtStart")); - assertTrue(encoded.contains("has_spaces_in_it")); - assertTrue(encoded.contains("no_or_or_or_or_or_allowed")); - assertTrue(encoded.contains("_DashStart")); - assertTrue(encoded.contains("_UpAtStart")); - assertTrue(encoded.contains("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ____________-____.:___________01234567890")); - - // test with auto-correct off - XMLTranscoder transcoder3 = new XMLTranscoder(false, true, false, false); - transcoder3.setFixTags(false); - - Map m4 = new ArrayOrderedMap(); - m4.clear(); - m4.put("totally-valid_name.1", "VALUE"); - encoded = transcoder3.encode(m4, "root", null); - assertNotNull(encoded); - assertTrue(encoded.contains("totally-valid_name.1")); - - try { - m4.clear(); - m4.put("1numberStart", "VALUE"); - encoded = transcoder3.encode(m4, "root", null); - fail("Should have caused exception"); - } catch (Exception e) { - assertNotNull(e.getMessage()); - } - try { - m4.clear(); - m4.put("xmlAtStart", "VALUE"); - encoded = transcoder3.encode(m4, "root", null); - fail("Should have caused exception"); - } catch (Exception e) { - assertNotNull(e.getMessage()); - } - try { - m4.clear(); - m4.put("has spaces in it", "VALUE"); - encoded = transcoder3.encode(m4, "root", null); - fail("Should have caused exception"); - } catch (Exception e) { - assertNotNull(e.getMessage()); - } - try { - m4.clear(); - m4.put("no=or'or\"oror&allowed", "VALUE"); - encoded = transcoder3.encode(m3, "root", null); - fail("Should have caused exception"); - } catch (Exception e) { - assertNotNull(e.getMessage()); - } - } - - public void testXMLEncodeSpecial() { - Transcoder transcoder = new XMLTranscoder(false, true, false); - String encoded = null; - - // test maps - Map m = new ArrayOrderedMap(); - m.put("A_1", 111); - m.put("B 2", 222); - m.put("C&3", 333); - m.put("D\"4", 444); - m.put("E'5", 555); - m.put("F<6", 666); - m.put("G>7", 777); - m.put("H=8", 888); - encoded = transcoder.encode(m, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("111")); - assertTrue(encoded.contains("222")); - assertTrue(encoded.contains("333")); - assertTrue(encoded.contains("444")); - assertTrue(encoded.contains("555")); - assertTrue(encoded.contains("666")); - assertTrue(encoded.contains("777")); - assertTrue(encoded.contains("888")); - } - - public void testXMLEncodeProperties() { - Transcoder transcoder = new XMLTranscoder(true, true, false); - String encoded = null; - - Map properties = new ArrayOrderedMap(); - properties.put("prop1", 999999); - properties.put("prop2", "Zeckoski"); - properties.put("prop3", new TestPea("AZ","azeckoski")); - properties.put("prop4", null); - - // test simple cases - encoded = transcoder.encode(null, null, properties); - assertNotNull(encoded); - assertTrue( encoded.startsWith("") ); // XML - assertFalse(encoded.contains("999999")); - assertFalse(encoded.contains("Zeckoski")); - assertFalse(encoded.contains("azeckoski")); - - encoded = transcoder.encode("AaronZ", null, properties); - assertNotNull(encoded); - assertTrue(encoded.contains("AaronZ")); - assertFalse(encoded.contains("999999")); - assertFalse(encoded.contains("Zeckoski")); - assertFalse(encoded.contains("azeckoski")); - - encoded = transcoder.encode(1234, null, properties); - assertNotNull(encoded); - assertTrue(encoded.contains("1234")); - assertFalse(encoded.contains("999999")); - assertFalse(encoded.contains("Zeckoski")); - assertFalse(encoded.contains("azeckoski")); - - encoded = transcoder.encode(true, null, properties); - assertNotNull(encoded); - assertTrue(encoded.contains("true")); - assertFalse(encoded.contains("999999")); - assertFalse(encoded.contains("Zeckoski")); - assertFalse(encoded.contains("azeckoski")); - - // test arrays - TestBean[] array = new TestBean[0]; - encoded = transcoder.encode(array, null, properties); - assertNotNull(encoded); - assertTrue(encoded.contains("type='array'")); // XML - assertFalse(encoded.contains("999999")); - assertFalse(encoded.contains("Zeckoski")); - assertFalse(encoded.contains("azeckoski")); - - array = new TestBean[] {new TestBean(888), new TestBean(777)}; - encoded = transcoder.encode(array, null, properties); - assertNotNull(encoded); - assertTrue(encoded.contains("888")); - assertTrue(encoded.contains("777")); - assertFalse(encoded.contains("999999")); - assertFalse(encoded.contains("Zeckoski")); - assertFalse(encoded.contains("azeckoski")); - - // test collections - List list = new ArrayList(); - encoded = transcoder.encode(list, null, properties); - assertNotNull(encoded); - //assertEquals("[]", encoded); //json - assertFalse(encoded.contains("999999")); - assertFalse(encoded.contains("Zeckoski")); - assertFalse(encoded.contains("azeckoski")); - - list.add( new TestPea("AZ","AaronZ")); - list.add( new TestPea("BZ","BeckyZ")); - encoded = transcoder.encode(list, null, properties); - assertNotNull(encoded); - assertTrue(encoded.contains("AZ")); - assertTrue(encoded.contains("AaronZ")); - assertTrue(encoded.contains("BZ")); - assertTrue(encoded.contains("BeckyZ")); - assertFalse(encoded.contains("999999")); - assertFalse(encoded.contains("Zeckoski")); - assertFalse(encoded.contains("azeckoski")); - - // test maps - Map m = new ArrayOrderedMap(); - m.put("id", 123); - m.put("thing", "AZ"); - encoded = transcoder.encode(m, null, properties); - assertNotNull(encoded); - assertTrue(encoded.contains("123")); - assertTrue(encoded.contains("AZ")); - assertTrue(encoded.contains("999999")); - assertTrue(encoded.contains("Zeckoski")); - assertTrue(encoded.contains("azeckoski")); - - Map m2 = new ArrayOrderedMap(); - m2.put("name", "aaron"); - m2.put("date", new Date()); - m2.put("num", 456); - m2.put("array", new String[] {"A","B","C"}); - m.put("map", m2); - - encoded = transcoder.encode(m, null, properties); - assertNotNull(encoded); - assertTrue(encoded.contains("123")); - assertTrue(encoded.contains("AZ")); - assertTrue(encoded.contains("aaron")); - assertTrue(encoded.contains("456")); - assertTrue(encoded.contains("999999")); - assertTrue(encoded.contains("Zeckoski")); - assertTrue(encoded.contains("azeckoski")); - - m.put("az", new TestBean()); - m.put("bz", new TestPea()); - m.put("oList", list); - m.put("oArray", array); - encoded = transcoder.encode(m, null, properties); - assertNotNull(encoded); - assertTrue(encoded.contains("123")); - assertTrue(encoded.contains("AZ")); - assertTrue(encoded.contains("aaron")); - assertTrue(encoded.contains("456")); - assertTrue(encoded.contains("az")); - assertTrue(encoded.contains("bz")); - assertTrue(encoded.contains("AaronZ")); - assertTrue(encoded.contains("BeckyZ")); - assertTrue(encoded.contains("888")); - assertTrue(encoded.contains("777")); - assertTrue(encoded.contains("999999")); - assertTrue(encoded.contains("Zeckoski")); - assertTrue(encoded.contains("azeckoski")); - - // test beans - TestCompound tc = new TestCompound(); - encoded = transcoder.encode(tc, "az-root", properties); - assertNotNull(encoded); - assertTrue(encoded.contains("az-root")); // XML - assertTrue(encoded.contains("fieldInt")); - assertTrue(encoded.contains("5")); - assertTrue(encoded.contains("myInt")); - assertTrue(encoded.contains("8")); - assertTrue(encoded.contains("myField")); - assertTrue(encoded.contains("myString")); - assertTrue(encoded.contains("999999")); - assertTrue(encoded.contains("Zeckoski")); - assertTrue(encoded.contains("azeckoski")); - - // test excluding nulls - Transcoder transcoder2 = new XMLTranscoder(false, false, false); - encoded = transcoder2.encode(tc, null, properties); - assertNotNull(encoded); - assertTrue(encoded.contains("fieldInt")); - assertTrue(encoded.contains("5")); - assertTrue(encoded.contains("myInt")); - assertTrue(encoded.contains("8")); - assertTrue(! encoded.contains("myField")); - assertTrue(! encoded.contains("myString")); - assertTrue(encoded.contains("999999")); - assertTrue(encoded.contains("Zeckoski")); - assertTrue(encoded.contains("azeckoski")); - - TestUltraNested tun = new TestUltraNested("aztitle", new TestNesting(999, "bztitle", new String[] {"ZZ","YY","XX"}) ); - encoded = transcoder.encode(tun, null, properties); - assertNotNull(encoded); - assertTrue(encoded.contains("aztitle")); - assertTrue(encoded.contains("testNesting")); - assertTrue(encoded.contains("sMap")); - assertTrue(encoded.contains("B2")); - assertTrue(encoded.contains("TWO")); - assertTrue(encoded.contains("testEntity")); - assertTrue(encoded.contains("prefix")); - assertTrue(encoded.contains("crud")); - assertTrue(encoded.contains("sArray")); - assertTrue(encoded.contains("entityId")); - assertTrue(encoded.contains("sList")); - assertTrue(encoded.contains("myArray")); - assertTrue(encoded.contains("extra")); - assertTrue(encoded.contains("testPea")); - assertTrue(encoded.contains("testBean")); - assertTrue(encoded.contains("999")); - assertTrue(encoded.contains("bztitle")); - assertTrue(encoded.contains("ZZ")); - assertTrue(encoded.contains("999999")); - assertTrue(encoded.contains("Zeckoski")); - assertTrue(encoded.contains("azeckoski")); + String encoded = transcoder.encode(new TestBean("alpha"), "bean", properties); + Map decoded = transcoder.decode(encoded); + assertEquals("test", decoded.get("meta")); + Map bean = (Map) decoded.get("bean"); + assertEquals("alpha", bean.get("value")); } - // testing the internal decoder - @SuppressWarnings("unchecked") - public void testXMLDecode() { - Transcoder transcoder = new XMLTranscoder(true, true, false); - Map decoded = null; - - // simple - String xml = "123AZ"; - decoded = transcoder.decode(xml); - assertNotNull(decoded); - assertEquals(123, decoded.get("id")); - assertEquals("AZ", decoded.get("thing")); - - // complete - xml = "123AZaaron1221659238015456ABC"; - decoded = transcoder.decode(xml); - assertNotNull(decoded); - assertEquals(3, decoded.size()); - assertEquals(123, decoded.get("id")); - assertEquals("AZ", decoded.get("thing")); - Map m2d = (Map) decoded.get("map"); - assertEquals(4, m2d.size()); - assertEquals("aaron", m2d.get("name")); - assertEquals(456, m2d.get("num")); - - // TEST in and out conversion - String encoded = null; - - // test simple cases -/*** TODO currently we always trash the root node(s) - encoded = transcoder.encode(null, null); - assertNotNull(encoded); - assertTrue( encoded.startsWith("") ); // XML - decoded = transcoder.decode(encoded); - assertNotNull(decoded); - assertEquals(null, decoded.get(Transcoder.DATA_KEY)); - - encoded = transcoder.encode("AaronZ", null); - assertNotNull(encoded); - assertTrue(encoded.contains("AaronZ")); - decoded = transcoder.decode(encoded); - assertNotNull(decoded); - assertEquals("AaronZ", decoded.get(Transcoder.DATA_KEY)); + @Test + void xmlEncodeDecodeRoundTrip() { + Transcoder transcoder = new XMLTranscoder(); + Map payload = new LinkedHashMap<>(); + payload.put("project", "reflectutils"); + payload.put("jdk", 21); - encoded = transcoder.encode(1234, null); - assertNotNull(encoded); - assertTrue(encoded.contains("1234")); - decoded = transcoder.decode(encoded); - assertNotNull(decoded); - assertEquals(1234, decoded.get(Transcoder.DATA_KEY)); + String encoded = transcoder.encode(payload, null, null); + Map decoded = transcoder.decode(encoded); - encoded = transcoder.encode(true, null); - assertNotNull(encoded); - assertTrue(encoded.contains("true")); - decoded = transcoder.decode(encoded); - assertNotNull(decoded); - assertEquals(true, decoded.get(Transcoder.DATA_KEY)); - - // test arrays - TestBean[] array = new TestBean[0]; - encoded = transcoder.encode(array, null); - assertNotNull(encoded); - //assertEquals("[]", encoded); //json - decoded = transcoder.decode(encoded); - assertNotNull(decoded); - assertEquals(0, ((List)decoded.get(Transcoder.DATA_KEY)).size()); - - array = new TestBean[] {new TestBean(888), new TestBean(777)}; - encoded = transcoder.encode(array, null); - assertNotNull(encoded); - assertTrue(encoded.contains("888")); - assertTrue(encoded.contains("777")); - decoded = transcoder.decode(encoded); - assertNotNull(decoded); - List> decodeArray = ((List)decoded.get(Transcoder.DATA_KEY)); - assertEquals(2, decodeArray.size()); - assertEquals(array[0].getMyInt(), decodeArray.get(0).get("myInt")); - assertEquals(array[1].getMyString(), decodeArray.get(1).get("myString")); - -****/ - - List list = new ArrayList(); - list.add( new TestPea("AZ","AaronZ")); - list.add( new TestPea("BZ","BeckyZ")); - - // test maps - Map m = new ArrayOrderedMap(); - m.put("id", 123); - m.put("thing", "AZ"); - encoded = transcoder.encode(m, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("123")); - assertTrue(encoded.contains("AZ")); - decoded = transcoder.decode(encoded); - assertNotNull(decoded); - assertEquals(2, decoded.size()); - assertEquals(123, decoded.get("id")); - assertEquals("AZ", decoded.get("thing")); - - Map m2 = new ArrayOrderedMap(); - m2.put("name", "aaron"); - m2.put("date", new Date()); - m2.put("num", 456); - m2.put("array", new String[] {"A","B","C"}); - m.put("map", m2); - - encoded = transcoder.encode(m, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("123")); - assertTrue(encoded.contains("AZ")); - assertTrue(encoded.contains("aaron")); - assertTrue(encoded.contains("456")); - decoded = transcoder.decode(encoded); - assertNotNull(decoded); - assertEquals(3, decoded.size()); - assertEquals(123, decoded.get("id")); - assertEquals("AZ", decoded.get("thing")); - m2d = (Map) decoded.get("map"); - assertEquals(4, m2d.size()); - assertEquals("aaron", m2d.get("name")); - assertEquals(456, m2d.get("num")); - - // test beans - TestCompound tc = new TestCompound(); - encoded = transcoder.encode(tc, "az-root", null); - assertNotNull(encoded); -// assertTrue(encoded.contains("az-root")); - assertTrue(encoded.contains("fieldInt")); - assertTrue(encoded.contains("5")); - assertTrue(encoded.contains("myInt")); - assertTrue(encoded.contains("8")); - assertTrue(encoded.contains("myField")); - assertTrue(encoded.contains("myString")); - decoded = transcoder.decode(encoded); - assertNotNull(decoded); - assertEquals(4, decoded.size()); - assertEquals(5, decoded.get("fieldInt")); - assertEquals(8, decoded.get("myInt")); - assertEquals(null, decoded.get("myField")); - assertEquals(null, decoded.get("myString")); + assertEquals("reflectutils", decoded.get("project")); + assertEquals(21, decoded.get("jdk")); } - @SuppressWarnings("unchecked") - public void testXMLDecodeWithoutTypes() { - Transcoder transcoder = new XMLTranscoder(true, true, false); - Map decoded = null; - - // simple - String xml = "123AZ"; - decoded = transcoder.decode(xml); - assertNotNull(decoded); - assertEquals("123", decoded.get("id")); - assertEquals("AZ", decoded.get("thing")); - - // nested - xml = "aaronaz@vt.edubeckybz@vt.eduUSA"; - decoded = transcoder.decode(xml); - assertNotNull(decoded); - assertEquals(2, decoded.size()); - assertEquals("USA", decoded.get("country")); - List> people = (List>) decoded.get("people"); - assertEquals(2, people.size()); - assertEquals("aaron", people.get(0).get("name")); - assertEquals("becky", people.get(1).get("name")); - assertEquals("az@vt.edu", people.get(0).get("email")); - assertEquals("bz@vt.edu", people.get(1).get("email")); + private static class TestBean { + private final String value; - xml = "aaronaz@vt.eduaaron@vt.eduazeckoski@gmail.combeckybz@vt.edubecky@vt.eduUSA"; - decoded = transcoder.decode(xml); - assertNotNull(decoded); - assertEquals(2, decoded.size()); - assertEquals("USA", decoded.get("country")); - people = (List>) decoded.get("people"); - assertEquals(2, people.size()); - assertEquals("aaron", people.get(0).get("name")); - assertEquals("becky", people.get(1).get("name")); - List emails = (List) people.get(0).get("emails"); - assertEquals(3, emails.size()); - assertEquals("az@vt.edu", emails.get(0)); - assertEquals("aaron@vt.edu", emails.get(1)); - assertEquals("azeckoski@gmail.com", emails.get(2)); - emails = (List) people.get(1).get("emails"); - assertEquals("bz@vt.edu", emails.get(0)); - assertEquals("becky@vt.edu", emails.get(1)); - - xml = "aaronaz@vt.eduaaron@vt.eduminervacatrockyrockputerlaptopbeckybz@vt.edubecky@vt.eduUSA"; - decoded = transcoder.decode(xml); - assertNotNull(decoded); - assertEquals(2, decoded.size()); - assertEquals("USA", decoded.get("country")); - people = (List>) decoded.get("people"); - assertEquals(2, people.size()); - assertEquals("aaron", people.get(0).get("name")); - assertEquals("becky", people.get(1).get("name")); - emails = (List) people.get(0).get("emails"); - assertEquals("az@vt.edu", emails.get(0)); - assertEquals("aaron@vt.edu", emails.get(1)); - emails = (List) people.get(1).get("emails"); - assertEquals("bz@vt.edu", emails.get(0)); - assertEquals("becky@vt.edu", emails.get(1)); - List> pets = (List>) people.get(0).get("pets"); - assertNotNull(pets); - assertEquals(3, pets.size()); - assertEquals("minerva", pets.get(0).get("name")); - assertEquals("cat", pets.get(0).get("type")); - assertEquals("rocky", pets.get(1).get("name")); - assertEquals("rock", pets.get(1).get("type")); - assertEquals("puter", pets.get(2).get("name")); - assertEquals("laptop", pets.get(2).get("type")); - assertNull( people.get(1).get("pets") ); - } - - public void testHTMLEncode() { - Transcoder transcoder = new HTMLTranscoder(true, true, false); - String encoded = null; - - // test simple cases - encoded = transcoder.encode(null, null, null); - assertNotNull(encoded); - assertTrue( encoded.contains("NULL") ); // HTML - - encoded = transcoder.encode("AaronZ", null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("AaronZ")); - - encoded = transcoder.encode(1234, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("1234")); - - encoded = transcoder.encode(true, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("true")); - - // test arrays - TestBean[] array = new TestBean[0]; - encoded = transcoder.encode(array, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("type=array")); // HTML - - array = new TestBean[] {new TestBean(888), new TestBean(777)}; - encoded = transcoder.encode(array, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("888")); - assertTrue(encoded.contains("777")); - - // test collections - List list = new ArrayList(); - encoded = transcoder.encode(list, null, null); - assertNotNull(encoded); - //assertEquals("[]", encoded); //json - - list.add( new TestPea("AZ","AaronZ")); - list.add( new TestPea("BZ","BeckyZ")); - encoded = transcoder.encode(list, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("AZ")); - assertTrue(encoded.contains("AaronZ")); - assertTrue(encoded.contains("BZ")); - assertTrue(encoded.contains("BeckyZ")); - - // test maps - Map m = new ArrayOrderedMap(); - m.put("id", 123); - m.put("thing", "AZ"); - encoded = transcoder.encode(m, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("123")); - assertTrue(encoded.contains("AZ")); - - Map m2 = new ArrayOrderedMap(); - m2.put("name", "aaron"); - m2.put("date", new Date()); - m2.put("num", 456); - m2.put("array", new String[] {"A","B","C"}); - m.put("map", m2); - - encoded = transcoder.encode(m, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("123")); - assertTrue(encoded.contains("AZ")); - assertTrue(encoded.contains("aaron")); - assertTrue(encoded.contains("456")); - - m.put("az", new TestBean()); - m.put("bz", new TestPea()); - m.put("oList", list); - m.put("oArray", array); - encoded = transcoder.encode(m, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("123")); - assertTrue(encoded.contains("AZ")); - assertTrue(encoded.contains("aaron")); - assertTrue(encoded.contains("456")); - assertTrue(encoded.contains("az")); - assertTrue(encoded.contains("bz")); - assertTrue(encoded.contains("AaronZ")); - assertTrue(encoded.contains("BeckyZ")); - assertTrue(encoded.contains("888")); - assertTrue(encoded.contains("777")); - - // test beans - TestCompound tc = new TestCompound(); - encoded = transcoder.encode(tc, "az-root", null); - assertNotNull(encoded); - assertTrue(encoded.contains("az-root")); // XML - assertTrue(encoded.contains("fieldInt")); - assertTrue(encoded.contains("5")); - assertTrue(encoded.contains("myInt")); - assertTrue(encoded.contains("8")); - assertTrue(encoded.contains("myField")); - assertTrue(encoded.contains("myString")); - - // test excluding nulls - Transcoder transcoder2 = new HTMLTranscoder(false, false, false); - encoded = transcoder2.encode(tc, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("fieldInt")); - assertTrue(encoded.contains("5")); - assertTrue(encoded.contains("myInt")); - assertTrue(encoded.contains("8")); - assertTrue(! encoded.contains("myField")); - assertTrue(! encoded.contains("myString")); - - TestUltraNested tun = new TestUltraNested("aztitle", new TestNesting(999, "bztitle", new String[] {"ZZ","YY","XX"}) ); - encoded = transcoder.encode(tun, null, null); - assertNotNull(encoded); - assertTrue(encoded.contains("aztitle")); - assertTrue(encoded.contains("testNesting")); - assertTrue(encoded.contains("sMap")); - assertTrue(encoded.contains("B2")); - assertTrue(encoded.contains("TWO")); - assertTrue(encoded.contains("testEntity")); - assertTrue(encoded.contains("prefix")); - assertTrue(encoded.contains("crud")); - assertTrue(encoded.contains("sArray")); - assertTrue(encoded.contains("entityId")); - assertTrue(encoded.contains("sList")); - assertTrue(encoded.contains("myArray")); - assertTrue(encoded.contains("extra")); - assertTrue(encoded.contains("testPea")); - assertTrue(encoded.contains("testBean")); - assertTrue(encoded.contains("999")); - assertTrue(encoded.contains("bztitle")); - assertTrue(encoded.contains("ZZ")); - - } - - public void testLoopStoppingJSON() { - Transcoder transcoder = new JSONTranscoder(true, true, false); - String encoded = null; - - TestBaseOne tbo = new TestBaseOne(); - encoded = transcoder.encode(tbo, null, null); - int size = encoded.length(); - assertNotNull(encoded); - assertTrue(size > 1000); - assertTrue(size < 200000); - - } - - public void testLoopStoppingXML() { - Transcoder transcoder = new XMLTranscoder(true, true, false); - String encoded = null; - - TestBaseOne tbo = new TestBaseOne(); - encoded = transcoder.encode(tbo, null, null); - int size = encoded.length(); - assertNotNull(encoded); - assertTrue(size > 1000); - assertTrue(size < 200000); - - } - - public void testCrazyClassesJSON() { - TestHibernateLikeBean crazy = new TestHibernateLikeBean(); - - Transcoder transcoder = new JSONTranscoder(true, true, false); - String encoded = null; - - encoded = transcoder.encode(crazy, null, null); - int size = encoded.length(); - assertNotNull(encoded); - assertTrue(size > 100); - assertTrue(size < 1000); - } - - public void testCrazyClassesXML() { - TestHibernateLikeBean crazy = new TestHibernateLikeBean(); - - Transcoder transcoder = new XMLTranscoder(true, true, false); - String encoded = null; - - encoded = transcoder.encode(crazy, null, null); - int size = encoded.length(); - assertNotNull(encoded); - assertTrue(size > 100); - assertTrue(size < 1000); - } - - public void testDateEncoding() { - Transcoder transcoder = new JSONTranscoder(false, true, false); - String encoded = null; - - Date d = new Date(1255129200000l); - encoded = transcoder.encode(d, "date", null); - assertNotNull(encoded); - assertEquals("1255129200000", encoded); - - Timestamp t = new Timestamp(1255129200000l); - encoded = transcoder.encode(t, "date", null); - assertNotNull(encoded); - assertEquals("1255129200000", encoded); - - /* sql date is not immutable - java.sql.Date sd = new java.sql.Date(1255129200000l); - encoded = transcoder.encode(sd, "date", null); - assertNotNull(encoded); - assertEquals("1255129200000", encoded); - */ + TestBean(String value) { + this.value = value; + } + public String getValue() { + return value; + } } - } diff --git a/src/test/java/org/azeckoski/reflectutils/map/ArrayOrderedMapTest.java b/src/test/java/org/azeckoski/reflectutils/map/ArrayOrderedMapTest.java deleted file mode 100644 index 7d5a565..0000000 --- a/src/test/java/org/azeckoski/reflectutils/map/ArrayOrderedMapTest.java +++ /dev/null @@ -1,317 +0,0 @@ -/** - * $Id: ArrayOrderedMapTest.java 2 2008-10-01 10:04:26Z azeckoski $ - * $URL: http://reflectutils.googlecode.com/svn/trunk/src/test/java/org/azeckoski/reflectutils/map/ArrayOrderedMapTest.java $ - * ArrayOrderedMapTest.java - entity-broker - Aug 15, 2008 5:08:59 PM - azeckoski - ************************************************************************** - * Copyright (c) 2008 Aaron Zeckoski - * Licensed under the Apache License, Version 2.0 - * - * A copy of the Apache License has been included in this - * distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt - * - * Aaron Zeckoski (azeckoski@gmail.com) (aaronz@vt.edu) (aaron@caret.cam.ac.uk) - */ - -package org.azeckoski.reflectutils.map; - -import java.util.Collection; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.List; -import java.util.NoSuchElementException; -import java.util.Set; -import java.util.Map.Entry; - -import junit.framework.TestCase; - -/** - * testing the ordered map - * - * @author Aaron Zeckoski (azeckoski @ gmail.com) - */ -public class ArrayOrderedMapTest extends TestCase { - - private ArrayOrderedMap m1 = null; - - @Override - protected void setUp() throws Exception { - m1 = new ArrayOrderedMap(); - m1.put("AAA", "aaronz"); - m1.put("BBB", "beckyz"); - m1.put("CCC", "cat"); - } - - /** - * Test method for {@link org.sakaiproject.entitybroker.util.map.OrderedMap#clear()}. - */ - public void testClear() { - assertNotNull(m1); - assertEquals(3, m1.size()); - assertFalse(m1.isEmpty()); - m1.clear(); - assertNotNull(m1); - assertEquals(0, m1.size()); - assertTrue(m1.isEmpty()); - } - - /** - * Test method for {@link org.sakaiproject.entitybroker.util.map.OrderedMap#getKeys()}. - */ - public void testGetKeys() { - List keys = m1.getKeys(); - assertNotNull(keys); - assertEquals(3, keys.size()); - assertEquals("AAA", keys.get(0)); - assertEquals("BBB", keys.get(1)); - assertEquals("CCC", keys.get(2)); - } - - /** - * testing the get values method - */ - public void testGetValues() { - List keys = m1.getValues(); - assertNotNull(keys); - assertEquals(3, keys.size()); - assertEquals("aaronz", keys.get(0)); - assertEquals("beckyz", keys.get(1)); - assertEquals("cat", keys.get(2)); - } - - /** - * Test method for {@link org.sakaiproject.entitybroker.util.map.OrderedMap#getEntries()}. - */ - public void testGetEntries() { - List> entries = m1.getEntries(); - assertNotNull(entries); - assertEquals(3, entries.size()); - assertEquals("AAA", entries.get(0).getKey()); - assertEquals("BBB", entries.get(1).getKey()); - assertEquals("CCC", entries.get(2).getKey()); - assertEquals("aaronz", entries.get(0).getValue()); - assertEquals("beckyz", entries.get(1).getValue()); - assertEquals("cat", entries.get(2).getValue()); - } - - public void testGet() { - assertEquals("aaronz", m1.get("AAA")); - assertEquals("beckyz", m1.get("BBB")); - assertEquals("cat", m1.get("CCC")); - assertEquals(null, m1.get("DDD")); - m1.put("null", null); - assertEquals(null, m1.get("null")); - } - - public void testGetEntry() { - Entry entry = m1.getEntry(1); - assertNotNull(entry); - assertEquals("BBB", entry.getKey()); - - try { - entry = m1.getEntry(5); - fail("should have died"); - } catch (IllegalArgumentException e) { - assertNotNull(e.getMessage()); - } - } - - public void testPutKV() { - m1.put("DDD", "dog"); - assertEquals(4, m1.size()); - - m1.put("BBB", "beckers"); - assertEquals(4, m1.size()); - - List keys = m1.getKeys(); - assertNotNull(keys); - assertEquals(4, keys.size()); - assertEquals("AAA", keys.get(0)); - assertEquals("CCC", keys.get(1)); - assertEquals("DDD", keys.get(2)); - assertEquals("BBB", keys.get(3)); - - m1.put("DDD", "dog"); - assertEquals(4, m1.size()); - - keys = m1.getKeys(); - assertEquals(4, keys.size()); - assertEquals("AAA", keys.get(0)); - assertEquals("CCC", keys.get(1)); - assertEquals("BBB", keys.get(2)); - assertEquals("DDD", keys.get(3)); - - m1.put("NULL", null); - assertEquals(5, m1.size()); - assertTrue(m1.containsKey("NULL")); - assertEquals(null, m1.get("NULL")); - } - - /** - * Test method for {@link org.sakaiproject.entitybroker.util.map.OrderedMap#remove(java.lang.Object)}. - */ - public void testRemoveObject() { - String val = m1.remove("AAA"); - assertNotNull(val); - assertEquals("aaronz", val); - assertEquals(2, m1.size()); - - List keys = m1.getKeys(); - assertNotNull(keys); - assertEquals(2, keys.size()); - assertEquals("BBB", keys.get(0)); - assertEquals("CCC", keys.get(1)); - - val = m1.remove("EEE"); - assertNull(val); - } - - /** - * Test method for {@link org.sakaiproject.entitybroker.util.map.OrderedMap#keys()}. - */ - public void testKeys() { - Enumeration e = m1.keys(); - assertTrue( e.hasMoreElements() ); - assertEquals(e.nextElement(), "AAA"); - assertTrue( e.hasMoreElements() ); - assertEquals(e.nextElement(), "BBB"); - assertTrue( e.hasMoreElements() ); - assertEquals(e.nextElement(), "CCC"); - assertFalse( e.hasMoreElements() ); - try { - e.nextElement(); - fail("should have died"); - } catch (NoSuchElementException ne) { - assertNotNull(ne.getMessage()); - } - } - - /** - * Test method for {@link org.sakaiproject.entitybroker.util.map.OrderedMap#elements()}. - */ - public void testElements() { - Enumeration e = m1.elements(); - assertTrue( e.hasMoreElements() ); - assertEquals(e.nextElement(), "aaronz"); - assertTrue( e.hasMoreElements() ); - assertEquals(e.nextElement(), "beckyz"); - assertTrue( e.hasMoreElements() ); - assertEquals(e.nextElement(), "cat"); - assertFalse( e.hasMoreElements() ); - try { - e.nextElement(); - fail("should have died"); - } catch (NoSuchElementException ne) { - assertNotNull(ne.getMessage()); - } - } - - - public void testKeySet() { - Set keys = m1.keySet(); - assertEquals(3, keys.size()); - Iterator it = keys.iterator(); - assertTrue( it.hasNext() ); - assertEquals(it.next(), "AAA"); - assertTrue( it.hasNext() ); - assertEquals(it.next(), "BBB"); - assertTrue( it.hasNext() ); - assertEquals(it.next(), "CCC"); - assertFalse( it.hasNext() ); - try { - it.next(); - fail("should have died"); - } catch (NoSuchElementException e) { - assertNotNull(e.getMessage()); - } - - // test remove - it = keys.iterator(); - it.next(); - it.next(); - it.remove(); - assertEquals(2, keys.size()); - assertEquals(2, m1.size()); - - // test remove all - keys.clear(); - assertEquals(0, keys.size()); - assertTrue(keys.isEmpty()); - assertEquals(0, m1.size()); - assertTrue(m1.isEmpty()); - } - - /** - * Test method for {@link org.sakaiproject.entitybroker.util.map.OrderedMap#values()}. - */ - public void testValues() { - Collection values = m1.values(); - assertEquals(3, values.size()); - Iterator it = values.iterator(); - assertTrue( it.hasNext() ); - assertEquals(it.next(), "aaronz"); - assertTrue( it.hasNext() ); - assertEquals(it.next(), "beckyz"); - assertTrue( it.hasNext() ); - assertEquals(it.next(), "cat"); - assertFalse( it.hasNext() ); - try { - it.next(); - fail("should have died"); - } catch (NoSuchElementException e) { - assertNotNull(e.getMessage()); - } - - // test remove - it = values.iterator(); - it.next(); - it.next(); - it.remove(); - assertEquals(2, values.size()); - assertEquals(2, m1.size()); - - // test remove all - values.clear(); - assertEquals(0, values.size()); - assertTrue(values.isEmpty()); - assertEquals(0, m1.size()); - assertTrue(m1.isEmpty()); - } - - /** - * Test method for {@link org.sakaiproject.entitybroker.util.map.OrderedMap#entrySet()}. - */ - public void testEntrySet() { - Set> entries = m1.entrySet(); - assertEquals(3, entries.size()); - Iterator> it = entries.iterator(); - assertTrue( it.hasNext() ); - assertEquals(it.next().getKey(), "AAA"); - assertTrue( it.hasNext() ); - assertEquals(it.next().getKey(), "BBB"); - assertTrue( it.hasNext() ); - assertEquals(it.next().getKey(), "CCC"); - assertFalse( it.hasNext() ); - try { - it.next(); - fail("should have died"); - } catch (NoSuchElementException e) { - assertNotNull(e.getMessage()); - } - - // test remove - it = entries.iterator(); - it.next(); - it.next(); - it.remove(); - assertEquals(2, entries.size()); - assertEquals(2, m1.size()); - - // test remove all - entries.clear(); - assertEquals(0, entries.size()); - assertTrue(entries.isEmpty()); - assertEquals(0, m1.size()); - assertTrue(m1.isEmpty()); - } - -}