I have recently tried programming various versions of Iterator and Observer Patterns in Java, but currently I'm stuck at the implementation of both in one project:
What I'm trying to accomplish is to iterate through an ArrayList, which contains elements of type and after each iteration-process to inform the Observer about the change and the containing element.
Also I want to be able to choose the "type" of iterator in my separate classes
Edit: I finally finished the project, hopefully this is the correct version of a "Observer Iterator", any tips on how to improve the code are greatly appreciated, but thanks to everybodys' encouraging tips.
Code:
First of all, the helper class for the Observer interface, which implements the update method. Changes with every iteration process and prints out the element.
package iteratorObserver;
import java.util.List;
public class ConcreteObserver implements Observer{
#Override
public void update(String element) {
System.out.println("The current element is: " + element);
}
}
The actual Observer interface:
package iteratorObserver;
public interface Observer<E> {
void update(String element);
}
Following that, the same by using a ConcreteSubject and an abstract class Subject
The observer pattern requires the getState and setState, so I integrated both into the next method. Getting the element by iterator.next aswell as setting it.
package iteratorObserver;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ConcreteSubject<E> extends Subject implements IteratorStandardFilter<E>{
List<String> listElements = new ArrayList<String>();
private int index;
private Iterator<E> iterator;
public ConcreteSubject(Iterator<E> iterator, List<String> listElements){
index = 0;
this.iterator = iterator;
this.listElements = listElements;
}
public void addElement(String element) {
listElements.add(element);
notifyObservers(element);
}
// check the size of the elements list and return if there are still
// elements left out
#Override
public boolean hasNext() {
if ((listElements.size() == index))
return false;
return true;
}
// iterate to the next element, not sure if it's overridden, since the
// actual next method of the iterator is still in use
#Override
public E next() {
E result = iterator.next();
index++;
notifyObservers((String) result);
return result;
}
}
Subject class, only used for the standard observer methods
package iteratorObserver;
import java.util.ArrayList;
import java.util.List;
public class Subject {
public List<Observer> listObservers = new ArrayList<Observer>();
public void addObserver(Observer observer){
listObservers.add(observer);
}
public void removeObserver(Observer observer){
listObservers.remove(observer);
}
public <E> void notifyObservers(String element){
for(Observer observerHelp : listObservers){
observerHelp.update(element);
}
}
}
Since i want to add various filters, not only the standard list-iterator, i added a class IteratorStandardFilter, as you can see here:
package iteratorObserver;
import java.util.Iterator;
public interface IteratorStandardFilter<E> extends Iterator<E> {
public boolean hasNext();
public E next();
}
And finally, the Test method, the main:
package iteratorObserver;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class iteratorObserverMain {
public static void main(String [] args){
List<String> listElements = new ArrayList<String>();
listElements.add("hello");
listElements.add("there");
listElements.add("everybody");
listElements.add("it");
listElements.add("works");
listElements.add("Thanks for your help. Nice and encouraging forum");
Iterator<String> iterator = listElements.iterator();
ConcreteSubject<String> concreteSubject = new ConcreteSubject<String>(iterator, listElements);
concreteSubject.addObserver(new ConcreteObserver());
while(concreteSubject.hasNext()){
concreteSubject.next();
}
}
}
Related
In my implementation I'm grabbing data from ElasticSearch via ElasticsearchTemplate#stream() which returns CloseableIterator<>.
I'd like to mock this method by doing:
List<MyClass> foo = new ArrayList<>(); // and then I add some elements
when(mockTemplate.stream(any(SearchQuery.class), eq(MyClass.class))
.thenReturn(foo.iterator());
but iterator() returns Iterator<MyClass> which is not CloseableIterator<MyClass> and I have no clue how to cast it or find a workaround.
org.springframework.data.util.CloseableIterator.CloseableIterator from Spring and java.util.Iterator from JDK are close enough interfaces : indeed CloseableIterator has Iterator as parent interface.
Which means that you can substitute a Iterator by a CloseableIterator but not the reverse : what you need.
While you cannot return an Iterator in your mock record, you can still convert an Iterator to a CloseableIterator. Which is not very hard thank to method delegation while it still requires a small amount of boilerplate.
Example :
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.data.util.CloseableIterator;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
#ExtendWith(MockitoExtension.class)
public class MockCloseableIteratorTest {
#Mock
ElasticsearchTemplate mockTemplateMock;
#Test
void foo() {
List<String> foo = new ArrayList<>();
// and then I add some elements
Mockito.when(mockTemplateMock.stream(any(SearchQuery.class), eq(String.class)))
.thenReturn(createCloseableIterator(foo.iterator()));
}
private <T> CloseableIterator<T> createCloseableIterator(Iterator<T> iterator) {
return new CloseableIterator<T>() {
#Override public void close() {
}
#Override public boolean hasNext() {
return iterator.hasNext();
}
#Override public T next() {
return iterator.next();
}
};
}
}
For those working on Kotlin, following will be the syntax for createCloseableIterator method:
private fun <T> createCloseableIterator(iterator: Iterator<T>): CloseableIterator<T>? =
object : CloseableIterator<T> {
override fun close() {}
override fun hasNext() = iterator.hasNext()
override fun next() = iterator.next()
override fun remove() {}
}
#MockK
private lateinit var closeableIterator: CloseableIterator<YourClass>
fun() {
every { closeableIterator.hasNext() } returnsMany listOf(true, false)
every { closeableIterator.next() } returnsMany listOf(YourClass())
}
For another Kotlin version that worked for me.
This question already has answers here:
My program keeps saying that the method cannot be resolved
(2 answers)
Closed 5 years ago.
My class Cupple needs to call the method beStored(char) of a class DataIterator that implements an interface StorableData.
Here the code of this interface StorableData :
package general_classes.cupples;
public interface StorableData {
public void beStored(char c);
}
Here the code of the implementation :
package general_classes.cupples;
public class Cupple<TYPE_OF_ELEMENTS> implements StorableData {
public void beStored(char c) {
}
}
And finally, here the code of the class DataIterator :
package general_classes.DataIteration;
public class DataIterator<StorableData> {
private StorableData root_storable_data;
public List<StorableData> iterate() {
this.root_storable_data.beStored(read_character);
}
}
Please note that I didn't write all the lines.
The problem is that the compiler tells me that he "cannot resolve the method beStored(int).
However, as you can see it, it's actually in the interface. So what's the problem ?
COMPLETE CODE.
INTERFACE :
package general_classes.cupples;
public interface StorableData {
public Cupple beStored(int c);
}
IMPLEMENTATION :
package general_classes.cupples;
import java.util.ArrayList;
public class Cupple<TYPE_OF_ELEMENTS> extends ArrayList<TYPE_OF_ELEMENTS> implements StorableData {
private int position_to_insert_element;
private int number_of_elements;
private Cupple<TYPE_OF_ELEMENTS> next_cupple;
private Cupple<TYPE_OF_ELEMENTS> current_empty_cupple;
public Cupple(int number_of_elements) {
this.position_to_insert_element = 0;
this.number_of_elements = number_of_elements;
}
public Cupple beStored(int c) {
Cupple returned_cupple = this;
if(this.position_to_insert_element > this.number_of_elements) {
this.next_cupple = returned_cupple = new Cupple<>(this.number_of_elements);
} else {
//this.add((TYPE_OF_ELEMENTS) c);
this.position_to_insert_element++;
}
return returned_cupple;
}
public Cupple next() {
return this.next_cupple;
}
}
CLASS :
package general_classes.DataIteration;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
/**
* Reads character per character some given data. Stores the character in a
* list, after having casted it in the specified type by the way.
*
* #author e1300478
*
* #param <StorableData>
* the wished type of the reading's returned elements
*/
public class DataIterator<StorableData> {
private Reader reader;
private List<StorableData> returned_elements_list;
private StorableData root_storable_data;
DataIterator(Reader reader, StorableData storable_data) {
this.reader = reader;
this.returned_elements_list = new ArrayList<>();
this.root_storable_data = storable_data;
}
public List<StorableData> iterate() throws IOException {
int read_character;
do {
read_character = this.reader.read();
StorableData storable_data = this.root_storable_data.beStored((int) read_character);
if(!this.returned_elements_list.contains(storable_data)) {
this.returned_elements_list.add(storable_data);
}
} while (read_character > -1);
return this.returned_elements_list;
}
}
The problem is that the compiler tells me that he "cannot resolve the
method beStored(int).
That simply means that you're attempting to pass an int type to the beStored method. If you look at the interface definition of this method again you'll notice that you're not obeying the contract that has been set.
public void beStored(char c);
in the code below read_character is most likely an int type rather than a character hence the error.
this.root_storable_data.beStored(read_character);
Solution
change this:
int read_character;
to this:
char read_character;
also change this:
StorableData storable_data = this.root_storable_data.beStored((int) read_character);
to this:
StorableData storable_data = this.root_storable_data.beStored(read_character);
The problem is this, in DataIterator StorableData is just a generic type, is not the class StorableData, is the same as DataIterator
The following code would compile.
public class DataIterator {
private StorableData root_storable_data;
public List<StorableData> iterate() {
char read_character='x';
this.root_storable_data.beStored(read_character);
return null;
}
}
Getting my feet wet on RxJava. I have a class that implements Iterable I want to convert to an Observable. Using Observable.from() seems easy. However I need to setup and tear-down the code that provides me the individual entries (the next() in the iterator.
When I run through the entire sequence, that's easy. I added the call to the hasNext() function and when there is no next I run the teardown. However one of the very promising operators I want to use is take(someNumber). If the taking stops before the Iterator runs out of items, the cleanup code never runs.
What can I do to get my cleanup running? If using something else than from(Iterable), I'm OK with that. I'm stuck on Java6 for now. To illustrate my predicament I created a minimal sample:
Update: Based on feedback not to mix Iterator and Iterable together, I updated the code below. To understand the original answers, the original code is in that gist.
Updated Test code (still bad):
import rx.Observable;
import rx.functions.Action0;
import rx.functions.Action1;
/**
* #author stw
*
*/
public class RXTest {
/**
* #param args
*/
public static void main(String[] args) {
ComplicatedObject co = new ComplicatedObject();
Observable<FancyObject> fancy = Observable.from(co);
// if the take is less than the elements cleanup never
// runs. If you take the take out, cleanup runs
fancy.take(3).subscribe(
new Action1<FancyObject>() {
public void call(FancyObject item) {
System.out.println(item.getName());
}
},
new Action1<Throwable>() {
public void call(Throwable error) {
System.out.println("Error encountered: " + error.getMessage());
}
},
new Action0() {
public void call() {
System.out.println("Sequence complete");
}
}
);
}
}
The fancy object:
import java.util.Date;
import java.util.UUID;
/**
* #author stw
*
*/
public class FancyObject {
private String name = UUID.randomUUID().toString();
private Date created = new Date();
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Date getCreated() {
return this.created;
}
public void setCreated(Date created) {
this.created = created;
}
}
The iterator:
import java.util.Iterator;
/**
* #author stw
*
*/
public class FancyIterator implements Iterator<FancyObject> {
private final ComplicatedObject theObject;
private int fancyCount = 0;
public FancyIterator(ComplicatedObject co) {
this.theObject = co;
}
public boolean hasNext() {
return this.theObject.hasObject(this.fancyCount);
}
public FancyObject next() {
FancyObject result = this.theObject.getOne(this.fancyCount);
this.fancyCount++;
return result;
}
}
The Iterable:
import java.util.Iterator;
import java.util.Vector;
/**
* #author stw
*
*/
public class ComplicatedObject implements Iterable<FancyObject> {
private boolean isInitialized = false;
Vector<FancyObject> allOfThem = new Vector<FancyObject>();
public Iterator<FancyObject> iterator() {
return new FancyIterator(this);
}
public boolean hasObject(int whichone) {
if (!this.isInitialized) {
this.setupAccesstoFancyObject();
}
return (whichone < this.allOfThem.size());
}
public FancyObject getOne(int whichone) {
if (!this.isInitialized) {
this.setupAccesstoFancyObject();
}
if (whichone < this.allOfThem.size()) {
return this.allOfThem.get(whichone);
}
// If we ask bejond...
this.isInitialized = false;
this.teardownAccessToFancyObjects();
return null;
}
private void setupAccesstoFancyObject() {
System.out.println("Initializing fancy objects");
for (int i = 0; i < 20; i++) {
this.allOfThem.addElement(new FancyObject());
}
this.isInitialized = true;
}
private void teardownAccessToFancyObjects() {
System.out.println("I'm doing proper cleanup here");
}
}
But the real question (thx #Andreas) seem to be:
What construct can I use to create an Observable when the underlying code need setup/teardown, especially when one expects that not all elements are pulled. The Iterable just was my first idea
Update 2: Based on Dave's answer I created a gist with my working solution. The iterator isn't perfect, but it's a start.
Observable.using is used for tearing down on termination (completion or error) or unsubscription. To use it you need to make the tear-down code accessible so that your source observable can look like this:
source = Observable.using(
resourceFactory,
observableFactory,
resourceDisposer);
With your code it might look like this:
source = Observable.using(
() -> new ComplicatedObject(),
co -> Observable.from(co),
co -> co.tearDown());
If you want that kind of control you need to separate the implementation of Iterable from Iterator. Iterable means the class can provide an Iterator that is meaningful in whatever fashion makes sense for the class.
However, if you implement Iterator in the same class, then you are stuck with only ever having one Iterator for each instance of ComplicatedObject. The correct approach is to implement
class FancyObjectIterator implements Iterator<FancyObject>
{
...
}
separately from ComplicatedObject so you can merely discard the partially-used iterators when you are done with them. ComplicatedObject should implement only Iterable<FancyObject>.
If you object to that approach because the iterator has more state that needs special cleanup, then something is wrong with your design. The only state an Iterator should be aware of is the current position in the base "collection", for a very loose definition of "collection" and "position" since the concept of an iterator can apply to much more than typical collections.
You cannot implement Iterator and Iterable at the same time, since Iterable.iterator() must return a new Iterator or every call.
Code is allowed to iterate the same Iterable multiple times in parallel.
Example: An over-simplified way to find duplicate elements in an Iterable:
Iterable<MyObject> myIterable = ...;
for (MyObject myObj1 : myIterable) {
for (MyObject myObj2 : myIterable) {
if (myObj1 != myObj2 && myObj1.equals(myObj2)) {
// found duplicate
}
}
}
The enhanced for loops used here will each use an Iterator.
As you can see, each Iterator must maintain it's own independent position. Therefore, the iterator() method needs to return a new object, with it's own state.
And for your question on cleanup code, an Iterator does not have a close() method. Iterator state should not require cleanup. If they absolutely must, a finalizer can do it, but finalizers may take a very long time to be invoked. The general recommendation for finalizers is: DON'T.
I also need to store the time stamp inside the list when the log message is pushed into the list.So how can we get the timestamp and push into the list.I am pushing the logs into the list as follows
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.RollingFileAppender;
//import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.spi.LoggingEvent;
public class Listappender extends RollingFileAppender {
private List<LoggingEvent> events = new ArrayList<LoggingEvent>();
static List<String> clone = new ArrayList<String>();
#Override
public synchronized void doAppend(LoggingEvent event) {
//System.out.println("hi....");
//events.clear();
events.add(event);
super.doAppend(event);
clone.clear();
clone.add((String) event.getMessage());
//getEvents();
/*
for (int j = 0; j < events.size(); j++){
System.out.println(events.get(j));
System.out.println(j);
}*/
}
public List<String> getEntries()
{
return clone;
}
}
See how to create timestamp Java Timestamp - How can I create a Timestamp with the date 23/09/2007?
And you can simply do this
clone.add(timestamp.toString() + event.getMessage());
Just keep the LoggingEvent s in a list. You don't have to get the message and save it in a different list. The LoggingEvent has a public final long getTimeStamp() method to supply the time. Try using this code:
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.RollingFileAppender;
import org.apache.log4j.spi.LoggingEvent;
public class ListAppender extends RollingFileAppender {
private final List<LoggingEvent> events = new ArrayList<LoggingEvent>();
#Override
public synchronized void doAppend(LoggingEvent event) {
events.add(event);
super.doAppend(event);
}
public synchronized List<LoggingEvent> getLoggingEvents() {
List<LoggingEvent> clone = new ArrayList<>(events);
events.clear();
return clone;
}
}
What's it all about
Hi everyone - I was looking at a presentation called "Have your cake and eat it too: Meta-programming in Java"
The presenter was Howard M. Lewis Ship, (one?) of the authors of Tapestry - and in making that, a subproject called "plastic" was made to leverage ASM to alter the bytecode.
I won't pretend to be an expert, but the end-result should be that I can write code such that annotated classes, methods and fields can be used to generate further java code thus cutting down on boilerplate code.
My Question
The code below is a complete example to demonstrate my problem. The test example should modify the EqualsDemo class such that it contains implementations of equals() and hashCode().
When running it I get an error which basically states that I can't cast an object of type 'com.example.plastic.transformed.EqualsDemo' to 'com.example.plastic.transformed.EqualsDemo' (yes, the same class).
The presenter just mentioned that these errors were annoying without alluding to where they stem from - my searching so far indicates that they pertain to different class loaders.
I have, however, been completely unable to fix the problem, hence my question here(!)
com.example.plastic.transformed.EqualsDemo cannot be cast to com.example.plastic.transformed.EqualsDemo
at MainClass.main(MainClass.java:28)
So what do I need to do ? Replace class loaders ? (if so, how?) or is there some part of Plastic I don't get ? Some method for generating proxy objects or similar that I need to use for things to go smoothly ?
PS!
The examples I've found so far all use what I think is Groovy in the final use of the annotated instances.
Hopefully someone are more competent than I :)
Links:
Tapestry Homepage (plastic is contained as a jar in the download): http://tapestry.apache.org/
Main.java
import java.util.ArrayList;
import java.util.List;
import org.apache.tapestry5.internal.plastic.StandardDelegate;
import org.apache.tapestry5.plastic.ClassInstantiator;
import org.apache.tapestry5.plastic.PlasticManager;
import com.example.plastic.transformer.EqualsHashCodeTransformer;
import com.example.plastic.transformed.EqualsDemo;
public class MainClass {
public static void main(String[] args) {
List<String> pList = new ArrayList<String>();
pList.add("com.example.plastic.transformed");
PlasticManager pm = PlasticManager
.withContextClassLoader()
.delegate( new StandardDelegate(new EqualsHashCodeTransformer()) )
.packages(pList)
.create();
final String EQUALSDEMO = "com.example.plastic.transformed.EqualsDemo";
ClassInstantiator<EqualsDemo> i = pm.getClassInstantiator(EQUALSDEMO);
i.newInstance().hashCode();
/*
com.example.plastic.transformed.EqualsDemo cannot be cast to com.example.plastic.transformed.EqualsDemo
at MainClass.main(MainClass.java:28)
*/
}
}
ImplementEqualsHashCode.java
package com.example.plastic.annotations;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.*;
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Documented
public #interface ImplementEqualsHashCode {
}
EqualsHashCodeTransformer.java
package com.example.plastic.transformer;
import java.util.ArrayList;
import java.util.List;
import org.apache.tapestry5.plastic.FieldHandle;
import org.apache.tapestry5.plastic.MethodAdvice;
import org.apache.tapestry5.plastic.MethodDescription;
import org.apache.tapestry5.plastic.MethodInvocation;
import org.apache.tapestry5.plastic.PlasticClass;
import org.apache.tapestry5.plastic.PlasticClassTransformer;
import org.apache.tapestry5.plastic.PlasticField;
import com.example.plastic.annotations.*;
public class EqualsHashCodeTransformer implements PlasticClassTransformer {
private MethodDescription EQUALS = new MethodDescription("boolean", "equals", "java.lang.Object");
private MethodDescription HASHCODE = new MethodDescription("int", "hashCode");
private static final int PRIME = 37;
public void transform(PlasticClass plasticClass){
//check that the class is annotated
if(!plasticClass.hasAnnotation(ImplementEqualsHashCode.class)) {
return;
}
List<PlasticField> fields = plasticClass.getAllFields();
final List<FieldHandle> handles = new ArrayList<FieldHandle>();
for(PlasticField field : fields){
handles.add(field.getHandle());
}
//HashCode method introduction :)
plasticClass.introduceMethod(HASHCODE).addAdvice(new MethodAdvice() {
public void advise(MethodInvocation invocation){
Object instance = invocation.getInstance();
int result = 1;
for(FieldHandle handle : handles){
Object fieldValue = handle.get(instance);
if(fieldValue != null)
result = (result * PRIME) + fieldValue.hashCode();
}
invocation.setReturnValue(result);
//Don't proceed to the empty introduced method
}
});
plasticClass.introduceMethod(EQUALS).addAdvice(new MethodAdvice() {
public void advise(MethodInvocation invocation) {
Object thisInstance = invocation.getInstance();
Object otherInstance = invocation.getParameter(0);
invocation.setReturnValue(isEqual(thisInstance, otherInstance));
//Don't proceed to the empty introduced method
}
private boolean isEqual(Object thisInstance, Object otherInstance) {
if(thisInstance == otherInstance)
return true;
if(otherInstance == null)
return false;
if(!(thisInstance.getClass() == otherInstance.getClass()))
return false;
for(FieldHandle handle : handles){
Object thisValue = handle.get(thisInstance);
Object otherValue = handle.get(otherInstance);
if(!(thisValue == otherValue || thisValue.equals(otherValue)))
return false;
}
return true;
}
});
}
}
EqualsDemo.java
package com.example.plastic.transformed;
import com.example.plastic.annotations.ImplementEqualsHashCode;
#ImplementEqualsHashCode
public class EqualsDemo {
private int intValue;
private String stringValue;
public int getIntValue(){
return intValue;
}
public void setIntValue(int intValue){
this.intValue = intValue;
}
public String getStringValue(){
return stringValue;
}
public void setStringValue(String stringValue){
this.stringValue = stringValue;
}
}
you don't want to add the packages to the plastic manager -- it uses a different classloader and will load those classes, making two copies of the classes in those packages (one in the parent classloader and one in the plastic classloader) which will give you the ClassCastException you are seeing when the framework tries to cast to your class. Try this instead:
import org.apache.tapestry5.internal.plastic.StandardDelegate;
import org.apache.tapestry5.plastic.ClassInstantiator;
import org.apache.tapestry5.plastic.PlasticManager;
public class MainClass {
public static void main(String[] args) {
PlasticManager pm = PlasticManager
.withContextClassLoader()
.delegate(new StandardDelegate())
.create();
ClassInstantiator<EqualsDemo> ci = pm.createClass(EqualsDemo.class, new EqualsHashCodeTransformer());
System.out.println(ci.newInstance().hashCode());
}
}
I guess instead of
PlasticManager.withContextClassLoader()...
using the following should fix your problem:
PlasticManager.withClassLoader(getClass().getClassLoader())...