I use spring boot and thymeleaf
I start with a number in a template
//want to display startNubmer +1
//want to display startNubmer +2
Is there a way to get that with thymeleaf
Finally create a java class
public class TLCounter {
private int count;
public TLCounter()
{
count = 0;
}
public TLCounter(int init)
{
count = init;
}
public int get()
{
return count;
}
public void clear()
{
count = 0;
}
public int incrementAndGet()
{
return ++count;
}
public String toString()
{
return ""+count;
}
}
Pass a variable in my thymeleaf page, and call method
<th:block th:with="counterBullet = ${counter.incrementAndGet()}">
<p th:text="${counterBullet}">1.</p>
</th:block>
Related
I have a WCF service that I want to rewrite into a gRPC service. There is a specific endpoint that gives me some trouble. Right now the method looks like this:
public List<Dictionary<string, string> GetData(GetDataRequest request)
{
List<Dictionary<string, string>> results = new List<Dictionary<string, string>>();
/// ...
/// Code that populates the results list
/// ...
return results;
}
I have composed the proto file like this:
message GetDataRequest {
string code = 1;
}
message GetDataResponse {
message KeyValuePair {
map<string, string> pairs = 1;
}
repeated KeyValuePair results= 1;
}
service Demo {
rpc GetData(GetDataRequest) returns (GetDataResponse);
}
And the service implementation:
public class DemoService : Demo.DemoBase
{
public override async Task<GetDataResponse> GetData(GetDataRequest request, ServerCallContext context)
{
List<Dictionary<string, string>> results = new List<Dictionary<string, string>>();
/// ...
/// Code that populates the results list
/// ...
return await Task.FromResult(new GetDataResponse
{
Results = results
});
}
}
My problem is when I try to return the list of dictionaries I get the this error:
What changes I need to make in order to return the response properly?
I use the Visual Studio 2019 gRPC Service template.
This is the GetDataResponse generated code from protobuf compiler:
public sealed partial class GetDataResponse : pb::IMessage<GetDataResponse>
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
, pb::IBufferMessage
#endif
{
private static readonly pb::MessageParser<GetDataResponse> _parser = new pb::MessageParser<GetDataResponse>(() => new GetDataResponse());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<GetDataResponse> Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::GrpcService.Protos.DemoReflection.Descriptor.MessageTypes[1]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public GetDataResponse() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public GetDataResponse(GetDataResponse other) : this() {
results_ = other.results_.Clone();
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public GetDataResponse Clone() {
return new GetDataResponse(this);
}
/// <summary>Field number for the "results" field.</summary>
public const int ResultsFieldNumber = 1;
private static readonly pb::FieldCodec<global::GrpcService.Protos.GetDataResponse.Types.KeyValuePair> _repeated_results_codec
= pb::FieldCodec.ForMessage(10, global::GrpcService.Protos.GetDataResponse.Types.KeyValuePair.Parser);
private readonly pbc::RepeatedField<global::GrpcService.Protos.GetDataResponse.Types.KeyValuePair> results_ = new pbc::RepeatedField<global::GrpcService.Protos.GetDataResponse.Types.KeyValuePair>();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public pbc::RepeatedField<global::GrpcService.Protos.GetDataResponse.Types.KeyValuePair> Results {
get { return results_; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as GetDataResponse);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(GetDataResponse other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if(!results_.Equals(other.results_)) return false;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
hash ^= results_.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
output.WriteRawMessage(this);
#else
results_.WriteTo(output, _repeated_results_codec);
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
#endif
}
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
results_.WriteTo(ref output, _repeated_results_codec);
if (_unknownFields != null) {
_unknownFields.WriteTo(ref output);
}
}
#endif
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
size += results_.CalculateSize(_repeated_results_codec);
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(GetDataResponse other) {
if (other == null) {
return;
}
results_.Add(other.results_);
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
input.ReadRawMessage(this);
#else
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 10: {
results_.AddEntriesFrom(input, _repeated_results_codec);
break;
}
}
}
#endif
}
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
break;
case 10: {
results_.AddEntriesFrom(ref input, _repeated_results_codec);
break;
}
}
}
}
#endif
#region Nested types
/// <summary>Container for nested types declared in the GetDataResponse message type.</summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static partial class Types {
public sealed partial class KeyValuePair : pb::IMessage<KeyValuePair>
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
, pb::IBufferMessage
#endif
{
private static readonly pb::MessageParser<KeyValuePair> _parser = new pb::MessageParser<KeyValuePair>(() => new KeyValuePair());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<KeyValuePair> Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::GrpcService.Protos.GetDataResponse.Descriptor.NestedTypes[0]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public KeyValuePair() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public KeyValuePair(KeyValuePair other) : this() {
pairs_ = other.pairs_.Clone();
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public KeyValuePair Clone() {
return new KeyValuePair(this);
}
/// <summary>Field number for the "pairs" field.</summary>
public const int PairsFieldNumber = 1;
private static readonly pbc::MapField<string, string>.Codec _map_pairs_codec
= new pbc::MapField<string, string>.Codec(pb::FieldCodec.ForString(10, ""), pb::FieldCodec.ForString(18, ""), 10);
private readonly pbc::MapField<string, string> pairs_ = new pbc::MapField<string, string>();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public pbc::MapField<string, string> Pairs {
get { return pairs_; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as KeyValuePair);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(KeyValuePair other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (!Pairs.Equals(other.Pairs)) return false;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
hash ^= Pairs.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
output.WriteRawMessage(this);
#else
pairs_.WriteTo(output, _map_pairs_codec);
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
#endif
}
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
pairs_.WriteTo(ref output, _map_pairs_codec);
if (_unknownFields != null) {
_unknownFields.WriteTo(ref output);
}
}
#endif
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
size += pairs_.CalculateSize(_map_pairs_codec);
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(KeyValuePair other) {
if (other == null) {
return;
}
pairs_.Add(other.pairs_);
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
input.ReadRawMessage(this);
#else
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 10: {
pairs_.AddEntriesFrom(input, _map_pairs_codec);
break;
}
}
}
#endif
}
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
break;
case 10: {
pairs_.AddEntriesFrom(ref input, _map_pairs_codec);
break;
}
}
}
}
#endif
}
}
#endregion
}
In ASP.NET Core gRPC for WCF developers the Repeated fields for lists and arrays section explains that
repeated fields are represented by read-only properties of the Google.Protobuf.Collections.RepeatedField type rather than any of the built-in .NET collection types. This type implements all the standard .NET collection interfaces, such as IList and IEnumerable. So you can use LINQ queries or convert it to an array or a list easily.
You'll have to use Add/AddRange to add items to that property , eg:
var response=new GetDataResponse();
response.AddRange(results);
return response;
You don't need to wrap response in a Task to return it because your method has the async signature, so it already wraps return values. In any case, await Task.FromResult(x) just returns x
I am working with a new application written to version 8 (currently testing with 8.1.0.rc2).
The issue surrounds the "select all" checkbox that appears in the header of a Grid when using SelectionMode.MULTI. In particular, the problem is that the checkbox appears and operates as expected when the DataProvider implements InMemoryDataProvider, but the checkbox does not appear when the DataProvider implements BackEndDataProvider.
The following code creates two grids that differ only in whether they use InMemory or BackEnd:
public class Test {
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
private String name;
}
public class TestView extends BaseView {
public TestView() {
super("Test");
addComponent(new TestGrid(new TestDataProvider0()));
addComponent(new TestGrid(new TestDataProvider1()));
}
}
public class TestGrid extends Grid<Test> {
public TestGrid(DataProvider<Test, ?> dataProvider) {
setHeightByRows(4);
setSelectionMode(SelectionMode.MULTI);
setDataProvider(dataProvider);
addColumn(Test::getName).setCaption("Name");
}
}
public class TestDataProvider0 extends AbstractDataProvider<Test, SerializablePredicate<Test>> implements
BackEndDataProvider<Test, SerializablePredicate<Test>> {
public Stream<Test> fetch(Query<Test, SerializablePredicate<Test>> query) {
List<Test> tests = new ArrayList<>(query.getLimit());
for (int i = 0; i < query.getLimit(); i++) {
Test test = new Test();
test.setName(String.valueOf(query.getOffset() + i));
tests.add(test);
}
return tests.stream();
}
public int size(Query<Test, SerializablePredicate<Test>> query) {
return 100;
}
public void setSortOrders(List<QuerySortOrder> sortOrders) {
}
}
public class TestDataProvider1 extends AbstractDataProvider<Test, SerializablePredicate<Test>> implements
InMemoryDataProvider<Test> {
public Stream<Test> fetch(Query<Test, SerializablePredicate<Test>> query) {
List<Test> tests = new ArrayList<>(query.getLimit());
for (int i = 0; i < query.getLimit(); i++) {
Test test = new Test();
test.setName(String.valueOf(query.getOffset() + i));
tests.add(test);
}
return tests.stream();
}
public int size(Query<Test, SerializablePredicate<Test>> query) {
return 100;
}
public SerializablePredicate<Test> getFilter() {
return null;
}
public void setFilter(SerializablePredicate<Test> filter) {
}
public SerializableComparator<Test> getSortComparator() {
return null;
}
public void setSortComparator(SerializableComparator<Test> comparator) {
}
}
Here is how the grids are rendered:
Have I missed a critical step in setting up my BackEnd-based data provider/grid? The related documentation does not seem to address this issue.
Is there a known issue related to this?
Is select-all not available by design? Obviously, this could interact really badly with the concept of lazy-loading on a large data set...
MultiSelectionModelImpl has this method:
protected void updateCanSelectAll() {
switch (selectAllCheckBoxVisibility) {
case VISIBLE:
getState(false).selectAllCheckBoxVisible = true;
break;
case HIDDEN:
getState(false).selectAllCheckBoxVisible = false;
break;
case DEFAULT:
getState(false).selectAllCheckBoxVisible = getGrid()
.getDataProvider().isInMemory();
break;
default:
break;
}
}
This indicates that the default behavior for non-in-memory providers is to not show the select-all checkbox, but that this behavior can be overridden by setting the visibility to VISIBLE.
Tweaking the original code here:
public class TestGrid extends Grid<Test> {
public TestGrid(DataProvider<Test, ?> dataProvider) {
setHeightByRows(4);
MultiSelectionModel<Test> selectionModel = (MultiSelectionModel<Test>) setSelectionMode(SelectionMode.MULTI);
selectionModel.setSelectAllCheckBoxVisibility(SelectAllCheckBoxVisibility.VISIBLE);
setDataProvider(dataProvider);
addColumn(Test::getName).setCaption("Name");
}
}
Specifically, this call is required for the checkbox to appear for data providers that implement BackEndDataProvider:
MultiSelectionModel<Test> selectionModel = (MultiSelectionModel<Test>) setSelectionMode(SelectionMode.MULTI);
selectionModel.setSelectAllCheckBoxVisibility(SelectAllCheckBoxVisibility.VISIBLE);
With this change, the select-all checkbox now appears:
I have a recyclerview with a header achieved by using two different element types. In my header there is an edit text which I want to use for filtering the nonheader elements of the list. Below is my current implementation, I have one concern and one problem with it.
My concern is that what I am doing in publishResults with the notifyItemRangeRemoved and notifyItemInserted is the wrong way to update the recycler view. I originally was doing notifyDatasetChanged but his would cause the header row to be refreshed too and the edit text to lose focus. What I really want is a way to refresh only the item rows and leave the header row untouched.
My current problem is that with the existing code if I scroll down too much the edit text looses focus. I want the edit text to keep focus even if I scroll to the bottom of the list.
The code used to use a ListView with setHeaderView and that worked somehow so there must be someway of achieving the goal just not sure what the trick with a recycler view is. Any help is much appreciated.
public class SideListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements Filterable {
private static final int TYPE_HEADER = 0;
private static final int TYPE_ITEM = 1;
private final List<String> data;
public List<String> filteredData;
private HeaderActionListener headerActionListener;
public SideListAdapter(Context context, ArrayList<String> data, HeaderActionListener headerActionListener) {
this.data = data;
filteredData = new ArrayList<>(data);
this.context = context;
this.headerActionListener = headerActionListener;
}
#Override
public Filter getFilter() {
return new TestFilter();
}
static class SideListItem extends RecyclerView.ViewHolder {
LinearLayout baseLayout;
public SideListItem(View itemView) {
super(itemView);
baseLayout = (LinearLayout) itemView.findViewById(R.id.settings_defaultcolor);
}
}
class SideListHeader extends SideListHeader {
EditText sort;
public SideListHeaderLoggedIn(View itemView) {
super(itemView);
sort = (EditText) itemView.findViewById(R.id.sort);
}
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_ITEM) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false);
return new SideListItem(v);
} else if (viewType == SideListHeader) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.header, parent, false);
return new SideListHeader(v);
}
throw new RuntimeException("there is no type that matches the type " + viewType + " + make sure your using types correctly");
}
public interface HeaderActionListener {
boolean onSortEditorAction(TextView arg0, int arg1, KeyEvent arg2);
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
if (holder instanceof SideListHeader) {
final SideListHeader sideListHeader = (SideListHeader) holder;
sideListHeader.sort.setOnEditorActionListener(new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
}
});
sideListHeader.sort.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
}
#Override
public void afterTextChanged(Editable editable) {
String result = sideListHeader.sort.getText().toString().replaceAll(" ", "");
getFilter().filter(result);
}
});
}
if (holder instanceof SideListItem) {
// Inflate normal item //
}
}
// need to override this method
#Override
public int getItemViewType(int position) {
if (isPositionHeader(position)) {
return TYPE_HEADER;
}
return TYPE_ITEM;
}
private boolean isPositionHeader(int position) {
return position == 0;
}
//increasing getItemcount to 1. This will be the row of header.
#Override
public int getItemCount() {
return filteredData.size() + 1;
}
private class TestFilter extends Filter {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
String prefix = constraint.toString().toLowerCase();
if (prefix.isEmpty()) {
ArrayList<String> list = new ArrayList<>(data);
results.values = list;
results.count = list.size();
} else {
final ArrayList<String> list = new ArrayList<>(data);
final ArrayList<String> nlist = new ArrayList<>();
for (int i = 0 ; i < list.size(); i++) {
String item = list.get(i);
if (item.contains(prefix)) {
nlist.add(item);
}
}
results.values = nlist;
results.count = nlist.size();
}
return results;
}
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
notifyItemRangeRemoved(1, getItemCount()-1);
filteredData.clear();
filteredData.addAll((List<String>)results.values);
for(int i = 1; i < getItemCount() - 1; i++){
notifyItemInserted(i);
}
}
}
}
I'm not sure how correct this way is, but in my code I implemented it like that
private var headerList: List<HeaderItem> = listOf(HeaderItem("Title"))
private fun searchItem(items: List<Items>, query: String) {
items.filterIsInstance<MainItem>().filter { filteredItems ->
filteredItems.header.lowercase().contains(query.lowercase())
}.let { searchedItems ->
rvAdapter.submitList(headerList + searchedItems)
}
}
This way I was able to preserve header element when I did my search
I'm looking for a convenient way to provide initial data for my application. Currently I've implemented a Spring Data JPA based project which is my foundation of all database related operation.
Example:
I've got a entity Role which can be assigned to the entity User. On a clean application start I would like to provide directly some default roles (e.g. admin, manager, etc).
Best
I built a random data factory :
public class RandomDataFactory {
private static final String UNGENERATED_VALUE_MARKER = "UNGENERATED_VALUE_MARKER";
private static void randomlyPopulateFields(Object object) {
new RandomValueFieldPopulator().populate(object);
}
/**
* Instantiates a single object with random data
*/
public static <T> T getSingle(Class<T> clazz) throws IllegalAccessException, InstantiationException {
T object = clazz.newInstance();
randomlyPopulateFields(object);
return object;
}
/**
* Returns an unmodifiable list of specified type objects with random data
*
* #param clazz the myPojo.class to be instantiated with random data
* #param maxLength the length of list to be returned
*/
public static <T> List<T> getList(Class<T> clazz, int maxLength) throws IllegalAccessException, InstantiationException {
List<T> list = new ArrayList<T>(maxLength);
for (int i = 0; i < maxLength; i++) {
T object = clazz.newInstance();
randomlyPopulateFields(object);
list.add(i, object);
}
return Collections.unmodifiableList(list);
}
/**
* Returns a unmodifiable list of specified type T objects with random data
* <p>List length will be 3</p>
*
* #param clazz the myPojo.class to be instantiated with random data
*/
public static <T> List<T> getList(Class<T> clazz) throws InstantiationException, IllegalAccessException {
return getList(clazz, 3);
}
public static <T> T getPrimitive(Class<T> clazz) {
return (T) RandomValueFieldPopulator.generateRandomValue(clazz);
}
public static <T> List<T> getPrimitiveList(Class<T> clazz) {
return getPrimitiveList(clazz, 3);
}
public static <T> List<T> getPrimitiveList(Class<T> clazz, int length) {
List<T> randoms = new ArrayList<T>(length);
for (int i = 0; i < length; i++) {
randoms.add(getPrimitive(clazz));
}
return randoms;
}
private static class RandomValueFieldPopulator {
public static Object generateRandomValue(Class<?> fieldType) {
Random random = new Random();
if (fieldType.equals(String.class)) {
return UUID.randomUUID().toString();
} else if (Date.class.isAssignableFrom(fieldType)) {
return new Date(System.currentTimeMillis() - random.nextInt());
} else if (LocalDate.class.isAssignableFrom(fieldType)) {
Date date = new Date(System.currentTimeMillis() - random.nextInt());
return new LocalDate(date);
} else if (fieldType.equals(Character.class) || fieldType.equals(Character.TYPE)) {
return (char) (random.nextInt(26) + 'a');
} else if (fieldType.equals(Integer.TYPE) || fieldType.equals(Integer.class)) {
return random.nextInt();
} else if (fieldType.equals(Short.TYPE) || fieldType.equals(Short.class)) {
return (short) random.nextInt();
} else if (fieldType.equals(Long.TYPE) || fieldType.equals(Long.class)) {
return random.nextLong();
} else if (fieldType.equals(Float.TYPE) || fieldType.equals(Float.class)) {
return random.nextFloat();
} else if (fieldType.equals(Double.TYPE)) {
return random.nextInt(); //if double is used, jsonPath uses bigdecimal to convert back
} else if (fieldType.equals(Double.class)) {
return random.nextDouble(); //if double is used, jsonPath uses bigdecimal to convert back
} else if (fieldType.equals(Boolean.TYPE) || fieldType.equals(Boolean.class)) {
return random.nextBoolean();
} else if (fieldType.equals(BigDecimal.class)) {
return new BigDecimal(random.nextFloat());
} else if (Enum.class.isAssignableFrom(fieldType)) {
Object[] enumValues = fieldType.getEnumConstants();
return enumValues[random.nextInt(enumValues.length)];
} else if (Number.class.isAssignableFrom(fieldType)) {
return random.nextInt(Byte.MAX_VALUE) + 1;
} else {
return UNGENERATED_VALUE_MARKER;
}
public void populate(Object object) {
ReflectionUtils.doWithFields(object.getClass(), new RandomValueFieldSetterCallback(object));
}
private static class RandomValueFieldSetterCallback implements ReflectionUtils.FieldCallback {
private final Object targetObject;
public RandomValueFieldSetterCallback(Object targetObject) {
this.targetObject = targetObject;
}
#Override
public void doWith(Field field) throws IllegalAccessException {
Class<?> fieldType = field.getType();
if (!Modifier.isFinal(field.getModifiers())) {
Object value = generateRandomValue(fieldType);
if (!value.equals(UNGENERATED_VALUE_MARKER)) {
ReflectionUtils.makeAccessible(field);
field.set(targetObject, value);
}
}
}
}
}
}
Look into an in-memory H2 database.
http://www.h2database.com/html/main.html
Maven Dependency
<!-- H2 Database -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.178</version>
</dependency>
Spring Java Config Entry
#Bean
public DataSource dataSource() {
System.out.println("**** USING H2 DATABASE ****");
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
return builder.setType(EmbeddedDatabaseType.H2).addScript("/schema.sql").build();
}
You can create/load the H2 database w/ a SQL script in the above code using .addscript().
If you are using it for Unit test, and need a different state for different test, then
There is a http://dbunit.sourceforge.net/
Specifically for Spring there is http://springtestdbunit.github.io/spring-test-dbunit/
If you need to initialize it only once and using EmbeddedDatabaseBuilder for testing, then as Brandon said, you can use EmbeddedDatabaseBuilder.
#Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
return builder.setType(EmbeddedDatabaseType.H2).addScript("/schema.sql").build();
}
If you want it to be initialised on application start, you can add #PostConstruct function to your Configuration bean, and it will be initialised after configuration bean was created.
#PostConstruct
public void initializeDB() {
}
I am a newbie to Trident and I'm looking to create an 'Average' aggregator similar to 'Sum(), but for 'Average'.The following does not work:
public class Average implements CombinerAggregator<Long>.......{
public Long init(TridentTuple tuple)
{
(Long)tuple.getValue(0);
}
public Long Combine(long val1,long val2){
return val1+val2/2;
}
public Long zero(){
return 0L;
}
}
It may not be exactly syntactically correct, but that's the idea. Please help if you can. Given 2 tuples with values [2,4,1] and [2,2,5] and fields 'a','b' and 'c' and doing an average on field 'b' should return '3'. I'm not entirely sure how init() and zero() work.
Thank you so much for your help in advance.
Eli
public class Average implements CombinerAggregator<Number> {
int count = 0;
double sum = 0;
#Override
public Double init(final TridentTuple tuple) {
this.count++;
if (!(tuple.getValue(0) instanceof Double)) {
double d = ((Number) tuple.getValue(0)).doubleValue();
this.sum += d;
return d;
}
this.sum += (Double) tuple.getValue(0);
return (Double) tuple.getValue(0);
}
#Override
public Double combine(final Number val1, final Number val2) {
return this.sum / this.count;
}
#Override
public Double zero() {
this.sum = 0;
this.count = 0;
return 0D;
}
}
I am a complete newbie when it comes to Trident as well, and so I'm not entirely if the following will work. But it might:
public class AvgAgg extends BaseAggregator<AvgState> {
static class AvgState {
long count = 0;
long total = 0;
double getAverage() {
return total/count;
}
}
public AvgState init(Object batchId, TridentCollector collector) {
return new AvgState();
}
public void aggregate(AvgState state, TridentTuple tuple, TridentCollector collector) {
state.count++;
state.total++;
}
public void complete(AvgState state, TridentCollector collector) {
collector.emit(new Values(state.getAverage()));
}
}