/***************************************************************** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.apache.cayenne.access.types; import org.apache.cayenne.util.IDUtil; import java.lang.reflect.Array; /** * A factory that dynamically creates ExtendedTypes for Character, Character[], Byte[] and * char[] based on adapter configured types for String and byte[]. * * @since 3.0 */ class ByteOrCharArrayFactory implements ExtendedTypeFactory { private ExtendedTypeMap map; ByteOrCharArrayFactory(ExtendedTypeMap map) { this.map = map; } @SuppressWarnings("unchecked") public ExtendedType getType(Class<?> objectClass) { if (objectClass.isArray()) { Class<?> elementType = objectClass.getComponentType(); if (Character.class.isAssignableFrom(elementType)) { // can't use "getRegisteredType" as it causes infinite recursion ExtendedType<String> stringType = map.getExplictlyRegisteredType("java.lang.String"); return new CharacterArrayType(stringType); } else if (Character.TYPE.isAssignableFrom(elementType)) { // can't use "getRegisteredType" as it causes infinite recursion ExtendedType<String> stringType = map.getExplictlyRegisteredType("java.lang.String"); return new CharArrayType(stringType); } else if (Byte.class.isAssignableFrom(elementType)) { // can't use "getRegisteredType" as it causes infinite recursion ExtendedType<byte[]> bytesType = map.getExplictlyRegisteredType("byte[]"); return new ByteWrapperArrayType(bytesType); } } else if (Character.class.isAssignableFrom(objectClass)) { // can't use "getRegisteredType" as it causes infinite recursion ExtendedType<String> stringType = map.getExplictlyRegisteredType("java.lang.String"); return new CharacterType(stringType); } return null; } final class CharacterType extends ExtendedTypeDecorator<Character, String> { CharacterType(ExtendedType<String> stringType) { super(stringType); } @Override public String getClassName() { return "java.lang.Character"; } @Override String fromJavaObject(Character object) { return object != null ? String.valueOf(object.charValue()) : null; } @Override Character toJavaObject(String string) { if (string == null) { return null; } return (string.length() > 0) ? string.charAt(0) : null; } } final class CharArrayType extends ExtendedTypeDecorator<char[], String> { CharArrayType(ExtendedType<String> stringType) { super(stringType); } @Override public String getClassName() { return "char[]"; } @Override String fromJavaObject(char[] object) { return object != null ? new String(object) : null; } @Override char[] toJavaObject(String object) { return object != null ? object.toCharArray() : null; } @Override public String toString(char[] value) { if (value == null) { return "NULL"; } StringBuilder buffer = new StringBuilder(); buffer.append("< "); int len = Array.getLength(value); boolean trimming = false; if (len > TRIM_VALUES_THRESHOLD) { len = TRIM_VALUES_THRESHOLD; trimming = true; } for (int i = 0; i < len; i++) { if (i > 0) { buffer.append(","); } buffer.append(Array.get(value, i)); } if (trimming) { buffer.append("..."); } buffer.append('>'); return buffer.toString(); } } final class CharacterArrayType extends ExtendedTypeDecorator<Character[], String> { CharacterArrayType(ExtendedType<String> stringType) { super(stringType); } @Override public String getClassName() { return "java.lang.Character[]"; } @Override String fromJavaObject(Character[] object) { if (object == null) { return null; } StringBuilder buffer = new StringBuilder(object.length); for (Character aChar : object) { buffer.append(aChar != null ? aChar : 0); } return buffer.toString(); } @Override Character[] toJavaObject(String object) { if (object == null) { return null; } Character[] chars = new Character[object.length()]; for (int i = 0; i < object.length(); i++) { chars[i] = object.charAt(i); } return chars; } @Override public String toString(Character[] value) { if (value == null) { return "NULL"; } StringBuilder buffer = new StringBuilder(); buffer.append("< "); int len = Array.getLength(value); boolean trimming = false; if (len > TRIM_VALUES_THRESHOLD) { len = TRIM_VALUES_THRESHOLD; trimming = true; } for (int i = 0; i < len; i++) { if (i > 0) { buffer.append(","); } buffer.append(Array.get(value, i)); } if (trimming) { buffer.append("..."); } buffer.append('>'); return buffer.toString(); } } final class ByteWrapperArrayType extends ExtendedTypeDecorator<Byte[], byte[]> { ByteWrapperArrayType(ExtendedType<byte[]> byteArrayType) { super(byteArrayType); } @Override public String getClassName() { return "java.lang.Byte[]"; } @Override byte[] fromJavaObject(Byte[] bytes) { if (bytes == null) { return null; } byte[] buffer = new byte[bytes.length]; for (int i = 0; i < bytes.length; i++) { buffer[i] = bytes[i] != null ? bytes[i] : 0; } return buffer; } @Override Byte[] toJavaObject(byte[] bytes) { if (bytes == null) { return null; } Byte[] byteWrappers = new Byte[bytes.length]; for (int i = 0; i < bytes.length; i++) { byteWrappers[i] = bytes[i]; } return byteWrappers; } @Override public String toString(Byte[] value) { if (value == null) { return "NULL"; } StringBuilder buffer = new StringBuilder(); buffer.append("< "); int len = value.length; boolean trimming = false; if (len > TRIM_VALUES_THRESHOLD) { len = TRIM_VALUES_THRESHOLD; trimming = true; } for (int i = 0; i < len; i++) { if (i > 0) { buffer.append(","); } IDUtil.appendFormattedByte(buffer, value[i]); } if (trimming) { buffer.append("..."); } buffer.append('>'); return buffer.toString(); } } }