Java tutorial
// // Copyright (c) 2014 VK.com // // Permission is hereby granted, free of charge, to any person obtaining a copy of // this software and associated documentation files (the "Software"), to deal in // the Software without restriction, including without limitation the rights to // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of // the Software, and to permit persons to whom the Software is furnished to do so, // subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // package vk.model; import com.fasterxml.jackson.databind.JsonNode; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.ListIterator; import java.util.regex.Pattern; /** * Universal data list for VK API. * This class is not thread-safe. * @param <T> type of stored values. * @see <a href="http://vk.com/dev/list">http://vk.com/dev/list</a> */ @SuppressWarnings({ "unchecked", "UnusedDeclaration" }) public class VKList<T extends VKApiModel & Identifiable> extends VKApiModel implements java.util.List<T> { /** * The server did not return the count field. */ private final static int NO_COUNT = -1; /** * Decorated list */ private ArrayList<T> items = new ArrayList<T>(); /** * Field {@code count} which returned by server. */ private int count = NO_COUNT; /** * Creates empty list. */ public VKList() { } /** * Creates list and fills it according with given data. */ public VKList(java.util.List<? extends T> data) { assert data != null; items = new ArrayList<T>(data); } /** * Creates list and fills it according with data in {@code from}. * @param from an object that represents a list adopted in accordance with VK API format. You can use null. * @param clazz class represents a model that has a public constructor with {} argument. */ public VKList(JsonNode from, Class<? extends T> clazz) { fill(from, clazz); } /** * Fills list according with data in {@code from}. * @param from an object that represents a list adopted in accordance with VK API format. You can use null. * @param clazz class represents a model that has a public constructor with {} argument. */ public void fill(JsonNode from, Class<? extends T> clazz) { if (from.has("response")) { JsonNode array = from.get("response"); if (array != null) { // fill(array, clazz); } else { // fill(from.get("response"), clazz); } } else { // fill(from, new ReflectParser<T>(clazz)); } } /** * Adds the element before the element with the specified id. * If an element with the specified id is not found, adds an element to the end of the list. * @param id element identifier to add element before it. * @param data element to add */ public void addBefore(int id, T data) { int size = size(); for (int i = 0; i < size; i++) { if (get(i).getId() > id || i == size - 1) { add(i, data); break; } } } /** * Adds the element after the element with the specified id. * If an element with the specified id is not found, adds an element to the end of the list. * @param id element identifier to add element after it. * @param data element to add */ public void addAfter(int id, T data) { int size = size(); for (int i = 0; i < size; i++) { if (get(i).getId() > id || i == size - 1) { add(i + 1, data); break; } } } /** * Returns element according with id. * If nothing found, returns null. */ public T getById(int id) { for (T item : this) { if (item.getId() == id) { return item; } } return null; } /** * Searches through the list of available items. <br /> * <br /> * The search will be carried out not by the content of characters per line, and the content of them in separate words. <br /> * <br /> * Search is not case sensitive. <br /> * <br /> * To support search class {@code T} must have overridden method {@link #toString()}, * search will be carried out exactly according to the result of calling this method. <br /> * <br /> * <br /> * Suppose there are elements in the list of contents: * <code><pre> * - Hello world * - Hello test * </pre></code> * In this case, the matches will be on search phrases {@code 'Hel'}, {@code 'Hello'}, {@code 'test'}, but not on {@code 'llo'}, {@code 'llo world'} * * @param query search query can not be equal to {@code null}, but can be an empty string. * @return created based on the search results new list. If no matches are found, the list will be empty. */ public VKList<T> search(String query) { VKList<T> result = new VKList<T>(); final Pattern pattern = Pattern.compile("(?i).*\\b" + query + ".*"); for (T item : this) { if (pattern.matcher(item.toString()).find()) { result.add(item); } } return result; } /** * Returns the return value of the field VK API {@code count}, if it has been returned, and the size of the list, if not. */ public int getCount() { return count != NO_COUNT ? count : size(); } @Override public void add(int location, T object) { items.add(location, object); } @Override public boolean add(T object) { return items.add(object); } @Override public boolean addAll(int location, Collection<? extends T> collection) { return items.addAll(location, collection); } @Override public boolean addAll(Collection<? extends T> collection) { return items.addAll(collection); } @Override public void clear() { items.clear(); } @Override public boolean contains(Object object) { return items.contains(object); } @Override public boolean containsAll(Collection<?> collection) { assert collection != null; return items.containsAll(collection); } @Override public boolean equals(Object object) { return ((Object) this).getClass().equals(object.getClass()) && items.equals(object); } @Override public T get(int location) { return items.get(location); } @Override public int indexOf(Object object) { return items.indexOf(object); } @Override public boolean isEmpty() { return items.isEmpty(); } @Override public Iterator<T> iterator() { return items.iterator(); } @Override public int lastIndexOf(Object object) { return items.lastIndexOf(object); } @Override public ListIterator<T> listIterator() { return items.listIterator(); } @Override public ListIterator<T> listIterator(int location) { return items.listIterator(location); } @Override public T remove(int location) { return items.remove(location); } @Override public boolean remove(Object object) { return items.remove(object); } @Override public boolean removeAll(Collection<?> collection) { assert collection != null; return items.removeAll(collection); } @Override public boolean retainAll(Collection<?> collection) { return items.retainAll(collection); } @Override public T set(int location, T object) { return items.set(location, object); } @Override public int size() { return items.size(); } @Override public java.util.List<T> subList(int start, int end) { return items.subList(start, end); } @Override public Object[] toArray() { return items.toArray(); } @Override public <T1> T1[] toArray(T1[] array) { assert array != null; return items.toArray(array); } public int describeContents() { return 0; } /** * Used when parsing the list objects as interator created from {} a instances of items of the list. * @param <D> list item type. */ public static interface Parser<D> { /** * Creates a list item of its representation return VK API from {} * @param source representation of the object in the format returned by VK API. * @return created element to add to the list. * @throws Exception if the exception is thrown, the element iterated this method will not be added to the list. */ D parseObject(JsonNode source) throws Exception; } /** * Parser list items using reflection mechanism. * To use an object class must have a public constructor that accepts {}. * If, during the creation of the object constructor will throw any exception, the element will not be added to the list. * @param <D> list item type. */ public final static class ReflectParser<D extends VKApiModel> implements Parser<D> { private final Class<? extends D> clazz; public ReflectParser(Class<? extends D> clazz) { this.clazz = clazz; } @Override public D parseObject(JsonNode source) throws Exception { try { Constructor<? extends D> jsonConstructor = clazz.getConstructor(JsonNode.class); if (jsonConstructor != null) { return jsonConstructor.newInstance(source); } } catch (Exception ignored) { //Ignored. Try default constructor } return (D) clazz.newInstance(); } } // public void parse(JsonNode response) { public VKApiModel parse(JsonNode response) { // throw new JSONException("Operation is not supported while class is generic"); return new VKApiUser(); } }