问:
how to get running total by month
I am trying populate a graph and my Model looks like this

```<code>public class Transaction : BaseEntity
{
    public TransactionType TransactionType { get; set; }
    public DateTime TransactionDate { get; set; }
    public double TransactionAmount { get; set; }
}
public enum TransactionType{
    Deposit = 0,
    Withdraw = 1
}
</code>```

i populated this model with sample data of first 2 months of 2018.

```<code>    b.HasData(new
            {
                Id = Guid.NewGuid().ToString(),
                AccountId = "37846734-172e-4149-8cec-6f43d1eb3f60",
                TransactionAmount = 3334.38,
                TransactionDate = new DateTime(DateTime.UtcNow.AddYears(-2).Year, 1, 20),
                TransactionType = TransactionType.Deposit
            });
            b.HasData(new
            {
                Id = Guid.NewGuid().ToString(),
                AccountId = "37846734-172e-4149-8cec-6f43d1eb3f60",
                TransactionAmount = -3334.38,
                TransactionDate = new DateTime(DateTime.UtcNow.AddYears(-2).Year, 1, 21),
                TransactionType = TransactionType.Withdraw

            });
            b.HasData(new
            {
                Id = Guid.NewGuid().ToString(),
                AccountId = "37846734-172e-4149-8cec-6f43d1eb3f60",
                TransactionAmount = 1000.23,
                TransactionDate = new DateTime(DateTime.UtcNow.AddYears(-2).Year, 1, 25),
                TransactionType = TransactionType.Deposit
            });
            b.HasData(new
            {
                Id = Guid.NewGuid().ToString(),
                AccountId = "37846734-172e-4149-8cec-6f43d1eb3f60",
                TransactionAmount = 1008.18,
                TransactionDate = new DateTime(DateTime.UtcNow.AddYears(-2).Year, 4, 10),
                TransactionType = TransactionType.Deposit
            });
            b.HasData(new
            {
                Id = Guid.NewGuid().ToString(),
                AccountId = "37846734-172e-4149-8cec-6f43d1eb3f60",
                TransactionAmount = -34.10,
                TransactionDate = new DateTime(DateTime.UtcNow.AddYears(-2).Year, 4, 19),
                TransactionType = TransactionType.Withdraw
            });
</code>```

I am trying to get a result that what was the balance at end of each month.

for example in

2018    Jan   1000.23

        April 1974.23 (1000.23 from January + 974.0 from April)

but what i am getting is

Jan 1000.23

   April 974.0

basically it is adding all the values in each month individually.

```<code> var data = from t in transactions
                   group t by new { t.TransactionDate.Year, t.TransactionDate.Month } into g
                   select new
                   {
                       //Balance = g.Select(i =>
                       //{
                       //    currentTotal += g.Sum(x => x.TransactionAmount);
                       //    return new
                       //    {
                       //        //Date = i.TransactionDate,
                       //        //Amount = i.TransactionAmount,
                       //        currentTotal
                       //    };
                       //}),
                       Balance = g.Sum(x => x.TransactionAmount),
                       g.First().TransactionDate.Month,
                       g.First().TransactionDate.Year
                   };
        var yearlyGroups = data.OrderBy(x => x.Month).GroupBy(x => x.Year);
        var lastTwoYearsSortedByMonth = yearlyGroups.OrderBy(x => x.Key).TakeLast(2);
</code>```

As you can see in the code above i tried something to get the running total. but not working.

答:
I think I have misled you with my suggestion. I couldn't come up with an elegant enough solution that would've used .Aggregate().

    var runningBalance = 0.0;
    var data = transactions.GroupBy(t => new { t.TransactionDate.Year, t.TransactionDate.Month })
        .OrderBy(d => d.Key.Year)
        .ThenBy(dd => dd.Key.Month)
        .Select((g) => new
        {
            Year = g.Key.Year,
            Month = g.Key.Month,
            Balance = g.Sum(i => i.TransactionAmount),
            RunningBalance = (runningBalance = (runningBalance + g.Sum(i => i.TransactionAmount)))
        });
```

Title: how to get running total by month

Body:
I am trying populate a graph and my Model looks like this

public class Transaction : BaseEntity
{
    public TransactionType TransactionType { get; set; }
    public DateTime TransactionDate { get; set; }
    public double TransactionAmount { get; set; }
}
public enum TransactionType{
    Deposit = 0,
    Withdraw = 1
}

i populated this model with sample data of first 2 months of 2018.

    b.HasData(new
            {
                Id = Guid.NewGuid().ToString(),
                AccountId = "37846734-172e-4149-8cec-6f43d1eb3f60",
                TransactionAmount = 3334.38,
                TransactionDate = new DateTime(DateTime.UtcNow.AddYears(-2).Year, 1, 20),
                TransactionType = TransactionType.Deposit
            });
            b.HasData(new
            {
                Id = Guid.NewGuid().ToString(),
                AccountId = "37846734-172e-4149-8cec-6f43d1eb3f60",
                TransactionAmount = -3334.38,
                TransactionDate = new DateTime(DateTime.UtcNow.AddYears(-2).Year, 1, 21),
                TransactionType = TransactionType.Withdraw

            });
            b.HasData(new
            {
                Id = Guid.NewGuid().ToString(),
                AccountId = "37846734-172e-4149-8cec-6f43d1eb3f60",
                TransactionAmount = 1000.23,
                TransactionDate = new DateTime(DateTime.UtcNow.AddYears(-2).Year, 1, 25),
                TransactionType = TransactionType.Deposit
            });
            b.HasData(new
            {
                Id = Guid.NewGuid().ToString(),
                AccountId = "37846734-172e-4149-8cec-6f43d1eb3f60",
                TransactionAmount = 1008.18,
                TransactionDate = new DateTime(DateTime.UtcNow.AddYears(-2).Year, 4, 10),
                TransactionType = TransactionType.Deposit
            });
            b.HasData(new
            {
                Id = Guid.NewGuid().ToString(),
                AccountId = "37846734-172e-4149-8cec-6f43d1eb3f60",
                TransactionAmount = -34.10,
                TransactionDate = new DateTime(DateTime.UtcNow.AddYears(-2).Year, 4, 19),
                TransactionType = TransactionType.Withdraw
            });

I am trying to get a result that what was the balance at end of each month.

for example in

2018    Jan   1000.23

        April 1974.23 (1000.23 from January + 974.0 from April)

but what i am getting is

Jan 1000.23

   April 974.0

basically it is adding all the values in each month individually.

 var data = from t in transactions
                   group t by new { t.TransactionDate.Year, t.TransactionDate.Month } into g
                   select new
                   {
                       //Balance = g.Select(i =>
                       //{
                       //    currentTotal += g.Sum(x => x.TransactionAmount);
                       //    return new
                       //    {
                       //        //Date = i.TransactionDate,
                       //        //Amount = i.TransactionAmount,
                       //        currentTotal
                       //    };
                       //}),
                       Balance = g.Sum(x => x.TransactionAmount),
                       g.First().TransactionDate.Month,
                       g.First().TransactionDate.Year
                   };
        var yearlyGroups = data.OrderBy(x => x.Month).GroupBy(x => x.Year);
        var lastTwoYearsSortedByMonth = yearlyGroups.OrderBy(x => x.Key).TakeLast(2);

As you can see in the code above i tried something to get the running total. but not working.


来源: stackexchange

答:
So the direct answer to why you're getting an error is that you're passing an array of lists as an argument. Sklearn thus think you're passing in a 1D array of lists. It is not possible to transform your data to a 2D matrix because the number of values in your list in inconsistent.

From my understanding (which could be wrong), each row of your input feature matrix need to have the same amount of numbers. Given this is satisfied, then you should be able to feed your data into MultinomialNB no problem.

Consider padding with zeros:

data1 = np.zeros((len(data), 10))
for i in range(len(data)):
    data1[i, :len(data[i])] = data[i]
```

ContentLicense: CC BY-SA 4.0

Title: Using Naive Bayes to do multi classification

Body:
I have a dataset as below:

data = [[92, 155],
 [56, 186, 117, 210, 224],
 [247, 202, 189, 210, 65, 3, 270, 224],
 [20, 14, 157, 224],
 [17, 89, 158, 224],
 [263, 283, 68, 224],
 [182, 166, 224],
 [176, 37, 100, 224],
 [33, 102, 41, 269, 177, 224],
 [0, 260, 49, 207, 278, 217, 35],
 [119],
 [118],
 [142, 185, 7, 246, 224],
 [104, 22, 101, 224],
 [84, 205, 224],
 [225, 93, 54, 224],
 [98, 32, 78, 224],
 [159, 217, 212, 198, 224],
 [178, 94, 187, 224],
 [211, 149, 193, 149, 66, 139, 67, 28, 106, 224],
 [133, 151],
 [259, 109, 29, 224],
 [215, 241, 73, 255, 77, 144, 224],
 [36, 254, 19, 268, 183, 224],
 [47, 234, 203, 111, 231, 141, 30],
 [127, 275, 220, 161],
 [214, 267, 22, 90, 224],
 [46, 217, 103],
 [17, 89, 128, 224],
 [225, 22, 101, 224],
 [285, 265, 151],
 [215, 206, 264, 43, 224],
 [244, 21, 224],
 [82, 122, 240, 5, 224],
 [259, 136, 162, 194, 224],
 [176, 208, 112, 224],
 [172, 19, 146, 276, 31, 246, 51, 224],
 [45, 10],
 [229, 24, 224],
 [143, 108, 239, 224],
 [225, 282, 83, 224],
 [110, 267, 171],
 [176, 245, 95, 123, 270, 224],
 [248, 195, 139, 261, 173, 281, 232, 80, 18, 224],
 [61, 60, 233],
 [211, 120, 1, 23],
 [225, 267, 249, 224],
 [247, 202, 86, 196, 224],
 [15, 127, 222, 224],
 [247, 202, 186, 226, 145, 224],
 [174, 242, 196, 224],
 [259, 152, 71, 224],
 [235, 44, 230, 224],
 [69, 96, 50, 99, 116],
 [259, 279, 224],
 [228, 70],
 [39, 139, 201, 190, 224],
 [132, 40, 219, 81, 224],
 [159, 221, 224],
 [267, 16, 6, 62],
 [143, 59, 175, 129, 48, 224],
 [280, 140, 224],
 [284, 124, 167, 150, 274],
 [113, 265, 184],
 [179, 4, 257, 145, 224],
 [247, 202, 72, 11, 224],
 [64],
 [192, 125, 105],
 [174, 134, 224],
 [58, 139, 85, 160, 209, 224],
 [130, 169, 137, 256, 224],
 [215, 163, 265, 185, 26],
 [176, 147, 74, 224],
 [0, 266],
 [143, 34, 153, 188, 224],
 [121],
 [243, 75, 135],
 [38, 218, 199, 253, 224],
 [178, 271, 224],
 [154, 164, 180, 27, 270, 224],
 [176, 189, 148, 139, 277, 224],
 [57, 62],
 [91, 168, 251, 224],
 [172, 19, 146, 276, 53, 97, 200, 224],
 [64],
 [8, 237, 224],
 [138, 107, 224],
 [176, 238, 224],
 [204, 217, 63, 165, 224],
 [215, 216, 272, 62, 170, 2, 55, 224],
 [247, 273, 202, 223, 9, 148, 224],
 [258, 267, 181, 224],
 [262, 76, 126, 12, 224],
 [36, 254, 19, 268, 250, 213, 48, 224],
 [227, 42],
 [79, 197, 52, 87, 224],
 [143, 131, 224],
 [156, 88, 115, 236, 224],
 [259, 13, 252, 224],
 [114, 25, 191, 224]]

target = [9,
 31,
 20,
 9,
 3,
 26,
 16,
 11,
 28,
 0,
 9,
 9,
 9,
 9,
 7,
 1,
 33,
 9,
 13,
 15,
 9,
 21,
 9,
 34,
 9,
 9,
 9,
 9,
 3,
 1,
 9,
 27,
 14,
 22,
 21,
 11,
 17,
 9,
 6,
 8,
 1,
 9,
 11,
 9,
 9,
 9,
 1,
 20,
 29,
 20,
 23,
 21,
 9,
 9,
 21,
 9,
 18,
 9,
 9,
 30,
 8,
 9,
 9,
 9,
 9,
 20,
 9,
 32,
 23,
 9,
 24,
 9,
 11,
 9,
 8,
 9,
 9,
 9,
 13,
 10,
 11,
 9,
 12,
 17,
 9,
 5,
 9,
 11,
 9,
 2,
 20,
 9,
 25,
 34,
 9,
 9,
 8,
 4,
 21,
 19]

I wish to do classification by using naive bayes or any other BEST algorithms available. However, I received error when using naive bayes as below:

from sklearn.naive_bayes import MultinomialNB

mnb = MultinomialNB(class_prior=[.25,.75])
mnb.fit(data, target)

Errros:

ValueError: Expected 2D array, got 1D array instead:
array=[list([92, 155]) list([56, 186, 117, 210, 224])
 list([247, 202, 189, 210, 65, 3, 270, 224]) list([20, 14, 157, 224])
 list([17, 89, 158, 224]) list([263, 283, 68, 224]) list([182, 166, 224])
 list([176, 37, 100, 224]) list([33, 102, 41, 269, 177, 224])
 list([0, 260, 49, 207, 278, 217, 35]) list([119]) list([118])
 list([142, 185, 7, 246, 224]) list([104, 22, 101, 224])
 list([84, 205, 224]) list([225, 93, 54, 224]) list([98, 32, 78, 224])
 list([159, 217, 212, 198, 224]) list([178, 94, 187, 224])
 list([211, 149, 193, 149, 66, 139, 67, 28, 106, 224]) list([133, 151])
 list([259, 109, 29, 224]) list([215, 241, 73, 255, 77, 144, 224])
 list([36, 254, 19, 268, 183, 224])
 list([47, 234, 203, 111, 231, 141, 30]) list([127, 275, 220, 161])
 list([214, 267, 22, 90, 224]) list([46, 217, 103])
 list([17, 89, 128, 224]) list([225, 22, 101, 224]) list([285, 265, 151])
 list([215, 206, 264, 43, 224]) list([244, 21, 224])
 list([82, 122, 240, 5, 224]) list([259, 136, 162, 194, 224])
 list([176, 208, 112, 224]) list([172, 19, 146, 276, 31, 246, 51, 224])
 list([45, 10]) list([229, 24, 224]) list([143, 108, 239, 224])
 list([225, 282, 83, 224]) list([110, 267, 171])
 list([176, 245, 95, 123, 270, 224])
 list([248, 195, 139, 261, 173, 281, 232, 80, 18, 224])
 list([61, 60, 233]) list([211, 120, 1, 23]) list([225, 267, 249, 224])
 list([247, 202, 86, 196, 224]) list([15, 127, 222, 224])
 list([247, 202, 186, 226, 145, 224]) list([174, 242, 196, 224])
 list([259, 152, 71, 224]) list([235, 44, 230, 224])
 list([69, 96, 50, 99, 116]) list([259, 279, 224]) list([228, 70])
 list([39, 139, 201, 190, 224]) list([132, 40, 219, 81, 224])
 list([159, 221, 224]) list([267, 16, 6, 62])
 list([143, 59, 175, 129, 48, 224]) list([280, 140, 224])
 list([284, 124, 167, 150, 274]) list([113, 265, 184])
 list([179, 4, 257, 145, 224]) list([247, 202, 72, 11, 224]) list([64])
 list([192, 125, 105]) list([174, 134, 224])
 list([58, 139, 85, 160, 209, 224]) list([130, 169, 137, 256, 224])
 list([215, 163, 265, 185, 26]) list([176, 147, 74, 224]) list([0, 266])
 list([143, 34, 153, 188, 224]) list([121]) list([243, 75, 135])
 list([38, 218, 199, 253, 224]) list([178, 271, 224])
 list([154, 164, 180, 27, 270, 224]) list([176, 189, 148, 139, 277, 224])
 list([57, 62]) list([91, 168, 251, 224])
 list([172, 19, 146, 276, 53, 97, 200, 224]) list([64])
 list([8, 237, 224]) list([138, 107, 224]) list([176, 238, 224])
 list([204, 217, 63, 165, 224]) list([215, 216, 272, 62, 170, 2, 55, 224])
 list([247, 273, 202, 223, 9, 148, 224]) list([258, 267, 181, 224])
 list([262, 76, 126, 12, 224]) list([36, 254, 19, 268, 250, 213, 48, 224])
 list([227, 42]) list([79, 197, 52, 87, 224]) list([143, 131, 224])
 list([156, 88, 115, 236, 224]) list([259, 13, 252, 224])
 list([114, 25, 191, 224])].
Reshape your data either using array.reshape(-1, 1) if your data has a single feature or array.reshape(1, -1) if it contains a single sample.

Please can anyone please help me with this? Or can someone show me some other best examples of algorithms to use for machine learning like decision tree, svm or anything.


问:
Get duplicate set
I am trying to update a table with a duplicate set ID, based on the email address. I was able to find the duplicates using this query:

```<code>;WITH CTE AS (
    SELECT
      [First Name]
    , [Last Name]
    , [E-mail Address]
    , ROW_NUMBER() OVER ( PARTITION BY [E-mail Address] ORDER BY [First Name] ) RN
    FROM Contact_Master
)
SELECT * FROM CTE
</code>```

Which gives me a table like so:

```<code>First Name    Last Name    Email Address         RN
-----------------------------------------------------
John          Doe          John.Doe@gmail.com    1
John          Doe          John.Doe@gmail.com    2
Jane          Doe          Jane.Doe@gmail.com    1
Jane          Doe          Jane.Doe@gmail.com    2
</code>```

What i want is to have the RN field be a unique ID for each found duplicate:

```<code>First Name    Last Name    Email Address         RN
-----------------------------------------------------
John          Doe          John.Doe@gmail.com    1
John          Doe          John.Doe@gmail.com    1
Jane          Doe          Jane.Doe@gmail.com    2
Jane          Doe          Jane.Doe@gmail.com    2
</code>```

答:
Do it this way, by using DENSE_RANK:

```<code>;WITH CTE AS (
    SELECT
      [First Name]
    , [Last Name]
    , [E-mail Address]
    , DENSE_RANK() OVER ( PARTITION BY [E-mail Address] ORDER BY [First Name] ) RN
    FROM Contact_Master
)
SELECT * FROM CTE
</code>```

--
Owainrun this below:

```<code>with Contact_Master as
(
select 1 as id, 'John'   as [First Name]   ,     'Doe'  as [Last Name],        'John.Doe@gmail.com'  as [E-mail Address]
union select 2, 'John'   ,       'Doe'   ,       'John.Doe@gmail.com'
union select 3, 'Jane'   ,       'Doe'    ,      'Jane.Doe@gmail.com'
union select 4, 'Jane'    ,      'Doe'    ,      'Jane.Doe@gmail.com'
), CTE AS (
    SELECT id,
      [First Name]
    , [Last Name]
    , [E-mail Address]
    , DENSE_RANK() OVER (PARTITION BY [Last Name] ORDER BY [E-mail Address] ) RN
    FROM Contact_Master
)
SELECT * FROM CTE
</code>```

Output:

```<code>id  First Name  Last Name   E-mail Address  RN
3   Jane    Doe Jane.Doe@gmail.com  1
4   Jane    Doe Jane.Doe@gmail.com  1
1   John    Doe John.Doe@gmail.com  2
2   John    Doe John.Doe@gmail.com  2
</code>```

Title: Get duplicate set

Body:
I am trying to update a table with a duplicate set ID, based on the email address. I was able to find the duplicates using this query:

;WITH CTE AS (
    SELECT
      [First Name]
    , [Last Name]
    , [E-mail Address]
    , ROW_NUMBER() OVER ( PARTITION BY [E-mail Address] ORDER BY [First Name] ) RN
    FROM Contact_Master
)
SELECT * FROM CTE

Which gives me a table like so:

First Name    Last Name    Email Address         RN
-----------------------------------------------------
John          Doe          John.Doe@gmail.com    1
John          Doe          John.Doe@gmail.com    2
Jane          Doe          Jane.Doe@gmail.com    1
Jane          Doe          Jane.Doe@gmail.com    2

What i want is to have the RN field be a unique ID for each found duplicate:

First Name    Last Name    Email Address         RN
-----------------------------------------------------
John          Doe          John.Doe@gmail.com    1
John          Doe          John.Doe@gmail.com    1
Jane          Doe          Jane.Doe@gmail.com    2
Jane          Doe          Jane.Doe@gmail.com    2

Body:
Do it this way, by using DENSE_RANK:

;WITH CTE AS (
    SELECT
      [First Name]
    , [Last Name]
    , [E-mail Address]
    , DENSE_RANK() OVER ( PARTITION BY [E-mail Address] ORDER BY [First Name] ) RN
    FROM Contact_Master
)
SELECT * FROM CTE

--
Owainrun this below:

with Contact_Master as
(
select 1 as id, 'John'   as [First Name]   ,     'Doe'  as [Last Name],        'John.Doe@gmail.com'  as [E-mail Address]
union select 2, 'John'   ,       'Doe'   ,       'John.Doe@gmail.com'
union select 3, 'Jane'   ,       'Doe'    ,      'Jane.Doe@gmail.com'
union select 4, 'Jane'    ,      'Doe'    ,      'Jane.Doe@gmail.com'
), CTE AS (
    SELECT id,
      [First Name]
    , [Last Name]
    , [E-mail Address]
    , DENSE_RANK() OVER (PARTITION BY [Last Name] ORDER BY [E-mail Address] ) RN
    FROM Contact_Master
)
SELECT * FROM CTE

Output:

id  First Name  Last Name   E-mail Address  RN
3   Jane    Doe Jane.Doe@gmail.com  1
4   Jane    Doe Jane.Doe@gmail.com  1
1   John    Doe John.Doe@gmail.com  2
2   John    Doe John.Doe@gmail.com  2


问:
How to create a dynamic const name for an array using dropdown options in reactjs or nextjs?
Is it possible to create a dynamic const name of an array using dropdown options?</p>

```<code>Import {array1, array2, array3} from './myfilesystem/arrays';

const somename = array1;

</code>```

答:
```<code>import * as arr from '..pathname'

//  ..and somewhere in your code..
const someArray = arr.array1
</code>```

is that what u ment?

imports/exports :

exporting from a file, has many syntax variants

```<code>// explicit exports
export const PI = 3.14159
export const cylinderVolume = (r, h) => {....}

//export as an object..
const PI = 3.14159
const cylinderVolume = (r, h) => {....}

export { PI, cylinderVolume }

// default export
export default PI = 3.14159
export const cylinderVolume = (r, h) => {....}

imports

// importing explict exports
import { PI, cylinderVolume } from 'path'

//importing default and explict exports(PI is default and cylinderVolume is explict)
import PI, { cylinderVolume } from 'path'

// importing as whole..

import * as shape from 'path'
// useage..
const cylinderSurfaceArea = (r, h) => 2*shape.PI*r ( r + h )
</code>```

Re-export from another file..

```<code>export { cylinderVolume } from 'path'
// re-exporting as default..
export { default as PI } from 'path'
</code>```

comparing some impacts on size on usecases:

```<code>import _ from 'lodash' // use case..
import * as shape from 'path' // same effect..
</code>```

this will import the entire module and has a huge effect on the project size. however if we are using libs like lodash this is the way they recommend.

```<code>import { get, has } from 'lodash'
import { PI, cylinderVolume } from 'path'
</code>```

surprisingly this don't have any much size diffrence comparing with the above syntax.

Tree Shaking

Modern build tools (webpack and others) bundle modules together and optimize them to speedup loading and remove unused stuff.

so, in order to minimize the impact on size the recommended syntax would be

```<code>import get from 'lodash/get'
</code>```

but still when we have to import a whole load of stuff it's not practical(or recommended/ideal for the sake of readability)..

Body:
Is it possible to create a dynamic const name of an array using dropdown options?

Import {array1, array2, array3} from './myfilesystem/arrays';

const somename = array1;

Body:
import * as arr from '..pathname'

//  ..and somewhere in your code..
const someArray = arr.array1

is that what u ment?

imports/exports :

exporting from a file, has many syntax variants

// explicit exports
export const PI = 3.14159
export const cylinderVolume = (r, h) => {....}

//export as an object..
const PI = 3.14159
const cylinderVolume = (r, h) => {....}

export { PI, cylinderVolume }

// default export
export default PI = 3.14159
export const cylinderVolume = (r, h) => {....}

imports

// importing explict exports
import { PI, cylinderVolume } from 'path'

//importing default and explict exports(PI is default and cylinderVolume is explict)
import PI, { cylinderVolume } from 'path'

// importing as whole..

import * as shape from 'path'
// useage..
const cylinderSurfaceArea = (r, h) => 2*shape.PI*r ( r + h )

Re-export from another file..

export { cylinderVolume } from 'path'
// re-exporting as default..
export { default as PI } from 'path'

comparing some impacts on size on usecases:

import _ from 'lodash' // use case..
import * as shape from 'path' // same effect..

this will import the entire module and has a huge effect on the project size. however if we are using libs like lodash this is the way they recommend.

import { get, has } from 'lodash'
import { PI, cylinderVolume } from 'path'

surprisingly this don't have any much size diffrence comparing with the above syntax.

Tree Shaking

Modern build tools (webpack and others) bundle modules together and optimize them to speedup loading and remove unused stuff.

so, in order to minimize the impact on size the recommended syntax would be

import get from 'lodash/get'

but still when we have to import a whole load of stuff it's not practical(or recommended/ideal for the sake of readability)..


问:
How to sync two date fields input. A drift, need some guidance
I am creating a form using html and php, inside this form I have date input "from" and date input "to".
How can "to" get update with the date I select in "from"?
For example, if I select in the "from" July 1st, I want "to" to get update with the same date or the next day.

This is my form:

```<code><?php ob_start() ?>
<?php if(isset($params['message'])) :?>
    <b><span style="color: red;"><?php echo $params['message'] ?></span></b>
<?php endif; ?>
<?php
    date_default_timezone_set('America/Costa_Rica');
?>
<br/>
<form name="formInsertDocument" action="index.php?ctl=insertDocument" autocomplete="off" method="POST">
    <h2>Insert New Document</h2>
    <fieldset>
        <ul>
            <li>
                <label for="name">Type:</label>
                <input type="number" name="id_type" required value="<?php echo $params['id_type'] ?>" />
            </li>
            <li>
                <label for="name">Client:</label>
                <input type="number" name="id_client" required value="<?php echo $params['id_client'] ?>" />
            </li>
            <li>
                <label for="name">Date:</label>
                <input type="date" name="date_document" required value="<?php echo date('Y-m-d'); ?>" value="<?php echo $params['date_document'] ?>" />
            </li>
            <li>
                <label for="name">Arrival:</label>
                <input type="date" name="date_arrival" required value="<?php echo date('Y-m-d'); ?>" value="<?php echo $params['date_arrival'] ?>" />
            </li>
            <li>
                <label for="name">Departure:</label>
                <input type="date" name="date_leaving" required value="<?php echo date('Y-m-d'); ?>" value="<?php echo $params['date_leaving'] ?>" />
            </li>
            <li>
                <label for="name">Subtotal:</label>
                <input type="number" name="subtotal" required value="<?php echo $params['subtotal'] ?>" />
            </li>
            <li>
                <label for="name">Taxable:</label>
                <input type="number" name="taxable" required value=00000000 value="<?php echo $params['taxable'] ?>" />
            </li>
            <li>
                <label for="name">Tax:</label>
                <input type="number" name="tax" value=00000000 value="<?php echo $params['tax'] ?>" />
            </li>
            <li>
                <label for="name">Other:</label>
                <input type="number" name="other" required value="<?php echo $params['other'] ?>" />
            </li>
            <li>
                <label for="name">Total:</label>
                <input type="number" name="total" required value=0 value="<?php echo $params['total'] ?>" />
            </li>
        </ul>
    </fieldset>
    <input type="submit" value="Insert" name="insert" />
</form>
<?php $contenido = ob_get_clean() ?>
<?php include '../app/templates/layout.php' ?>
</code>```

答:
With javascript you'll have to use something like this:</p>

```<code><script>
  var date_arrival = document.getElementsByName('date_arrival')[0];
  var date_leave = document.getElementsByName('date_leave')[0];

  date_arrival.addEventListener('change', function() {
    date_leave.value = date_arrival.value;
  });
</script>
</code>```

Body:
I am creating a form using html and php, inside this form I have date input "from" and date input "to".
How can "to" get update with the date I select in "from"?
For example, if I select in the "from" July 1st, I want "to" to get update with the same date or the next day.

This is my form:

<?php ob_start() ?>
<?php if(isset($params['message'])) :?>
    <?php echo $params['message'] ?>
<?php endif; ?>
<?php
    date_default_timezone_set('America/Costa_Rica');
?>

<form name="formInsertDocument" action="index.php?ctl=insertDocument" autocomplete="off" method="POST">

Insert New Document

    <fieldset>

                Type:
                <input type="number" name="id_type" required value="<?php echo $params['id_type'] ?>" />

                Client:
                <input type="number" name="id_client" required value="<?php echo $params['id_client'] ?>" />

                Date:
                <input type="date" name="date_document" required value="<?php echo date('Y-m-d'); ?>" value="<?php echo $params['date_document'] ?>" />

                Arrival:
                <input type="date" name="date_arrival" required value="<?php echo date('Y-m-d'); ?>" value="<?php echo $params['date_arrival'] ?>" />

                Departure:
                <input type="date" name="date_leaving" required value="<?php echo date('Y-m-d'); ?>" value="<?php echo $params['date_leaving'] ?>" />

                Subtotal:
                <input type="number" name="subtotal" required value="<?php echo $params['subtotal'] ?>" />

                Taxable:
                <input type="number" name="taxable" required value=00000000 value="<?php echo $params['taxable'] ?>" />

                Tax:
                <input type="number" name="tax" value=00000000 value="<?php echo $params['tax'] ?>" />

                Other:
                <input type="number" name="other" required value="<?php echo $params['other'] ?>" />

                Total:
                <input type="number" name="total" required value=0 value="<?php echo $params['total'] ?>" />

    </fieldset>
    <input type="submit" value="Insert" name="insert" />
</form>
<?php $contenido = ob_get_clean() ?>
<?php include '../app/templates/layout.php' ?>

Body:
With javascript you'll have to use something like this:

<script>
  var date_arrival = document.getElementsByName('date_arrival')[0];
  var date_leave = document.getElementsByName('date_leave')[0];

  date_arrival.addEventListener('change', function() {
    date_leave.value = date_arrival.value;
  });
</script>


问:
How can I get back access to the backend of TYPO3 when fluidpages are causing an error on backend and frontend?
I got to work on a Typo3 page and I have to say I'm at the very beginning if it comes to TYPO3.

So I wanted to fix a bug and updated the plugin "fluidpages" from version 4.1.0 (I guess) to 4.3. That cause the "Oops, an error occurred!" in the backend and frontend, so I dont have access from that side. I still have the FTP login for the website. The version of TYPO3 is 8.7.18.

The errorcode I get is that one:

Could not analyse class:

  "FluidTYPO3\Flux\Configuration\ConfigurationManager" maybe not loaded
  or no autoloader?

  Class FluidTYPO3\Flux\Configuration\ConfigurationManager does not exist

So does anyone know what I need to do?

From my research I think I need to update another plugins to make it back to work? And can I update them just by uploading them through FTP?

Thanks in advance!

Edit: After I tried to get the old version of the plugin running, I'm getting this error code from the log file:

Mon, 17 Feb 2020 22:59:56 +0100 [ALERT] request="fec23f8baf6dc" component="TYPO3.CMS.Frontend.ContentObject.Exception.ProductionExceptionHandler": Oops, an error occurred! Code: 2020021722595594039a4d - {"exception":"TYPO3\CMS\Extbase\Mvc\Exception: The default controller for extension \"Flux\" and plugin \"Page\" can not be determined. Please check for TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin() in your ext_localconf.php.

答: Have you tried dumping autoload from Install Tool? Generally, it would help for the class not loaded problem. Otherwise, you may want to check the log at typo3/temp/var/log/ and find the errors in code.</p>


问:
How to generate certs for secured connection from Celery to Redis
I'm following this tutorial, and adjusting the Celery-background related code to my project.

In my case I am operating in a Docker environment, and I have a secured site (i.e. https://localhost) which requires secured ssl communication.

The documentation in here shows an example on how to provide cert related files (keyfile, certfile, ca_certs).

But it is not clear to me how to create these files in the first place.

The tutorial in here shows how to create a custom certificate authority, and how to sign a certificate with it.

I followed the steps and created the 3 files:

keyfile - dev.mergebot.com.crt  - the signed certificate (signed by myCA.pem)

ca_certs - dev.mergebot.com.key - private key to create a signed cert with "self-trusted CA"

certfile - myCA.pem - "self-trusted CA" certificate (filename in the tutorial: myCA.pem)

Note that I created these 3 files completely unrelated to Celery or Redis or Docker.
They were created in my local machine outside Docker. The files don't have the name of the Redis container and the Common Name in the cert was set to "foo"

When I use these files in my webapp, there is no connection from Celery to Redis.

Without ssl I do get a connection, so the overall environment aside from ssl is OK - see here

Is there any specific requirements to create the cert related files? (e.g. should the Common Name in the cert have the container name "redis", etc... )

Is there a way to test the validity of the certs without the app, e.g. by issuing a command from the container shell?

Thanks

答:
I was able to generate the cert related files (keyfile, certfile, ca_certs) using the tutorial in here

I first tested that I can connect from my localhost to the "redis with ssl" docker container.
and I described the details here

Then I tested that I can connect from Celery docker container to the "redis with ssl" docker container
and I described the details here


问:
Kotlin print issue with farenheit conversion
I tried to print out:

F degrees Fahrenheit = C degrees Celsius

and I can't get it to work I have tried so many things also be nice I'm new to coding.

```<code>fun main(args: Array<String>) {
  var F = "32";
  var C = (F - 32) * .5555556;
  var conversion = "F  degrees Fahrenheit = C degrees Celsius"
  println(conversion);
}
</code>```

答:
You can use a template string:

```<code>fun main() {
    var f = 68.0;
    var c = (f - 32.0) * 5.0 / 9.0;

    var conversion = "$f degrees Fahrenheit = $c degrees Celsius"

    println(conversion)
}
</code>```

Other things to note:

I've used a floating point number instead of a string for the f variable. This allows me to use floating point math to calculate the Celsius equivalent.

I renamed the variables to be lowercase, as per the coding conventions.

I replaced the .5555556 literal with 5.0 / 9.0. Better to introduce rounding errors later rather than earlier.

Even though in this case it's sufficient to only explicitly turn the f variable into a floating point number to force floating point math to be used, it's probably safer to just apply the same logic to all numbers.

Body:
I tried to print out:

F degrees Fahrenheit = C degrees Celsius

and I can't get it to work I have tried so many things also be nice I'm new to coding.

fun main(args: Array<String>) {
  var F = "32";
  var C = (F - 32) * .5555556;
  var conversion = "F  degrees Fahrenheit = C degrees Celsius"
  println(conversion);
}

Body:
You can use a template string:

fun main() {
    var f = 68.0;
    var c = (f - 32.0) * 5.0 / 9.0;

    var conversion = "$f degrees Fahrenheit = $c degrees Celsius"

    println(conversion)
}

Other things to note:

I've used a floating point number instead of a string for the f variable. This allows me to use floating point math to calculate the Celsius equivalent.

I renamed the variables to be lowercase, as per the coding conventions.

I replaced the .5555556 literal with 5.0 / 9.0. Better to introduce rounding errors later rather than earlier.

Even though in this case it's sufficient to only explicitly turn the f variable into a floating point number to force floating point math to be used, it's probably safer to just apply the same logic to all numbers.


问:
Kubernetes Pod stuck in CrashLoopBackOff

Dockerfile

```<code>FROM ubuntu
MAINTAINER user@gmail.com
RUN apt-get update
RUN apt-get install -y openjdk-8-jdk
ADD build/libs/micro-service-gradle-0.0.1-SNAPSHOT.jar /var/local/
ENTRYPOINT exec java $JAVA_OPTS \
 -jar /var/local/micro-service-gradle-0.0.1-SNAPSHOT.jar
EXPOSE 8080
</code>```

deployment.yaml

```<code>apiVersion: apps/v1
kind: Deployment
metadata:
  name: micro-service-gradle
  labels:
    app: micro-service-gradle
spec:
  replicas: 1
  selector:
    matchLabels:
      app: micro-service-gradle
  template:
    metadata:
      labels:
        app: micro-service-gradle
    spec:
      containers:
      - name: micro-service-gradle
        image: micro-service-gradle:latest
        ports:
        - containerPort: 8080
</code>```

Deploying spring boot application in Kubernetes . Pod is not getting created. When i check kubectl get pods. it says CrashLoopBackOff.

```<code>NAME                                  READY   STATUS             RESTARTS   AGE
micro-service-gradle-fc97c97b-8hwhg   0/1     CrashLoopBackOff   6          6m23s
</code>```

I tried to check logs for the same container. Logs are empty

```<code>kubectl logs -p micro-service-gradle-fc97c97b-8hwhg
</code>```

I created the container manually using docker run. There is no issues in image and containers works fine.

How to verify the logs for why the pods in crash status.

答:
I ran into a similar issue. When I run

```<code>kubectl describe pod <podname>
</code>```

and read the events, Though the image was pulled, message outputted was 'restarting failed container'
The pod was crashing because it was not performing any task. To keep it running, I add a sleep command based on similar example in the docs

```<code>  command: ['sh', '-c', 'echo The app is running! && sleep 3600']
</code>```

This SO answer also mentions running an infinite could also solve the problem
https://stackoverflow.com/a/55610769/7128032

Body:
Dockerfile

FROM ubuntu
MAINTAINER user@gmail.com
RUN apt-get update
RUN apt-get install -y openjdk-8-jdk
ADD build/libs/micro-service-gradle-0.0.1-SNAPSHOT.jar /var/local/
ENTRYPOINT exec java $JAVA_OPTS \
 -jar /var/local/micro-service-gradle-0.0.1-SNAPSHOT.jar
EXPOSE 8080

deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: micro-service-gradle
  labels:
    app: micro-service-gradle
spec:
  replicas: 1
  selector:
    matchLabels:
      app: micro-service-gradle
  template:
    metadata:
      labels:
        app: micro-service-gradle
    spec:
      containers:
      - name: micro-service-gradle
        image: micro-service-gradle:latest
        ports:
        - containerPort: 8080

Deploying spring boot application in Kubernetes . Pod is not getting created. When i check kubectl get pods. it says CrashLoopBackOff.

NAME                                  READY   STATUS             RESTARTS   AGE
micro-service-gradle-fc97c97b-8hwhg   0/1     CrashLoopBackOff   6          6m23s

I tried to check logs for the same container. Logs are empty

kubectl logs -p micro-service-gradle-fc97c97b-8hwhg

I created the container manually using docker run. There is no issues in image and containers works fine.

How to verify the logs for why the pods in crash status.

Body:
I ran into a similar issue. When I run

kubectl describe pod <podname>

and read the events, Though the image was pulled, message outputted was 'restarting failed container'
The pod was crashing because it was not performing any task. To keep it running, I add a sleep command based on similar example in the docs

  command: ['sh', '-c', 'echo The app is running! && sleep 3600']

This SO answer also mentions running an infinite could also solve the problem
https://stackoverflow.com/a/55610769/7128032


问:
Json object array
```<code>.ajax({
  cache: false,
    url: '/Dashboard/ListofNames',
    data: {
        charSearch: txtboxvalue
    },
    success: function (res){
        var obj = JSON.parse(res); //this object contains 1 index which is 0.
        var parseObj = JSON.parse(obj[0].JsonResult) // This line is working i successfully gets the data from index 0
        var parseObj2 = JSON.parse(obj[1].JsonResult) //This is not working because index 1 is not existing, what i want is instead of getting an undefined exception, i want to set the index 1 into an empty string or whatever solution that i wont get any undefined exception.

    }
});
</code>```

Any suggestion would really help me thanks.

答: Found out a solution. I checked all of the undefined obj and set a new value for each. I created a loop to check every undefined obj after that i created a new object with Empty string and push it inside my jsonresult. Not a good practice, but it does the job. </p>

Title: Json object array

Body:
.ajax({
  cache: false,
    url: '/Dashboard/ListofNames',
    data: {
        charSearch: txtboxvalue
    },
    success: function (res){
        var obj = JSON.parse(res); //this object contains 1 index which is 0.
        var parseObj = JSON.parse(obj[0].JsonResult) // This line is working i successfully gets the data from index 0
        var parseObj2 = JSON.parse(obj[1].JsonResult) //This is not working because index 1 is not existing, what i want is instead of getting an undefined exception, i want to set the index 1 into an empty string or whatever solution that i wont get any undefined exception.

    }
});

Any suggestion would really help me thanks.


问:
Desc Order in SubQueries
With this input, how do I use ORDER BY to get descending order for a subquery? It is not applying to the data in the column.

答:
Instead of a correlated subquery, you can directly use Regular INNER JOIN among those tables including aliasing without quotes :

```<code>SELECT i.name, COUNT(*) AS NumberOfSections
  FROM instructor i
  JOIN teaches t
    ON i.ID = t.ID
 GROUP BY i.name
HAVING COUNT(*) >= 2
 ORDER BY NumberOfSections DESC;
</code>```

If you still want to use quotes, use double-quotes( "NumberOfSections", in this case also possible to use spaces such as "Number Of Sections" ) rather than single for both places ( aliasing COUNT and within the ORDER BY list )

Title: Desc Order in SubQueries

Body:
Instead of a correlated subquery, you can directly use Regular INNER JOIN among those tables including aliasing without quotes :

SELECT i.name, COUNT(*) AS NumberOfSections
  FROM instructor i
  JOIN teaches t
    ON i.ID = t.ID
 GROUP BY i.name
HAVING COUNT(*) >= 2
 ORDER BY NumberOfSections DESC;

If you still want to use quotes, use double-quotes( "NumberOfSections", in this case also possible to use spaces such as "Number Of Sections" ) rather than single for both places ( aliasing COUNT and within the ORDER BY list )


问:
Sort a list based on repetition values
I have a string list like this : {3,2,2,1,1,1,1,4,4,4} And i want sort it by number of repetition of values so that the be this {1,1,1,1,2,2,4,4,4,3} Thanks for you attenttion</p>

答:
You can sort the list based on repetition using Collections.frequency with Comparator.comparingInt

```<code>Comparator.comparingInt(i->Collections.frequency(list, i)).reversed()
</code>```

Below is the example

```<code>    List<Integer>  list = new ArrayList<>(List.of(3,2,2,1,1,1,1,4,4,4));

    System.out.println(list);

    list.sort(Comparator.comparingInt(i->Collections.frequency(list, i)).reversed());

    System.out.println(list);  //[1, 1, 1, 1, 4, 4, 4, 2, 2, 3]
</code>```

Instead of checking the frequency of each and every element in List, you can do it in other way by grouping the element and count into Map<Integer, Long> and then creating another sorted list Collections.nCopies

```<code>List<Integer> result = list.stream()
                       .collect(Collectors.groupingBy(Function.identity(),Collectors.counting()))
                       .entrySet()
                       .stream()
                       .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
                       .map(entry->Collections.nCopies(entry.getValue().intValue(), entry.getKey()))
                       .flatMap(List::stream)
                       .collect(Collectors.toList());
</code>```

Title: Sort a list based on repetition values

Body:
You can sort the list based on repetition using Collections.frequency with Comparator.comparingInt

Comparator.comparingInt(i->Collections.frequency(list, i)).reversed()

Below is the example

    List<Integer>  list = new ArrayList<>(List.of(3,2,2,1,1,1,1,4,4,4));

    System.out.println(list);

    list.sort(Comparator.comparingInt(i->Collections.frequency(list, i)).reversed());

    System.out.println(list);  //[1, 1, 1, 1, 4, 4, 4, 2, 2, 3]

Instead of checking the frequency of each and every element in List, you can do it in other way by grouping the element and count into Map<Integer, Long> and then creating another sorted list Collections.nCopies

List<Integer> result = list.stream()
                       .collect(Collectors.groupingBy(Function.identity(),Collectors.counting()))
                       .entrySet()
                       .stream()
                       .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
                       .map(entry->Collections.nCopies(entry.getValue().intValue(), entry.getKey()))
                       .flatMap(List::stream)
                       .collect(Collectors.toList());


问:
UIView background image gets squashed
In my iPhone app I have a UIView with a tiled background image created via view.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:@"IndexCard.png"]];

On my iOS3.1 device, when the view gets resized, the background image gets squashed - i.e. it tiles the same number of times but the height of each tile is reduced. Instead I would like each tile to stay the same size but the number of repeats to adjust according to the new view size. If I clear the background and then reset it the problem gets fixed, but that seems like a particular innefficient solution to the problem. On the iOS4.3 simulator it works correctly.

Here's the original image - 12 lines:

Here's what I'm seeing when I resize the view - it still has 12 lines:

Whereas here's what I'd really like to see - the background would be cropped to 5 lines:

Any ideas?

答:
I found a much simpler solution:</p>

```<code>view.contentMode = UIViewContentModeRedraw;
// instead of the default UIViewContentModeScaleToFill
</code>```

ContentLicense: CC BY-SA 3.0

Title: UIView background image gets squashed

Body:
I found a much simpler solution:

view.contentMode = UIViewContentModeRedraw;
// instead of the default UIViewContentModeScaleToFill


问:
Why do user agents / browsers lie
I have read several articles on feature detection and that it is more reliable than browser detection because browsers lie. </p>

<p>I couldn't find any information on why they lie. Does anyone know the reason why they would do that? </p>

答:
Another more modern reason is to just avoid demands to install mobile apps (where product owners contol what I can and can't do with content. No thanks!).

Today Reddit started to block viewing subreddits in case they detect a mobile browser in UserAgent so I had to change it just to be able to view content.

Title: Why do user agents / browsers lie

Body:
I have read several articles on feature detection and that it is more reliable than browser detection because browsers lie.

I couldn't find any information on why they lie. Does anyone know the reason why they would do that?


问:
'tensorflow' has no attribute 'Session'
I am trying to convert a Tensor to a numpy array.
The tensor i have has a shape as below

```<code>LastDenseLayer.output.shape
TensorShape([None, 128])
</code>```

When i am running the code as below,

```<code>with tf.Session() as sess:
    LastLayer = LastDenseLayer.output.eval()
</code>```

getting the below error

module 'tensorflow' has no attribute 'Session'

I am running Keras model and trying to get the values of a specific layer out of that.

Unable to understand that is wrong here.

Regards
Sachin

答: TensorFlow 2.x removed tf.Session because eager execution is now a default. Please refer to the TensorFlow migration guide for more information.

Title: 'tensorflow' has no attribute 'Session'

Body:
I am trying to convert a Tensor to a numpy array.
The tensor i have has a shape as below

LastDenseLayer.output.shape
TensorShape([None, 128])

When i am running the code as below,

with tf.Session() as sess:
    LastLayer = LastDenseLayer.output.eval()

getting the below error

module 'tensorflow' has no attribute 'Session'

I am running Keras model and trying to get the values of a specific layer out of that.

Unable to understand that is wrong here.

Regards
Sachin


问:
Text semantic preprocessing
Let assume that I have a dataset of car accidents. Each accident has a textual description made using a set of cameras and other sensors.

Suppose now I have only the data of a single camera (e.g. the frontal) and I want to remove all the sentences of the description that are not related to it. I think a basic and easy solution could be to use a boolean retrieval system using a set of specific keywords to remove unwanted sentences, but I don't know neither if it is a good idea ner if it could work; could someone suggest me any idea? What kind of statistics might be useful to study this problem? Thanks

答:
Regex could be one solution.
I created a regex matching the word "front", case insensitive, which searches for front and then get the whole sentences with one or more matches.
The results can be trimmed some from starting white spaces. (Can probably be removed as well with some fine tuning.)

The word you can swap out through some variable taking values from a list, if you need "front", "rear", "side", "right", "left" or other.

Regex Example https://regex101.com/r/ZHU0kr/5

Title: Text semantic preprocessing


问:
How to pass variables as parameters to an Aspect
```<code>@Component("taskCreateListener")
public class TaskCreateListener implements FlowableEventListener {

@LogMethod
    @DetermineCaseTypeOfWork
    @Override
    public void onEvent(FlowableEvent event) {

///Do stuff that results in variables I want to pass to aspect
//For example, get ids and details and set to variables that I want to pass to insertThing() method once onEvent(FlowableEvent event) is finished executing
//ex:
//String procInstId = "abc1234";
//String type = "case1";
}

</code>```

I need the onEvent to fully complete and then get local variables set in onEvent(FlowableEvent event) passed into my aspect insertThing() method:

```<code>@Aspect
@Component
public class DetermineCaseTypeOfWork {

@Transactional
@After(@annotation(path goes here))
public void insertThing() {
    //Do something here with the variables passed in from doSomething method
//if(procInstId.equals("abc1234") && type.equals("case1")) {
//do something
} else if(//other id and type) {
//do something else
} else {
//do something else
}
}
</code>```

I can't modify the onEvent(FlowableEvent event) method to return something and the onEvent(FlowableEvent event) method has to fully complete first, so how would I go about passing parameters into insertThing()?

答:
Preface / Rationale

I would not suggest to use Daniil's solution because

it adds the complexity of handling a thread-local variable to both the aspect (OK) and the core business code (not OK in my opinion),

the context holder, being a map, is not particularly type-safe,

the core business code does not work anymore without the aspect (it relies on the aspect initialising the context holder) and is inextricably linked to it, which is a bad design decision.

The main problem is in the OP's (moesyzlack23) way of thinking: He said, he wants to "pass parameters to the aspect". This is violating the basic AOP principle that the aspect should know how to add cross-cutting behaviour but the application code should be agnostic of the aspect.

AspectJ solution

I would suggest to

just add a method responsible for calculating the results to the TaskCreateListener class and calling it from onEvent(..),

switch from Spring AOP to AspectJ as described in the Spring manual and use features like cflowbelow pointcut and percflow aspect instantiation, thus getting rid of thread-locals and making the core code agnostic of AOP again,

optionally converting the Map<String, Object> into a more type-safe data object with regular getter methods. This would only be difficult if the aspect applies to many annotated methods with a very diverse set of data to be handled. But to me it looks like this aspect is pretty specific, though.

Here is an example in plain AspectJ (no Spring) which you can easily integrate into your Spring application after enabling full AspectJ:

Helper classes:

package de.scrum_master.app;

public class FlowableEvent {}
```

<pre class="lang-java prettyprint-override"><code>package de.scrum_master.app;

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Retention(RUNTIME)
@Target(METHOD)
public @interface DetermineCaseTypeOfWork {}
</code>```

Aspect target class:

package de.scrum_master.app;

public class TaskCreateListener {
  @DetermineCaseTypeOfWork
  public void onEvent(FlowableEvent event) {
    // Calculate values which might be dependent on 'event' or not
    Data data = calculateData(event);
    System.out.println("[" + Thread.currentThread().getId() + "] onEvent: " + data);
  }

  public Data calculateData(FlowableEvent event) {
    return new Data("thread-" + Thread.currentThread().getId(), "case1");
  }

  public static class Data {
    private String procInstId;
    private String type;

    public Data(String procInstId, String type) {
      this.procInstId = procInstId;
      this.type = type;
    }

    public String getProcInstId() {
      return procInstId;
    }

    public String getType() {
      return type;
    }

    @Override
    public String toString() {
      return "Data[procInstId=" + procInstId + ", type=" + type + "]";
    }
  }
}
```

<p>The inner <code>Data</code> class is optional, you could just continue to use a <code>Map<String, Object></code> and refactor the class and the aspect (see below) so as to use the map instead.</p>

<p><strong>Driver application starting several threads:</strong></p>

<pre class="lang-java prettyprint-override"><code>package de.scrum_master.app;

public class Application {
  public static void main(String[] args) {
    for (int taskCount = 0; taskCount < 5; taskCount++) {
      new Thread(() -> new TaskCreateListener().onEvent(new FlowableEvent())).start();
    }
  }
}
</code>```

Console log without aspect:

[11] onEvent: Data[procInstId=thread-11, type=case1]
[12] onEvent: Data[procInstId=thread-12, type=case1]
[13] onEvent: Data[procInstId=thread-13, type=case1]
[10] onEvent: Data[procInstId=thread-10, type=case1]
[14] onEvent: Data[procInstId=thread-14, type=case1]
```

<p>So far, so simple.</p>

<p><strong>Aspect:</strong></p>

<pre class="lang-java prettyprint-override"><code>package de.scrum_master.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

import de.scrum_master.app.TaskCreateListener.Data;

@Aspect("percflow(myPointcut())")
public class DetermineTypeOfWorkAspect {
  private Data data;

  @Pointcut("execution(* *(..)) && @annotation(de.scrum_master.app.DetermineCaseTypeOfWork)")
  private void myPointcut() {}

  @Around("myPointcut()")
  public void insertThing(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("[" + Thread.currentThread().getId() + "] " + joinPoint);
    joinPoint.proceed();
    System.out.println("[" + Thread.currentThread().getId() + "] " + "insertThing: " + data);
  }

  @AfterReturning(pointcut = "execution(* *(..)) && cflowbelow(myPointcut())", returning = "result")
  public void saveData(JoinPoint joinPoint, Data result) throws Throwable {
    System.out.println("[" + Thread.currentThread().getId() + "] " + joinPoint);
    data = result;
  }
}
</code>```

Please note:

@Aspect("percflow(myPointcut())") makes sure that the aspect is not a singleton, which would be the default. Instead, one aspect instance is created each time the application enters the control flow of myPointcut(), i.e. each time a method annotated by DetermineCaseTypeOfWork is being executed.

The @Around advice insertThing relies on the @AfterReturning advice saveData being executed during its waiting for joinPoint.proceed() to return.

The @AfterReturning advice saveData gets triggered for every method execution below the control flow of myPointcut() and returning a Data object. Methods returning something else or being executed outside the specified control flow will be ignored. The advice makes sure the result of the intercepted method call is being assigned to a private Data variable which can later be accessed by the insertThing advice.

I am adding execution(* *(..)) && to the pointcuts because in AspectJ there are other joinpoints such as method call() in addition method execution being the only supported type in Spring AOP. So there you don't need to be so specific, in AspectJ you ought to.

If you remove the percflow(myPointcut()) instantiation from the @Aspect annotation, you will have to make the private Data member a ThreadLocal<Data> instead in order to make the aspect thread-safe again. This also works and still keeps the core application free from thread-local handling, but the aspect itself would have to deal with it.

Console log with active aspect:

[10] execution(void de.scrum_master.app.TaskCreateListener.onEvent(FlowableEvent))
[14] execution(void de.scrum_master.app.TaskCreateListener.onEvent(FlowableEvent))
[12] execution(void de.scrum_master.app.TaskCreateListener.onEvent(FlowableEvent))
[13] execution(void de.scrum_master.app.TaskCreateListener.onEvent(FlowableEvent))
[11] execution(void de.scrum_master.app.TaskCreateListener.onEvent(FlowableEvent))
[14] execution(TaskCreateListener.Data de.scrum_master.app.TaskCreateListener.calculateData(FlowableEvent))
[14] onEvent: Data[procInstId=thread-14, type=case1]
[14] insertThing: Data[procInstId=thread-14, type=case1]
[11] execution(TaskCreateListener.Data de.scrum_master.app.TaskCreateListener.calculateData(FlowableEvent))
[11] onEvent: Data[procInstId=thread-11, type=case1]
[10] execution(TaskCreateListener.Data de.scrum_master.app.TaskCreateListener.calculateData(FlowableEvent))
[12] execution(TaskCreateListener.Data de.scrum_master.app.TaskCreateListener.calculateData(FlowableEvent))
[12] onEvent: Data[procInstId=thread-12, type=case1]
[10] onEvent: Data[procInstId=thread-10, type=case1]
[10] insertThing: Data[procInstId=thread-10, type=case1]
[12] insertThing: Data[procInstId=thread-12, type=case1]
[11] insertThing: Data[procInstId=thread-11, type=case1]
[13] execution(TaskCreateListener.Data de.scrum_master.app.TaskCreateListener.calculateData(FlowableEvent))
[13] onEvent: Data[procInstId=thread-13, type=case1]
[13] insertThing: Data[procInstId=thread-13, type=case1]
```

<p>Please note how the thread IDs at the beginning of each log line correspond to the value of <code>procInstId</code>. This proves that it actually works without thread-locals due to the <code>percflow</code> aspect instantiation model.</p>

<h2>Spring AOP solution</h2>

<p><strong>Alternative with Spring AOP:</strong> If you want to stick with Spring AOP, you can use neither <code>percflow</code> instantiation nor <code>cflowbelow</code> pointcuts because Spring AOP just does not support those features. So instead of the former you could still use a <code>ThreadLocal</code> inside the aspect and instead of the latter you could factor the calculation out into a separate Spring component/bean and make sure the <code>saveData</code> advice intercepts that one instead. So probably the cost of not having to use AspectJ (if you are so inclined to avoid it) would still be acceptable: one thread-local plus one new component. Please let me know if you are interested in that approach.</p>

<hr>

<p><strong>Update:</strong></p>

<blockquote>
  <p>I would also be interested in seeing your approach using Spring AOP if you wouldn't mind sharing.</p>
</blockquote>

<p>Fine. I will post the complete MCVE again with different package names in order to disambiguate all classes (some with minor or major changes) from the AspectJ sample code.</p>

<p><strong>Helper classes:</strong></p>

<pre class="lang-java prettyprint-override"><code>package de.scrum_master.spring.q60234800;

public class FlowableEvent {}
</code>```

package de.scrum_master.spring.q60234800;

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Retention(RUNTIME)
@Target(METHOD)
public @interface DetermineCaseTypeOfWork {}
```

<p><strong>Data provider component:</strong></p>

<p>This is the new component/bean I was talking about. Again, instead of the inner <code>Data</code> class you could use a <code>Map</code> but that would be less type-safe. The decision depends on how specific or generic you need your solution to be. What is important here is that the provider itself is a singleton bean but provides a new <code>Data</code> instance on each <code>calculateData(..)</code> call. So you need to make sure that method only depends on its input parameters and not on class fields in order to be thread-safe.</p>

<pre class="lang-java prettyprint-override"><code>package de.scrum_master.spring.q60234800;

import org.springframework.stereotype.Component;

@Component
public class DataProvider {
  public Data calculateData(FlowableEvent event) {
    return new Data("thread-" + Thread.currentThread().getId(), "event-" + event.hashCode());
  }

  public static class Data {
    private String procInstId;
    private String type;

    public Data(String procInstId, String type) {
      this.procInstId = procInstId;
      this.type = type;
    }

    @Override
    public String toString() {
      return "Data[procInstId=" + procInstId + ", type=" + type + "]";
    }
  }
}
</code>```

Listener component:

This is also a normal singleton bean which gets the data provider auto-injected.

package de.scrum_master.spring.q60234800;

import de.scrum_master.spring.q60234800.DataProvider.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class TaskCreateListener {
  @Autowired
  DataProvider dataProvider;

  @DetermineCaseTypeOfWork
  public void onEvent(FlowableEvent event) {
    // Calculate values which might be dependent on 'event' or not
    Data data = dataProvider.calculateData(event);
    System.out.println("[" + Thread.currentThread().getId() + "] onEvent: " + data);
  }
}
```

<p><strong>Driver application:</strong></p>

<p>Again, the application creates multiple threads and fires <code>TaskCreateListener.onEvent(..)</code> for each of them.</p>

<pre class="lang-java prettyprint-override"><code>package de.scrum_master.spring.q60234800;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

import java.util.stream.IntStream;

@SpringBootApplication
@Configuration
@EnableAspectJAutoProxy//(proxyTargetClass = true)
public class Application {
  public static void main(String[] args) {
    try (ConfigurableApplicationContext appContext = SpringApplication.run(Application.class, args)) {
      TaskCreateListener taskCreateListener = appContext.getBean(TaskCreateListener.class);
      IntStream.range(0, 5).forEach(i ->
        new Thread(() -> taskCreateListener.onEvent(new FlowableEvent())).start()
      );
    }
  }
}
</code>```

Spring AOP aspect:

As described earlier, we need a ThreadLocal<Data> field for thread-safety because also the aspect is a singleton bean. The combination of two pointcut/advice pairs targeting two different components makes sure that first we gather and save the right Data and then use them in the other advice.

package de.scrum_master.spring.q60234800;

import de.scrum_master.spring.q60234800.DataProvider.Data;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class DetermineTypeOfWorkAspect {
  private ThreadLocal<Data> data = new ThreadLocal<>();

  @Around("@annotation(de.scrum_master.spring.q60234800.DetermineCaseTypeOfWork)")
  public void insertThing(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("[" + Thread.currentThread().getId() + "] " + joinPoint);
    joinPoint.proceed();
    System.out.println("[" + Thread.currentThread().getId() + "] " + "insertThing: " + data.get());
  }

  @AfterReturning(pointcut = "execution(* calculateData(..))", returning = "result")
  public void saveData(JoinPoint joinPoint, Data result) throws Throwable {
    System.out.println("[" + Thread.currentThread().getId() + "] " + joinPoint);
    data.set(result);
  }
}
```

<p><strong>Console log:</strong></p>

<p>Just like in the AspectJ solution the thread IDs at the beggining of the log lines correspond with the ones captured in the <code>Data</code> objects.</p>

<pre class="lang-none prettyprint-override"><code>  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.5.2.RELEASE)

(...)
2020-02-20 08:03:47.494  INFO 12864 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2020-02-20 08:03:47.498  INFO 12864 --- [           main] d.s.spring.q60234800.Application         : Started Application in 4.429 seconds (JVM running for 5.986)
[33] execution(void de.scrum_master.spring.q60234800.TaskCreateListener.onEvent(FlowableEvent))
[32] execution(void de.scrum_master.spring.q60234800.TaskCreateListener.onEvent(FlowableEvent))
[35] execution(void de.scrum_master.spring.q60234800.TaskCreateListener.onEvent(FlowableEvent))
[34] execution(void de.scrum_master.spring.q60234800.TaskCreateListener.onEvent(FlowableEvent))
[36] execution(void de.scrum_master.spring.q60234800.TaskCreateListener.onEvent(FlowableEvent))
[33] execution(Data de.scrum_master.spring.q60234800.DataProvider.calculateData(FlowableEvent))
[35] execution(Data de.scrum_master.spring.q60234800.DataProvider.calculateData(FlowableEvent))
[34] execution(Data de.scrum_master.spring.q60234800.DataProvider.calculateData(FlowableEvent))
[33] onEvent: Data[procInstId=thread-33, type=event-932577999]
[33] insertThing: Data[procInstId=thread-33, type=event-932577999]
[34] onEvent: Data[procInstId=thread-34, type=event-1335128372]
[34] insertThing: Data[procInstId=thread-34, type=event-1335128372]
[36] execution(Data de.scrum_master.spring.q60234800.DataProvider.calculateData(FlowableEvent))
[36] onEvent: Data[procInstId=thread-36, type=event-130476008]
[32] execution(Data de.scrum_master.spring.q60234800.DataProvider.calculateData(FlowableEvent))
[36] insertThing: Data[procInstId=thread-36, type=event-130476008]
[35] onEvent: Data[procInstId=thread-35, type=event-987686114]
[35] insertThing: Data[procInstId=thread-35, type=event-987686114]
[32] onEvent: Data[procInstId=thread-32, type=event-1849439251]
[32] insertThing: Data[procInstId=thread-32, type=event-1849439251]
</code>```

Body:
@Component("taskCreateListener")
public class TaskCreateListener implements FlowableEventListener {

@LogMethod
    @DetermineCaseTypeOfWork
    @Override
    public void onEvent(FlowableEvent event) {

///Do stuff that results in variables I want to pass to aspect
//For example, get ids and details and set to variables that I want to pass to insertThing() method once onEvent(FlowableEvent event) is finished executing
//ex:
//String procInstId = "abc1234";
//String type = "case1";
}

I need the onEvent to fully complete and then get local variables set in onEvent(FlowableEvent event) passed into my aspect insertThing() method:

@Aspect
@Component
public class DetermineCaseTypeOfWork {

@Transactional
@After(@annotation(path goes here))
public void insertThing() {
    //Do something here with the variables passed in from doSomething method
//if(procInstId.equals("abc1234") && type.equals("case1")) {
//do something
} else if(//other id and type) {
//do something else
} else {
//do something else
}
}

I can't modify the onEvent(FlowableEvent event) method to return something and the onEvent(FlowableEvent event) method has to fully complete first, so how would I go about passing parameters into insertThing()?

Body:
Preface / Rationale

I would not suggest to use Daniil's solution because

it adds the complexity of handling a thread-local variable to both the aspect (OK) and the core business code (not OK in my opinion),

the context holder, being a map, is not particularly type-safe,

the core business code does not work anymore without the aspect (it relies on the aspect initialising the context holder) and is inextricably linked to it, which is a bad design decision.

The main problem is in the OP's (moesyzlack23) way of thinking: He said, he wants to "pass parameters to the aspect". This is violating the basic AOP principle that the aspect should know how to add cross-cutting behaviour but the application code should be agnostic of the aspect.

AspectJ solution

I would suggest to

just add a method responsible for calculating the results to the TaskCreateListener class and calling it from onEvent(..),

switch from Spring AOP to AspectJ as described in the Spring manual and use features like cflowbelow pointcut and percflow aspect instantiation, thus getting rid of thread-locals and making the core code agnostic of AOP again,

optionally converting the Map<String, Object> into a more type-safe data object with regular getter methods. This would only be difficult if the aspect applies to many annotated methods with a very diverse set of data to be handled. But to me it looks like this aspect is pretty specific, though.

Here is an example in plain AspectJ (no Spring) which you can easily integrate into your Spring application after enabling full AspectJ:

Helper classes:

package de.scrum_master.app;

public class FlowableEvent {}

package de.scrum_master.app;

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Retention(RUNTIME)
@Target(METHOD)
public @interface DetermineCaseTypeOfWork {}

Aspect target class:

package de.scrum_master.app;

public class TaskCreateListener {
  @DetermineCaseTypeOfWork
  public void onEvent(FlowableEvent event) {
    // Calculate values which might be dependent on 'event' or not
    Data data = calculateData(event);
    System.out.println("[" + Thread.currentThread().getId() + "] onEvent: " + data);
  }

  public Data calculateData(FlowableEvent event) {
    return new Data("thread-" + Thread.currentThread().getId(), "case1");
  }

  public static class Data {
    private String procInstId;
    private String type;

    public Data(String procInstId, String type) {
      this.procInstId = procInstId;
      this.type = type;
    }

    public String getProcInstId() {
      return procInstId;
    }

    public String getType() {
      return type;
    }

    @Override
    public String toString() {
      return "Data[procInstId=" + procInstId + ", type=" + type + "]";
    }
  }
}

The inner Data class is optional, you could just continue to use a Map<String, Object> and refactor the class and the aspect (see below) so as to use the map instead.

Driver application starting several threads:

package de.scrum_master.app;

public class Application {
  public static void main(String[] args) {
    for (int taskCount = 0; taskCount < 5; taskCount++) {
      new Thread(() -> new TaskCreateListener().onEvent(new FlowableEvent())).start();
    }
  }
}

Console log without aspect:

[11] onEvent: Data[procInstId=thread-11, type=case1]
[12] onEvent: Data[procInstId=thread-12, type=case1]
[13] onEvent: Data[procInstId=thread-13, type=case1]
[10] onEvent: Data[procInstId=thread-10, type=case1]
[14] onEvent: Data[procInstId=thread-14, type=case1]

So far, so simple.

Aspect:

package de.scrum_master.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

import de.scrum_master.app.TaskCreateListener.Data;

@Aspect("percflow(myPointcut())")
public class DetermineTypeOfWorkAspect {
  private Data data;

  @Pointcut("execution(* *(..)) && @annotation(de.scrum_master.app.DetermineCaseTypeOfWork)")
  private void myPointcut() {}

  @Around("myPointcut()")
  public void insertThing(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("[" + Thread.currentThread().getId() + "] " + joinPoint);
    joinPoint.proceed();
    System.out.println("[" + Thread.currentThread().getId() + "] " + "insertThing: " + data);
  }

  @AfterReturning(pointcut = "execution(* *(..)) && cflowbelow(myPointcut())", returning = "result")
  public void saveData(JoinPoint joinPoint, Data result) throws Throwable {
    System.out.println("[" + Thread.currentThread().getId() + "] " + joinPoint);
    data = result;
  }
}

Please note:

@Aspect("percflow(myPointcut())") makes sure that the aspect is not a singleton, which would be the default. Instead, one aspect instance is created each time the application enters the control flow of myPointcut(), i.e. each time a method annotated by DetermineCaseTypeOfWork is being executed.

The @Around advice insertThing relies on the @AfterReturning advice saveData being executed during its waiting for joinPoint.proceed() to return.

The @AfterReturning advice saveData gets triggered for every method execution below the control flow of myPointcut() and returning a Data object. Methods returning something else or being executed outside the specified control flow will be ignored. The advice makes sure the result of the intercepted method call is being assigned to a private Data variable which can later be accessed by the insertThing advice.

I am adding execution(* *(..)) && to the pointcuts because in AspectJ there are other joinpoints such as method call() in addition method execution being the only supported type in Spring AOP. So there you don't need to be so specific, in AspectJ you ought to.

If you remove the percflow(myPointcut()) instantiation from the @Aspect annotation, you will have to make the private Data member a ThreadLocal<Data> instead in order to make the aspect thread-safe again. This also works and still keeps the core application free from thread-local handling, but the aspect itself would have to deal with it.

Console log with active aspect:

[10] execution(void de.scrum_master.app.TaskCreateListener.onEvent(FlowableEvent))
[14] execution(void de.scrum_master.app.TaskCreateListener.onEvent(FlowableEvent))
[12] execution(void de.scrum_master.app.TaskCreateListener.onEvent(FlowableEvent))
[13] execution(void de.scrum_master.app.TaskCreateListener.onEvent(FlowableEvent))
[11] execution(void de.scrum_master.app.TaskCreateListener.onEvent(FlowableEvent))
[14] execution(TaskCreateListener.Data de.scrum_master.app.TaskCreateListener.calculateData(FlowableEvent))
[14] onEvent: Data[procInstId=thread-14, type=case1]
[14] insertThing: Data[procInstId=thread-14, type=case1]
[11] execution(TaskCreateListener.Data de.scrum_master.app.TaskCreateListener.calculateData(FlowableEvent))
[11] onEvent: Data[procInstId=thread-11, type=case1]
[10] execution(TaskCreateListener.Data de.scrum_master.app.TaskCreateListener.calculateData(FlowableEvent))
[12] execution(TaskCreateListener.Data de.scrum_master.app.TaskCreateListener.calculateData(FlowableEvent))
[12] onEvent: Data[procInstId=thread-12, type=case1]
[10] onEvent: Data[procInstId=thread-10, type=case1]
[10] insertThing: Data[procInstId=thread-10, type=case1]
[12] insertThing: Data[procInstId=thread-12, type=case1]
[11] insertThing: Data[procInstId=thread-11, type=case1]
[13] execution(TaskCreateListener.Data de.scrum_master.app.TaskCreateListener.calculateData(FlowableEvent))
[13] onEvent: Data[procInstId=thread-13, type=case1]
[13] insertThing: Data[procInstId=thread-13, type=case1]

Please note how the thread IDs at the beginning of each log line correspond to the value of procInstId. This proves that it actually works without thread-locals due to the percflow aspect instantiation model.

Spring AOP solution

Alternative with Spring AOP: If you want to stick with Spring AOP, you can use neither percflow instantiation nor cflowbelow pointcuts because Spring AOP just does not support those features. So instead of the former you could still use a ThreadLocal inside the aspect and instead of the latter you could factor the calculation out into a separate Spring component/bean and make sure the saveData advice intercepts that one instead. So probably the cost of not having to use AspectJ (if you are so inclined to avoid it) would still be acceptable: one thread-local plus one new component. Please let me know if you are interested in that approach.

Update:

I would also be interested in seeing your approach using Spring AOP if you wouldn't mind sharing.

Fine. I will post the complete MCVE again with different package names in order to disambiguate all classes (some with minor or major changes) from the AspectJ sample code.

Helper classes:

package de.scrum_master.spring.q60234800;

public class FlowableEvent {}

package de.scrum_master.spring.q60234800;

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Retention(RUNTIME)
@Target(METHOD)
public @interface DetermineCaseTypeOfWork {}

Data provider component:

This is the new component/bean I was talking about. Again, instead of the inner Data class you could use a Map but that would be less type-safe. The decision depends on how specific or generic you need your solution to be. What is important here is that the provider itself is a singleton bean but provides a new Data instance on each calculateData(..) call. So you need to make sure that method only depends on its input parameters and not on class fields in order to be thread-safe.

package de.scrum_master.spring.q60234800;

import org.springframework.stereotype.Component;

@Component
public class DataProvider {
  public Data calculateData(FlowableEvent event) {
    return new Data("thread-" + Thread.currentThread().getId(), "event-" + event.hashCode());
  }

  public static class Data {
    private String procInstId;
    private String type;

    public Data(String procInstId, String type) {
      this.procInstId = procInstId;
      this.type = type;
    }

    @Override
    public String toString() {
      return "Data[procInstId=" + procInstId + ", type=" + type + "]";
    }
  }
}

Listener component:

This is also a normal singleton bean which gets the data provider auto-injected.

package de.scrum_master.spring.q60234800;

import de.scrum_master.spring.q60234800.DataProvider.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class TaskCreateListener {
  @Autowired
  DataProvider dataProvider;

  @DetermineCaseTypeOfWork
  public void onEvent(FlowableEvent event) {
    // Calculate values which might be dependent on 'event' or not
    Data data = dataProvider.calculateData(event);
    System.out.println("[" + Thread.currentThread().getId() + "] onEvent: " + data);
  }
}

Driver application:

Again, the application creates multiple threads and fires TaskCreateListener.onEvent(..) for each of them.

package de.scrum_master.spring.q60234800;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

import java.util.stream.IntStream;

@SpringBootApplication
@Configuration
@EnableAspectJAutoProxy//(proxyTargetClass = true)
public class Application {
  public static void main(String[] args) {
    try (ConfigurableApplicationContext appContext = SpringApplication.run(Application.class, args)) {
      TaskCreateListener taskCreateListener = appContext.getBean(TaskCreateListener.class);
      IntStream.range(0, 5).forEach(i ->
        new Thread(() -> taskCreateListener.onEvent(new FlowableEvent())).start()
      );
    }
  }
}

Spring AOP aspect:

As described earlier, we need a ThreadLocal<Data> field for thread-safety because also the aspect is a singleton bean. The combination of two pointcut/advice pairs targeting two different components makes sure that first we gather and save the right Data and then use them in the other advice.

package de.scrum_master.spring.q60234800;

import de.scrum_master.spring.q60234800.DataProvider.Data;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class DetermineTypeOfWorkAspect {
  private ThreadLocal<Data> data = new ThreadLocal<>();

  @Around("@annotation(de.scrum_master.spring.q60234800.DetermineCaseTypeOfWork)")
  public void insertThing(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("[" + Thread.currentThread().getId() + "] " + joinPoint);
    joinPoint.proceed();
    System.out.println("[" + Thread.currentThread().getId() + "] " + "insertThing: " + data.get());
  }

  @AfterReturning(pointcut = "execution(* calculateData(..))", returning = "result")
  public void saveData(JoinPoint joinPoint, Data result) throws Throwable {
    System.out.println("[" + Thread.currentThread().getId() + "] " + joinPoint);
    data.set(result);
  }
}

Console log:

Just like in the AspectJ solution the thread IDs at the beggining of the log lines correspond with the ones captured in the Data objects.

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.5.2.RELEASE)

(...)
2020-02-20 08:03:47.494  INFO 12864 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2020-02-20 08:03:47.498  INFO 12864 --- [           main] d.s.spring.q60234800.Application         : Started Application in 4.429 seconds (JVM running for 5.986)
[33] execution(void de.scrum_master.spring.q60234800.TaskCreateListener.onEvent(FlowableEvent))
[32] execution(void de.scrum_master.spring.q60234800.TaskCreateListener.onEvent(FlowableEvent))
[35] execution(void de.scrum_master.spring.q60234800.TaskCreateListener.onEvent(FlowableEvent))
[34] execution(void de.scrum_master.spring.q60234800.TaskCreateListener.onEvent(FlowableEvent))
[36] execution(void de.scrum_master.spring.q60234800.TaskCreateListener.onEvent(FlowableEvent))
[33] execution(Data de.scrum_master.spring.q60234800.DataProvider.calculateData(FlowableEvent))
[35] execution(Data de.scrum_master.spring.q60234800.DataProvider.calculateData(FlowableEvent))
[34] execution(Data de.scrum_master.spring.q60234800.DataProvider.calculateData(FlowableEvent))
[33] onEvent: Data[procInstId=thread-33, type=event-932577999]
[33] insertThing: Data[procInstId=thread-33, type=event-932577999]
[34] onEvent: Data[procInstId=thread-34, type=event-1335128372]
[34] insertThing: Data[procInstId=thread-34, type=event-1335128372]
[36] execution(Data de.scrum_master.spring.q60234800.DataProvider.calculateData(FlowableEvent))
[36] onEvent: Data[procInstId=thread-36, type=event-130476008]
[32] execution(Data de.scrum_master.spring.q60234800.DataProvider.calculateData(FlowableEvent))
[36] insertThing: Data[procInstId=thread-36, type=event-130476008]
[35] onEvent: Data[procInstId=thread-35, type=event-987686114]
[35] insertThing: Data[procInstId=thread-35, type=event-987686114]
[32] onEvent: Data[procInstId=thread-32, type=event-1849439251]
[32] insertThing: Data[procInstId=thread-32, type=event-1849439251]