Java Function chaining - function

I'm trying to work out why the following code fails to compile:
Function<Employee, String> getLastName = (Employee employee) -> {
return employee.getName().substring(employee.getName().indexOf(" ") + 1);
};
Function<Employee, String> getFirstName = (Employee employee) -> {
return employee.getName().substring(0, employee.getName().indexOf(" "));
};
Function chained = getFirstName.apply(employees.get(2).andThen(getFirstName.apply(employees.get(2))));
Can't all Functions be cahined in java 8?

Exactly, andThen is applied to the result from that Function, for example:
Function<Employee, String> chained = getFirstName.andThen(x -> x.toUpperCase());
x -> x.toUpperCase() (or this can be replaced with a method reference String::toUpperCase) is applied to the String result from getFirstName Function.
How do you imagine chaining them? One Function returns String, so that makes it impossible to chain. But you can return both those fields via a single Function:
Function<Employee, String[]> bothFunction = (Employee employee) -> {
String[] both = new String[2];
both[0] = employee.getName().substring(employee.getName().indexOf(" ") + 1);
both[1] = employee.getName().substring(0, employee.getName().indexOf(" "));
return both;
};

Related

JSONObject and Streams/Lambda

I'm trying to get more familiar with Java lambda, can do some streams and such but still a lot to learn.
Got this simple code using JSONObject and JSONArray (org.json.simple with this exact library and no other because Gson is too easy :P) is there a way to simplify the code with java lambda/streams? (I tried with no luck)
JSONArray jsonArray = (JSONArray) jsonObject.get("someData");
Iterator<JSONObject> iterator = jsonArray.iterator();
double total = 0;
while(iterator.hasNext()) {
JSONObject iteratedJson = iterator.next();
// iteratedJson.get("ip") = "101.99.99.101" example values
String ip = (String) iteratedJson.get("ip");
// Need only first octet
ip = ip.substring(0, ip.indexOf("."));
if (Integer.valueOf(ip) >= 1 && Integer.valueOf(ip) <= 100) {
// Another object inside the array object
JSONObject locationObject = (JSONObject) iteratedJson.get("location");
// Id is int but JSONObject don't let me parse int...
long locationId = (Long) locationObject.get("id");
if (locationId == 8) {
// iteratedJson.get("amount") = "$1,999.10" example values
Number number = NumberFormat.getCurrencyInstance(Locale.US).parse((String)iteratedJson.get("amount"));
// Don't need a lot of precission
total = total + number.doubleValue();
}
}
}
You can do like this:
first of all to extract data from JsonObject I've created a class. this class takes a JosonObject as an argument and extract its values as bellow.
class ExtractData {
Integer ip;
long id;
double amount;
public ExtractData(JSONObject jsonObject) {
this.ip = Integer.valueOf(jsonObject.get("ip").toString().split("\\.")[0]);
this.id = Long.parseLong(((JSONObject) jsonObject.get("location")).get("id").toString());
try {
this.amount = NumberFormat.getCurrencyInstance(Locale.US)
.parse((String) jsonObject.get("amount")).doubleValue();
} catch (ParseException e) {
this.amount = 0d;
}
}
// getter&setter
}
then you can use stream API to calculate the sum of the amount property.
jsonArray.stream()
.map(obj -> new ExtractData((JSONObject) obj))
.filter(predicate)
.mapToDouble(value -> ((ExtractData) value).getAmount())
.sum();
for simplifying I've extracted filter operation.
Predicate<ExtractData> predicate = extractData ->
extractData.getIp()>=1 && extractData.getIp()<=100 && extractData.getId() == 8;

Lazy loading with JPA criterea

I implemented a generic solution for using lazy loading primefaces datatables using JPA Criterea.
However I am still having some doubts with thie implemented solution whenever we deal with several Joins (say for example an entity User that has relation with other entities like Account, Address, Department.....in addition to raw type properties like: String username, Date birthdate...etc).
I tested this solution but I am having some delays while loading huge number of data (however the solution is supposed to load only a limited number of rows specified by PageSize coming from datatable), so:
How to improve the performance of this solution?
How to be sure the number of loaded data is the one specified in the Pagesize?
Can you check the count() method and tell if it counts the number of result rows without loading all the data?
And most importantly how to use this solution in order to be generic with filters coming from Search forms (I mean how to use this sae generic method and give search critereas from a search form with multi search fields)?
Please I need your answer on the above mentioned questions especially the last one.
Here is the code:
public <T extends Object> List<T> search(Class<T> type, int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, String> filters){
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<T> q = cb.createQuery(type);
Root<T> root=q.from(type);
q.select(root);
//Sorting
if (sortField != null && !sortField.isEmpty()) {
String[] sortingField = sortField.split("\\.", 2);
Path path = sortingField.length == 1 ? root.get(sortingField[0]): root.join(sortingField[0]).get(sortingField[1]);
if (sortOrder.equals(SortOrder.ASCENDING)) {
q.orderBy(cb.asc(path));
} else if (sortOrder.equals(SortOrder.DESCENDING)) {
q.orderBy(cb.desc(path));
}
}
// Filtering
Predicate filterCondition = cb.conjunction();
String wildCard = "%";
for (Map.Entry<String, String> filter : filters.entrySet()) {
String[] filterField = filter.getKey().split("\\.", 2);
Path path = filterField.length == 1 ? root.get(filterField[0]): root.join(filterField[0]).get(filterField[1]);
filterCondition = cb.and(filterCondition, filter.getValue().matches("[0-9]+")
? cb.equal(path, Long.valueOf(filter.getValue()))
: cb.like(path, wildCard + filter.getValue() + wildCard));
}q.where(filterCondition);
//Pagination
TypedQuery<T> s = entityManager.createQuery(q);
if (pageSize >= 0){
s.setMaxResults(pageSize);
}
if (first >= 0){
s.setFirstResult(first);
}
log.info("\n\n\n");
log.info("XXXXXXXXXxX");
log.info("=> CommonRepository - Total number of rows returned: ");
log.info("XXXXXXXXXXX");
log.info("\n\n\n");
return s.getResultList();
}
public <T extends Object> int count(Class<T> type, Map<String, String> filters){
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Long> cq = cb.createQuery(Long.class);
Root<T> root=cq.from(type);
// Filtering
Predicate filterCondition = cb.conjunction();
String wildCard = "%";
for (Map.Entry<String, String> filter : filters.entrySet()) {
String[] filterField = filter.getKey().split("\\.", 2);
Path path = filterField.length == 1 ? root.get(filterField[0]): root.join(filterField[0]).get(filterField[1]);
filterCondition = cb.and(filterCondition, filter.getValue().matches("[0-9]+")
? cb.equal(path, Long.valueOf(filter.getValue()))
: cb.like(path, wildCard + filter.getValue() + wildCard));
}cq.where(filterCondition);
cq.select(cb.count(root));
return entityManager.createQuery(cq).getSingleResult().intValue();
}

Grails - how to let a domain class convert JSON into a domain property

I want to teach my domain class to automatically convert the results of JSON.parse(someJSON) into a member that is also a custom domain class.
Given these domain classes:
class Person {
Long id
String name
static hasMany = [aliases: PersonAlias]
}
class PersonAlias {
Person person
Long id
String name
}
And this JSON representing a Person with some PersonAliases:
{
"id":20044397,
"name":"John Smith",
"aliases":[{"id":13376,"name":"Johnny Smith"},{"id":13377,"name":"J. Smith"}]
}
I want to keep the controller simple like:
class PersonController {
def saveViaAjax = {
def props = JSON.parse(params.JSON)
Person p = Person.get(props.id)
p.properties = props
p.save(flush: true)
}
}
But sadly I get this error:
Failed to convert property value of type
'org.codehaus.groovy.grails.web.json.JSONArray' to required type
'java.util.Set' for property 'aliases'; nested exception is
java.lang.IllegalStateException: Cannot convert value of type
[org.codehaus.groovy.grails.web.json.JSONObject] to required type
[heavymeta.PersonAlias] for property 'aliases[0]': no matching editors
or conversion strategy found
So, I want to teach my domain class to how to convert the JSON data into PersonAlias instances automatically. I'd like to avoid formatting the data in the controller before passing it to the Domain object. How do I accomplish these goals?
You can use the bindUsing annotation and provide your custom binding code to convert the json to the property being bound.
class Person {
Long id
String name
#BindUsing({obj, source ->
List retVal = []
def aliases = source['aliases']
if(aliases) {
aliases.each {
retVal << new PersonAlias(name:it.name)
}
}
return retVal
})
List<PersonAlias> aliases
static hasMany = [aliases: PersonAlias]
}
I think this plugin: https://github.com/pedjak/grails-marshallers might do what you're looking for? I have not tried it myself though.
I also encountered this problem - I did my best to document the fix on my website - See http://dalelotts.com/software-architect/grails
In general the solution is to convert the JSON to a parameter map that can be used for data binding. More info on the site, including an annotation driven DomainClassMarshaller for JSON
protected Object readFromJson(Class type, InputStream entityStream, String charset) {
def mapper = new ObjectMapper();
def parsedJSON = mapper.readValue(entityStream, typeRef);
Map<String, Object> map = new HashMap<>();
parsedJSON.entrySet().each {Map.Entry<String, Object> entry ->
if (List.isAssignableFrom(entry.getValue().getClass())) {
List values = (List) entry.getValue();
int limit = values.size()
for (int i = 0; i < limit; i++) {
final theValue = values.get(i)
map.put(entry.key + '[' + i + ']', theValue)
appendMapValues(map, theValue, entry.key + '[' + i + ']' )
}
} else {
map.put(entry.key, entry.value);
}
}
def result = type.metaClass.invokeConstructor(map)
// Workaround for http://jira.codehaus.org/browse/GRAILS-1984
if (!result.id) {
result.id = idFromMap(map)
}
result
}
private void appendMapValues(Map<String, Object> theMap, Object theValue, String prefix) {
if (Map.isAssignableFrom(theValue.getClass())) {
Map<String, Object> valueMap = (Map<String, Object>) theValue;
for (Map.Entry<String, Object> valueEntry : valueMap.entrySet()) {
theMap.put(prefix + '.' + valueEntry.key, valueEntry.value)
appendMapValues(theMap, valueEntry.value, prefix + '.' + valueEntry.key)
}
}
}

Using EF to query against a compile-time-unknown property

Is there a way in EntityFramework (and the resulting LINQ) to query against a property of an entity that is not hard-coded?
Let's say, something that can be used for a search function.
public IList<Entity> Search (string propertyName, object value) {
// something that'll do the following
return context.Set<Entity>()
.Where(x => x.propertyName == value)
.ToList()
;
}
How about Property Descriptor?
The following code seems to do what you require:
string propertyName = "Length";
List<string> testList = new List<string>();
testList.Add("String1");
testList.Add("String10");
testList.Add("String100");
testList.Add("String1000");
System.ComponentModel.PropertyDescriptorCollection props = System.ComponentModel.TypeDescriptor.GetProperties(typeof(string));
System.ComponentModel.PropertyDescriptor desc = props.Find(propertyName, false);
IEnumerable<object> obj = from env in testList
select desc.GetValue(env);
foreach (object it in obj)
{
Console.WriteLine(it.ToString());
}
You can build equals expression manually like this
private static Expression<Func<TEntity, bool>> BuildEqualExpression<TEntity>(string propertyName, object value)
{
var param = Expression.Parameter(typeof(TEntity), "x");
var body = Expression.MakeBinary(ExpressionType.Equal,
Expression.Property(param, propertyName), Expression.Constant(value));
return Expression.Lambda<Func<TEntity, bool>>(body, new ParameterExpression[] { param });
}
and then use it in your LINQ query
var expression = BuildEqualExpression<TEntity>(propertyName, value);
return context.Set<TEntity>().Where(expression).ToList();

Performing dynamic sorts on EF4 data

I'm attempting to perform dynamic sorting of data that I'm putting into grids into our MVC UI. Since MVC is abstracted from everything else via WCF, I've created a couple utility classes and extensions to help with this. The two most important things (slightly simplified) are as follows:
public static IQueryable<TModel> ApplySortOptions<TModel, TProperty>(this IQueryable<TModel> collection, IEnumerable<ISortOption<TModel, TProperty>> sortOptions) where TModel : class
{
var sortedSortOptions = (from o in sortOptions
orderby o.Priority ascending
select o).ToList();
var results = collection;
foreach (var option in sortedSortOptions)
{
var currentOption = option;
var propertyName = currentOption.Property.MemberWithoutInstance();
var isAscending = currentOption.IsAscending;
if (isAscending)
{
results = from r in results
orderby propertyName ascending
select r;
}
else
{
results = from r in results
orderby propertyName descending
select r;
}
}
return results;
}
public interface ISortOption<TModel, TProperty> where TModel : class
{
Expression<Func<TModel, TProperty>> Property { get; set; }
bool IsAscending { get; set; }
int Priority { get; set; }
}
I've not given you the implementation for MemberWithoutInstance() but just trust me in that it returns the name of the property as a string. :-)
Following is an example of how I would consume this (using a non-interesting, basic implementation of ISortOption<TModel, TProperty>):
var query = from b in CurrentContext.Businesses
select b;
var sortOptions = new List<ISortOption<Business, object>>
{
new SortOption<Business, object>
{
Property = (x => x.Name),
IsAscending = true,
Priority = 0
}
};
var results = query.ApplySortOptions(sortOptions);
As I discovered with this question, the problem is specific to my orderby propertyName ascending and orderby propertyName descending lines (everything else works great as far as I can tell). How can I do this in a dynamic/generic way that works properly?
You should really look at using Dynamic LINQ for this. In fact, you may opt to simply list the properties by name instead of using an expression, making it somewhat easier to construct.
public static IQueryable<T> ApplySortOptions<T, TModel, TProperty>(this IQueryable<T> collection, IEnumerable<ISortOption<TModel, TProperty>> sortOptions) where TModel : class
{
var results = collection;
foreach (var option in sortOptions.OrderBy( o => o.Priority ))
{
var currentOption = option;
var propertyName = currentOption.Property.MemberWithoutInstance();
var isAscending = currentOption.IsAscending;
results = results.OrderBy( string.Format( "{0}{1}", propertyName, !isAscending ? " desc" : null ) );
}
return results;
}
While I think #tvanfosson's solution will function perfectly, I'm also looking into this possibility:
/// <summary>
/// This extension method is used to help us apply ISortOptions to an IQueryable.
/// </summary>
/// <param name="collection">This is the IQueryable you wish to apply the ISortOptions to.</param>
/// <param name="sortOptions">These are the ISortOptions you wish to have applied. You must specify at least one ISortOption (otherwise, don't call this method).</param>
/// <returns>This returns an IQueryable object.</returns>
/// <remarks>This extension method should honor deferred execution on the IQueryable that is passed in.</remarks>
public static IOrderedQueryable<TModel> ApplySortOptions<TModel, TProperty>(this IQueryable<TModel> collection, IEnumerable<ISortOption<TModel, TProperty>> sortOptions) where TModel : class
{
Debug.Assert(sortOptions != null, "ApplySortOptions cannot accept a null sortOptions input.");
Debug.Assert(sortOptions.Count() > 0, "At least one sort order must be specified to ApplySortOptions' sortOptions input.");
var firstSortOption = sortOptions.OrderBy(o => o.Priority).First();
var propertyName = firstSortOption.Property.MemberWithoutInstance();
var isAscending = firstSortOption.IsAscending;
// Perform the first sort action
var results = isAscending ? collection.OrderBy(propertyName) : collection.OrderByDescending(propertyName);
// Loop through all of the rest ISortOptions
foreach (var sortOption in sortOptions.OrderBy(o => o.Priority).Skip(1))
{
// Make a copy of this or our deferred execution will bite us later.
var currentOption = sortOption;
propertyName = currentOption.Property.MemberWithoutInstance();
isAscending = currentOption.IsAscending;
// Perform the additional orderings.
results = isAscending ? results.ThenBy(propertyName) : results.ThenByDescending(propertyName);
}
return results;
}
using the code from this question's answer:
public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string property)
{
return ApplyOrder(source, property, "OrderBy");
}
public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> source, string property)
{
return ApplyOrder(source, property, "OrderByDescending");
}
public static IOrderedQueryable<T> ThenBy<T>(this IOrderedQueryable<T> source, string property)
{
return ApplyOrder(source, property, "ThenBy");
}
public static IOrderedQueryable<T> ThenByDescending<T>(this IOrderedQueryable<T> source, string property)
{
return ApplyOrder(source, property, "ThenByDescending");
}
private static IOrderedQueryable<T> ApplyOrder<T>(IQueryable<T> source, string property, string methodName)
{
var props = property.Split('.');
var type = typeof (T);
var arg = Expression.Parameter(type, "x");
Expression expr = arg;
foreach (var prop in props)
{
// use reflection (not ComponentModel) to mirror LINQ
var pi = type.GetProperty(prop);
expr = Expression.Property(expr, pi);
type = pi.PropertyType;
}
var delegateType = typeof (Func<,>).MakeGenericType(typeof (T), type);
var lambda = Expression.Lambda(delegateType, expr, arg);
var result = typeof (Queryable).GetMethods().Single(
method => method.Name == methodName
&& method.IsGenericMethodDefinition
&& method.GetGenericArguments().Length == 2
&& method.GetParameters().Length == 2)
.MakeGenericMethod(typeof (T), type)
.Invoke(null, new object[] {source, lambda});
return (IOrderedQueryable<T>) result;
}