/*
* 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.flink.streaming.util.typeutils;
import static org.junit.Assert.*;
import org.apache.flink.api.common.typeinfo.BasicArrayTypeInfo;
import org.apache.flink.api.common.typeinfo.BasicTypeInfo;
import org.apache.flink.api.common.typeinfo.PrimitiveArrayTypeInfo;
import org.apache.flink.api.common.typeinfo.TypeInformation;
import org.apache.flink.api.common.typeutils.CompositeType;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.api.java.tuple.Tuple3;
import org.apache.flink.api.java.typeutils.PojoTypeInfo;
import org.apache.flink.api.java.typeutils.TupleTypeInfo;
import org.apache.flink.api.java.typeutils.TypeExtractor;
import org.junit.Test;
public class FieldAccessorTest {
// Note, that AggregationFunctionTest indirectly also tests FieldAccessors.
// ProductFieldAccessors are tested in CaseClassFieldAccessorTest.
@Test
public void testFlatTuple() {
Tuple2<String, Integer> t = Tuple2.of("aa", 5);
TupleTypeInfo<Tuple2<String, Integer>> tpeInfo =
(TupleTypeInfo<Tuple2<String, Integer>>) TypeExtractor.getForObject(t);
FieldAccessor<Tuple2<String, Integer>, String> f0 = FieldAccessorFactory.getAccessor(tpeInfo, "f0", null);
assertEquals("aa", f0.get(t));
assertEquals("aa", t.f0);
t = f0.set(t, "b");
assertEquals("b", f0.get(t));
assertEquals("b", t.f0);
FieldAccessor<Tuple2<String, Integer>, Integer> f1 = FieldAccessorFactory.getAccessor(tpeInfo, "f1", null);
assertEquals(5, (int) f1.get(t));
assertEquals(5, (int) t.f1);
t = f1.set(t, 7);
assertEquals(7, (int) f1.get(t));
assertEquals(7, (int) t.f1);
assertEquals("b", f0.get(t));
assertEquals("b", t.f0);
FieldAccessor<Tuple2<String, Integer>, Integer> f1n = FieldAccessorFactory.getAccessor(tpeInfo, 1, null);
assertEquals(7, (int) f1n.get(t));
assertEquals(7, (int) t.f1);
t = f1n.set(t, 10);
assertEquals(10, (int) f1n.get(t));
assertEquals(10, (int) f1.get(t));
assertEquals(10, (int) t.f1);
assertEquals("b", f0.get(t));
assertEquals("b", t.f0);
FieldAccessor<Tuple2<String, Integer>, Integer> f1ns = FieldAccessorFactory.getAccessor(tpeInfo, "1", null);
assertEquals(10, (int) f1ns.get(t));
assertEquals(10, (int) t.f1);
t = f1ns.set(t, 11);
assertEquals(11, (int) f1ns.get(t));
assertEquals(11, (int) f1.get(t));
assertEquals(11, (int) t.f1);
assertEquals("b", f0.get(t));
assertEquals("b", t.f0);
// This is technically valid (the ".0" is selecting the 0th field of a basic type).
FieldAccessor<Tuple2<String, Integer>, String> f0_0 = FieldAccessorFactory.getAccessor(tpeInfo, "f0.0", null);
assertEquals("b", f0_0.get(t));
assertEquals("b", t.f0);
t = f0_0.set(t, "cc");
assertEquals("cc", f0_0.get(t));
assertEquals("cc", t.f0);
}
@Test(expected = CompositeType.InvalidFieldReferenceException.class)
public void testIllegalFlatTuple() {
Tuple2<String, Integer> t = Tuple2.of("aa", 5);
TupleTypeInfo<Tuple2<String, Integer>> tpeInfo =
(TupleTypeInfo<Tuple2<String, Integer>>) TypeExtractor.getForObject(t);
FieldAccessorFactory.getAccessor(tpeInfo, "illegal", null);
}
@Test
public void testTupleInTuple() {
Tuple2<String, Tuple3<Integer, Long, Double>> t = Tuple2.of("aa", Tuple3.of(5, 9L, 2.0));
TupleTypeInfo<Tuple2<String, Tuple3<Integer, Long, Double>>> tpeInfo =
(TupleTypeInfo<Tuple2<String, Tuple3<Integer, Long, Double>>>)TypeExtractor.getForObject(t);
FieldAccessor<Tuple2<String, Tuple3<Integer, Long, Double>>, String> f0 = FieldAccessorFactory
.getAccessor(tpeInfo, "f0", null);
assertEquals("aa", f0.get(t));
assertEquals("aa", t.f0);
FieldAccessor<Tuple2<String, Tuple3<Integer, Long, Double>>, Double> f1f2 = FieldAccessorFactory
.getAccessor(tpeInfo, "f1.f2", null);
assertEquals(2.0, f1f2.get(t), 0);
assertEquals(2.0, t.f1.f2, 0);
t = f1f2.set(t, 3.0);
assertEquals(3.0, f1f2.get(t), 0);
assertEquals(3.0, t.f1.f2, 0);
assertEquals("aa", f0.get(t));
assertEquals("aa", t.f0);
FieldAccessor<Tuple2<String, Tuple3<Integer, Long, Double>>, Tuple3<Integer, Long, Double>> f1 =
FieldAccessorFactory.getAccessor(tpeInfo, "f1", null);
assertEquals(Tuple3.of(5, 9L, 3.0), f1.get(t));
assertEquals(Tuple3.of(5, 9L, 3.0), t.f1);
t = f1.set(t, Tuple3.of(8, 12L, 4.0));
assertEquals(Tuple3.of(8, 12L, 4.0), f1.get(t));
assertEquals(Tuple3.of(8, 12L, 4.0), t.f1);
assertEquals("aa", f0.get(t));
assertEquals("aa", t.f0);
FieldAccessor<Tuple2<String, Tuple3<Integer, Long, Double>>, Tuple3<Integer, Long, Double>> f1n =
FieldAccessorFactory.getAccessor(tpeInfo, 1, null);
assertEquals(Tuple3.of(8, 12L, 4.0), f1n.get(t));
assertEquals(Tuple3.of(8, 12L, 4.0), t.f1);
t = f1n.set(t, Tuple3.of(10, 13L, 5.0));
assertEquals(Tuple3.of(10, 13L, 5.0), f1n.get(t));
assertEquals(Tuple3.of(10, 13L, 5.0), f1.get(t));
assertEquals(Tuple3.of(10, 13L, 5.0), t.f1);
assertEquals("aa", f0.get(t));
assertEquals("aa", t.f0);
}
@Test(expected = CompositeType.InvalidFieldReferenceException.class)
@SuppressWarnings("unchecked")
public void testIllegalTupleField() {
FieldAccessorFactory.getAccessor(TupleTypeInfo.getBasicTupleTypeInfo(Integer.class, Integer.class), 2, null);
}
public static class Foo {
public int x;
public Tuple2<String, Long> t;
public Short y;
public Foo() {}
public Foo(int x, Tuple2<String, Long> t, Short y) {
this.x = x;
this.t = t;
this.y = y;
}
}
@Test
public void testTupleInPojoInTuple() {
Tuple2<String, Foo> t = Tuple2.of("aa", new Foo(8, Tuple2.of("ddd", 9L), (short) 2));
TupleTypeInfo<Tuple2<String, Foo>> tpeInfo =
(TupleTypeInfo<Tuple2<String, Foo>>) TypeExtractor.getForObject(t);
FieldAccessor<Tuple2<String, Foo>, Long> f1tf1 = FieldAccessorFactory.getAccessor(tpeInfo, "f1.t.f1", null);
assertEquals(9L, (long) f1tf1.get(t));
assertEquals(9L, (long) t.f1.t.f1);
t = f1tf1.set(t, 12L);
assertEquals(12L, (long) f1tf1.get(t));
assertEquals(12L, (long) t.f1.t.f1);
FieldAccessor<Tuple2<String, Foo>, String> f1tf0 = FieldAccessorFactory.getAccessor(tpeInfo, "f1.t.f0", null);
assertEquals("ddd", f1tf0.get(t));
assertEquals("ddd", t.f1.t.f0);
t = f1tf0.set(t, "alma");
assertEquals("alma", f1tf0.get(t));
assertEquals("alma", t.f1.t.f0);
FieldAccessor<Tuple2<String, Foo>, Foo> f1 = FieldAccessorFactory.getAccessor(tpeInfo, "f1", null);
FieldAccessor<Tuple2<String, Foo>, Foo> f1n = FieldAccessorFactory.getAccessor(tpeInfo, 1, null);
assertEquals(Tuple2.of("alma", 12L), f1.get(t).t);
assertEquals(Tuple2.of("alma", 12L), f1n.get(t).t);
assertEquals(Tuple2.of("alma", 12L), t.f1.t);
Foo newFoo = new Foo(8, Tuple2.of("ddd", 9L), (short) 2);
f1.set(t, newFoo);
assertEquals(newFoo, f1.get(t));
assertEquals(newFoo, f1n.get(t));
assertEquals(newFoo, t.f1);
}
@Test(expected = CompositeType.InvalidFieldReferenceException.class)
public void testIllegalTupleInPojoInTuple() {
Tuple2<String, Foo> t = Tuple2.of("aa", new Foo(8, Tuple2.of("ddd", 9L), (short) 2));
TupleTypeInfo<Tuple2<String, Foo>> tpeInfo =
(TupleTypeInfo<Tuple2<String, Foo>>) TypeExtractor.getForObject(t);
FieldAccessorFactory.getAccessor(tpeInfo, "illegal.illegal.illegal", null);
}
public static class Inner {
public long x;
public boolean b;
public Inner(){}
public Inner(long x) {
this.x = x;
}
public Inner(long x, boolean b) {
this.x = x;
this.b = b;
}
@Override
public String toString() {
return ((Long)x).toString() + ", " + b;
}
}
public static class Outer {
public int a;
public Inner i;
public short b;
public Outer(){}
public Outer(int a, Inner i, short b) {
this.a = a;
this.i = i;
this.b = b;
}
@Override
public String toString() {
return a+", "+i.toString()+", "+b;
}
}
@Test
public void testPojoInPojo() {
Outer o = new Outer(10, new Inner(4L), (short)12);
PojoTypeInfo<Outer> tpeInfo = (PojoTypeInfo<Outer>) TypeInformation.of(Outer.class);
FieldAccessor<Outer, Long> fix = FieldAccessorFactory.getAccessor(tpeInfo, "i.x", null);
assertEquals(4L, (long) fix.get(o));
assertEquals(4L, o.i.x);
o = fix.set(o, 22L);
assertEquals(22L, (long) fix.get(o));
assertEquals(22L, o.i.x);
FieldAccessor<Outer, Inner> fi = FieldAccessorFactory.getAccessor(tpeInfo, "i", null);
assertEquals(22L, fi.get(o).x);
assertEquals(22L, (long) fix.get(o));
assertEquals(22L, o.i.x);
o = fi.set(o, new Inner(30L));
assertEquals(30L, fi.get(o).x);
assertEquals(30L, (long) fix.get(o));
assertEquals(30L, o.i.x);
}
@Test
@SuppressWarnings("unchecked")
public void testArray() {
int[] a = new int[]{3,5};
FieldAccessor<int[], Integer> fieldAccessor =
(FieldAccessor<int[], Integer>) (Object)
FieldAccessorFactory.getAccessor(PrimitiveArrayTypeInfo.getInfoFor(a.getClass()), 1, null);
assertEquals(Integer.class, fieldAccessor.getFieldType().getTypeClass());
assertEquals((Integer)a[1], fieldAccessor.get(a));
a = fieldAccessor.set(a, 6);
assertEquals((Integer)a[1], fieldAccessor.get(a));
Integer[] b = new Integer[]{3,5};
FieldAccessor<Integer[], Integer> fieldAccessor2 =
(FieldAccessor<Integer[], Integer>) (Object)
FieldAccessorFactory.getAccessor(BasicArrayTypeInfo.getInfoFor(b.getClass()), 1, null);
assertEquals(Integer.class, fieldAccessor2.getFieldType().getTypeClass());
assertEquals(b[1], fieldAccessor2.get(b));
b = fieldAccessor2.set(b, 6);
assertEquals(b[1], fieldAccessor2.get(b));
}
public static class ArrayInPojo {
public long x;
public int[] arr;
public int y;
public ArrayInPojo() {}
public ArrayInPojo(long x, int[] arr, int y) {
this.x = x;
this.arr = arr;
this.y = y;
}
}
@Test
public void testArrayInPojo() {
ArrayInPojo o = new ArrayInPojo(10L, new int[]{3,4,5}, 12);
PojoTypeInfo<ArrayInPojo> tpeInfo = (PojoTypeInfo<ArrayInPojo>)TypeInformation.of(ArrayInPojo.class);
FieldAccessor<ArrayInPojo, Integer> fix = FieldAccessorFactory.getAccessor(tpeInfo, "arr.1", null);
assertEquals(4, (int) fix.get(o));
assertEquals(4L, o.arr[1]);
o = fix.set(o, 8);
assertEquals(8, (int) fix.get(o));
assertEquals(8, o.arr[1]);
}
@Test
public void testBasicType() {
Long x = 7L;
TypeInformation<Long> tpeInfo = BasicTypeInfo.LONG_TYPE_INFO;
FieldAccessor<Long, Long> f = FieldAccessorFactory.getAccessor(tpeInfo, 0, null);
assertEquals(7L, (long) f.get(x));
x = f.set(x, 12L);
assertEquals(12L, (long) f.get(x));
assertEquals(12L, (long) x);
FieldAccessor<Long, Long> f2 = FieldAccessorFactory.getAccessor(tpeInfo, "*", null);
assertEquals(12L, (long) f2.get(x));
x = f2.set(x, 14L);
assertEquals(14L, (long) f2.get(x));
assertEquals(14L, (long) x);
}
@Test(expected = IllegalArgumentException.class)
public void testIllegalBasicType1() {
Long x = 7L;
TypeInformation<Long> tpeInfo = BasicTypeInfo.LONG_TYPE_INFO;
FieldAccessor<Long, Long> f = FieldAccessorFactory.getAccessor(tpeInfo, 1, null);
}
@Test(expected = IllegalArgumentException.class)
public void testIllegalBasicType2() {
Long x = 7L;
TypeInformation<Long> tpeInfo = BasicTypeInfo.LONG_TYPE_INFO;
FieldAccessor<Long, Long> f = FieldAccessorFactory.getAccessor(tpeInfo, "foo", null);
}
}